2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/param.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/msgport2.h>
43 #include <sys/sysctl.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
50 #include <net/if_arp.h>
51 #include <net/ethernet.h>
52 #include <net/if_dl.h>
53 #include <net/if_media.h>
54 #include <net/netmsg2.h>
56 #include <netproto/802_11/ieee80211_var.h>
57 #include <netproto/802_11/ieee80211_radiotap.h>
59 #include <bus/pci/pcidevs.h>
60 #include <bus/pci/pcireg.h>
61 #include <bus/pci/pcivar.h>
63 #include "if_iwlreg.h"
64 #include "if_iwlvar.h"
65 #include "iwl2100var.h"
70 int (*attach)(device_t);
71 void (*detach)(device_t);
72 int (*shutdown)(device_t);
78 struct iwl2100_softc sc2100;
80 const struct iwl_devinfo *sc_info;
83 static int iwl_probe(device_t);
84 static int iwl_attach(device_t);
85 static int iwl_detach(device_t);
86 static int iwl_shutdown(device_t);
88 static void iwl_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
89 static void iwl_service_loop(void *);
90 static int iwl_put_port(struct lwkt_port *, struct lwkt_msg *);
91 static void iwl_destroy_thread_dispatch(struct netmsg *);
93 static const struct iwl_devinfo iwl2100_devinfo = {
95 .bar = IWL2100_PCIR_BAR,
96 .attach = iwl2100_attach,
97 .detach = iwl2100_detach,
98 .shutdown = iwl2100_shutdown
101 static const struct iwl_dev {
104 const struct iwl_devinfo *info;
106 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PRO_WL_2100, &iwl2100_devinfo },
110 static device_method_t iwl_methods[] = {
111 /* Device interface */
112 DEVMETHOD(device_probe, iwl_probe),
113 DEVMETHOD(device_attach, iwl_attach),
114 DEVMETHOD(device_detach, iwl_detach),
115 DEVMETHOD(device_shutdown, iwl_shutdown),
120 static driver_t iwl_driver = {
123 sizeof(struct iwl_softc)
126 static devclass_t iwl_devclass;
128 DRIVER_MODULE(iwl, pci, iwl_driver, iwl_devclass, NULL, NULL);
130 MODULE_DEPEND(iwl, wlan, 1, 1, 1);
131 MODULE_DEPEND(iwl, pci, 1, 1, 1);
133 const struct ieee80211_rateset iwl_rateset_11b = { 4, { 2, 4, 11, 22 } };
136 iwl_probe(device_t dev)
138 const struct iwl_dev *d;
141 vid = pci_get_vendor(dev);
142 did = pci_get_device(dev);
144 for (d = iwl_devices; d->info != NULL; ++d) {
145 if (d->did == did && d->vid == vid) {
146 struct iwl_softc *sc = device_get_softc(dev);
148 device_set_desc(dev, d->info->desc);
149 sc->sc_info = d->info;
157 iwl_attach(device_t dev)
159 struct iwl_softc *sc = device_get_softc(dev);
160 struct iwlcom *iwl = &sc->u.common;
161 struct ifnet *ifp = &iwl->iwl_ic.ic_if;
164 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
165 bar = sc->sc_info->bar;
168 if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
171 irq = pci_read_config(dev, PCIR_INTLINE, 4);
172 mem = pci_read_config(dev, bar, 4);
174 device_printf(dev, "chip is in D%d power mode "
175 "-- setting to D0\n", pci_get_powerstate(dev));
177 pci_set_powerstate(dev, PCI_POWERSTATE_D0);
179 pci_write_config(dev, PCIR_INTLINE, irq, 4);
180 pci_write_config(dev, bar, mem, 4);
182 #endif /* !BURN_BRIDGES */
184 /* Enable bus mastering */
185 pci_enable_busmaster(dev);
190 iwl->iwl_mem_rid = bar;
191 iwl->iwl_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
192 &iwl->iwl_mem_rid, RF_ACTIVE);
193 if (iwl->iwl_mem_res == NULL) {
194 device_printf(dev, "can't allocate IO memory\n");
197 iwl->iwl_mem_bt = rman_get_bustag(iwl->iwl_mem_res);
198 iwl->iwl_mem_bh = rman_get_bushandle(iwl->iwl_mem_res);
203 iwl->iwl_irq_rid = 0;
204 iwl->iwl_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
206 RF_SHAREABLE | RF_ACTIVE);
207 if (iwl->iwl_irq_res == NULL) {
208 device_printf(dev, "can't allocate irq\n");
216 sysctl_ctx_init(&iwl->iwl_sysctl_ctx);
217 iwl->iwl_sysctl_tree = SYSCTL_ADD_NODE(&iwl->iwl_sysctl_ctx,
218 SYSCTL_STATIC_CHILDREN(_hw),
220 device_get_nameunit(dev),
222 if (iwl->iwl_sysctl_tree == NULL) {
223 device_printf(dev, "can't add sysctl node\n");
229 * Device specific attach
231 error = sc->sc_info->attach(dev);
239 iwl_detach(device_t dev)
241 struct iwl_softc *sc = device_get_softc(dev);
242 struct iwlcom *iwl = &sc->u.common;
244 sc->sc_info->detach(dev);
246 if (iwl->iwl_sysctl_tree != NULL)
247 sysctl_ctx_free(&iwl->iwl_sysctl_ctx);
249 if (iwl->iwl_irq_res != NULL) {
250 bus_release_resource(dev, SYS_RES_IRQ, iwl->iwl_irq_rid,
254 if (iwl->iwl_mem_res != NULL) {
255 bus_release_resource(dev, SYS_RES_MEMORY, iwl->iwl_mem_rid,
262 iwl_shutdown(device_t dev)
264 struct iwl_softc *sc = device_get_softc(dev);
266 return sc->sc_info->shutdown(dev);
270 iwl_ind_write_4(struct iwlcom *iwl, uint32_t addr, uint32_t data)
272 IWL_WRITE_4(iwl, IWL_IND_ADDR, addr);
273 IWL_WRITE_4(iwl, IWL_IND_DATA, data);
277 iwl_ind_write_2(struct iwlcom *iwl, uint32_t addr, uint16_t data)
279 IWL_WRITE_4(iwl, IWL_IND_ADDR, addr);
280 IWL_WRITE_2(iwl, IWL_IND_DATA, data);
284 iwl_ind_write_1(struct iwlcom *iwl, uint32_t addr, uint8_t data)
286 IWL_WRITE_4(iwl, IWL_IND_ADDR, addr);
287 IWL_WRITE_1(iwl, IWL_IND_DATA, data);
291 iwl_ind_read_4(struct iwlcom *iwl, uint32_t addr)
293 IWL_WRITE_4(iwl, IWL_IND_ADDR, addr);
294 return IWL_READ_4(iwl, IWL_IND_DATA);
298 iwl_ind_read_2(struct iwlcom *iwl, uint32_t addr)
300 IWL_WRITE_4(iwl, IWL_IND_ADDR, addr);
301 return IWL_READ_2(iwl, IWL_IND_DATA);
305 iwl_ind_read_1(struct iwlcom *iwl, uint32_t addr)
307 IWL_WRITE_4(iwl, IWL_IND_ADDR, addr);
308 return IWL_READ_1(iwl, IWL_IND_DATA);
311 #define EEPROM_WRITE(iwl, data) \
313 iwl_ind_write_4((iwl), IWL_EEPROM_IND_CSR, (data)); \
317 #define EEPROM_SET_BIT(iwl) \
319 EEPROM_WRITE((iwl), IWL_EEBIT_CS | IWL_EEBIT_DI); \
320 EEPROM_WRITE((iwl), IWL_EEBIT_CS | IWL_EEBIT_DI | IWL_EEBIT_SK); \
323 #define EEPROM_CLR_BIT(iwl) \
325 EEPROM_WRITE((iwl), IWL_EEBIT_CS); \
326 EEPROM_WRITE((iwl), IWL_EEBIT_CS | IWL_EEBIT_SK); \
330 iwl_read_eeprom(struct iwlcom *iwl, uint8_t ofs)
336 EEPROM_WRITE(iwl, 0);
337 EEPROM_WRITE(iwl, IWL_EEBIT_CS);
338 EEPROM_WRITE(iwl, IWL_EEBIT_CS | IWL_EEBIT_SK);
339 EEPROM_WRITE(iwl, IWL_EEBIT_CS);
341 /* Send READ opcode (0x2) */
343 EEPROM_SET_BIT(iwl); /* READ opcode */
344 EEPROM_CLR_BIT(iwl); /* READ opcode */
347 for (i = NBBY - 1; i >= 0; --i) {
355 EEPROM_WRITE(iwl, IWL_EEBIT_CS);
359 for (i = 0; i < (sizeof(ret) * NBBY); ++i) {
360 EEPROM_WRITE(iwl, IWL_EEBIT_CS | IWL_EEBIT_SK);
361 EEPROM_WRITE(iwl, IWL_EEBIT_CS);
364 if (iwl_ind_read_4(iwl, IWL_EEPROM_IND_CSR) & IWL_EEBIT_DO)
369 EEPROM_WRITE(iwl, 0);
372 EEPROM_WRITE(iwl, IWL_EEBIT_CS);
373 EEPROM_WRITE(iwl, 0);
374 EEPROM_WRITE(iwl, IWL_EEBIT_SK);
380 iwl_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
382 KASSERT(nseg == 1, ("too many segments"));
383 *((bus_addr_t *)arg) = seg->ds_addr;
387 iwl_dma_mem_create(device_t dev, bus_dma_tag_t parent, bus_size_t size,
388 bus_dma_tag_t *dtag, void **addr, bus_addr_t *paddr,
393 error = bus_dma_tag_create(parent, IWL_ALIGN, 0,
394 BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
396 size, 1, BUS_SPACE_MAXSIZE_32BIT,
399 device_printf(dev, "can't create DMA tag\n");
403 error = bus_dmamem_alloc(*dtag, addr, BUS_DMA_WAITOK | BUS_DMA_ZERO,
406 device_printf(dev, "can't allocate DMA mem\n");
407 bus_dma_tag_destroy(*dtag);
412 error = bus_dmamap_load(*dtag, *dmap, *addr, size,
413 iwl_dma_ring_addr, paddr, BUS_DMA_WAITOK);
415 device_printf(dev, "can't load DMA mem\n");
416 bus_dmamem_free(*dtag, *addr, *dmap);
417 bus_dma_tag_destroy(*dtag);
425 iwl_dma_mem_destroy(bus_dma_tag_t dtag, void *addr, bus_dmamap_t dmap)
428 bus_dmamap_unload(dtag, dmap);
429 bus_dmamem_free(dtag, addr, dmap);
430 bus_dma_tag_destroy(dtag);
435 iwl_dma_buf_addr(void *xctx, bus_dma_segment_t *segs, int nsegs,
436 bus_size_t mapsz __unused, int error)
438 struct iwl_dmamap_ctx *ctx = xctx;
444 if (nsegs > ctx->nsegs) {
450 for (i = 0; i < nsegs; ++i)
451 ctx->segs[i] = segs[i];
455 iwl_put_port(struct lwkt_port *port, struct lwkt_msg *lmsg)
457 struct iwlmsg *msg = (struct iwlmsg *)lmsg;
458 struct iwlcom *iwl = msg->iwlm_softc;
460 ASSERT_SERIALIZED(port->mpu_serialize);
462 if ((lmsg->ms_flags & MSGF_SYNC) && curthread == &iwl->iwl_thread) {
463 msg->iwlm_nmsg.nm_dispatch(&msg->iwlm_nmsg);
464 if ((lmsg->ms_flags & MSGF_DONE) == 0) {
465 panic("%s: self-referential deadlock on "
466 "iwl thread port\n", __func__);
470 return iwl->iwl_fwd_port(port, lmsg);
475 iwl_service_loop(void *arg)
477 struct iwlcom *iwl = arg;
478 struct ifnet *ifp = &iwl->iwl_ic.ic_if;
482 lwkt_serialize_enter(ifp->if_serializer);
483 while ((nmsg = lwkt_waitport(&iwl->iwl_thread_port, 0))) {
484 nmsg->nm_dispatch(nmsg);
488 lwkt_serialize_exit(ifp->if_serializer);
493 iwl_create_thread(struct iwlcom *iwl, int unit)
495 struct ifnet *ifp = &iwl->iwl_ic.ic_if;
497 lwkt_initport_serialize(&iwl->iwl_reply_port, ifp->if_serializer);
498 lwkt_initport_serialize(&iwl->iwl_thread_port, ifp->if_serializer);
500 /* NB: avoid self-reference domsg */
501 iwl->iwl_fwd_port = iwl->iwl_thread_port.mp_putport;
502 iwl->iwl_thread_port.mp_putport = iwl_put_port;
504 lwkt_create(iwl_service_loop, iwl, NULL, &iwl->iwl_thread,
505 0, unit % ncpus, "iwl%d", unit);
509 iwl_destroy_thread_dispatch(struct netmsg *nmsg)
511 struct iwlmsg *msg = (struct iwlmsg *)nmsg;
512 struct iwlcom *iwl = msg->iwlm_softc;
514 ASSERT_SERIALIZED(iwl->iwl_ic.ic_if.if_serializer);
517 lwkt_replymsg(&nmsg->nm_lmsg, 0);
521 iwl_destroy_thread(struct iwlcom *iwl)
525 ASSERT_SERIALIZED(iwl->iwl_ic.ic_if.if_serializer);
527 iwlmsg_init(&msg, &iwl->iwl_reply_port,
528 iwl_destroy_thread_dispatch, iwl);
529 lwkt_domsg(&iwl->iwl_thread_port, &msg.iwlm_nmsg.nm_lmsg, 0);
533 iwlmsg_init(struct iwlmsg *msg, struct lwkt_port *rport, netisr_fn_t dispatch,
536 netmsg_init(&msg->iwlm_nmsg, NULL, rport, 0, dispatch);
537 msg->iwlm_softc = sc;
541 iwlmsg_send(struct iwlmsg *msg, struct lwkt_port *port)
543 struct lwkt_msg *lmsg;
545 lmsg = &msg->iwlm_nmsg.nm_lmsg;
546 if (lmsg->ms_flags & MSGF_DONE)
547 lwkt_sendmsg(port, lmsg);