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
34 * $DragonFly: src/sys/dev/netif/iwl/if_iwl.c,v 1.1 2008/03/05 14:10:39 sephe Exp $
37 #include <sys/param.h>
39 #include <sys/endian.h>
40 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/msgport2.h>
44 #include <sys/sysctl.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
51 #include <net/if_arp.h>
52 #include <net/ethernet.h>
53 #include <net/if_dl.h>
54 #include <net/if_media.h>
55 #include <net/netmsg2.h>
57 #include <netproto/802_11/ieee80211_var.h>
58 #include <netproto/802_11/ieee80211_radiotap.h>
60 #include <bus/pci/pcidevs.h>
61 #include <bus/pci/pcireg.h>
62 #include <bus/pci/pcivar.h>
64 #include "if_iwlreg.h"
65 #include "if_iwlvar.h"
66 #include "iwl2100var.h"
71 int (*attach
)(device_t
);
72 void (*detach
)(device_t
);
73 int (*shutdown
)(device_t
);
79 struct iwl2100_softc sc2100
;
81 const struct iwl_devinfo
*sc_info
;
84 static int iwl_probe(device_t
);
85 static int iwl_attach(device_t
);
86 static int iwl_detach(device_t
);
87 static int iwl_shutdown(device_t
);
89 static void iwl_dma_ring_addr(void *, bus_dma_segment_t
*, int, int);
90 static void iwl_service_loop(void *);
91 static int iwl_put_port(struct lwkt_port
*, struct lwkt_msg
*);
92 static void iwl_destroy_thread_dispatch(struct netmsg
*);
94 static const struct iwl_devinfo iwl2100_devinfo
= {
96 .bar
= IWL2100_PCIR_BAR
,
97 .attach
= iwl2100_attach
,
98 .detach
= iwl2100_detach
,
99 .shutdown
= iwl2100_shutdown
102 static const struct iwl_dev
{
105 const struct iwl_devinfo
*info
;
107 { PCI_VENDOR_INTEL
, PCI_PRODUCT_INTEL_PRO_WL_2100
, &iwl2100_devinfo
},
111 static device_method_t iwl_methods
[] = {
112 /* Device interface */
113 DEVMETHOD(device_probe
, iwl_probe
),
114 DEVMETHOD(device_attach
, iwl_attach
),
115 DEVMETHOD(device_detach
, iwl_detach
),
116 DEVMETHOD(device_shutdown
, iwl_shutdown
),
121 static driver_t iwl_driver
= {
124 sizeof(struct iwl_softc
)
127 static devclass_t iwl_devclass
;
129 DRIVER_MODULE(iwl
, pci
, iwl_driver
, iwl_devclass
, 0, 0);
131 MODULE_DEPEND(iwl
, wlan
, 1, 1, 1);
132 MODULE_DEPEND(iwl
, pci
, 1, 1, 1);
134 const struct ieee80211_rateset iwl_rateset_11b
= { 4, { 2, 4, 11, 22 } };
137 iwl_probe(device_t dev
)
139 const struct iwl_dev
*d
;
142 vid
= pci_get_vendor(dev
);
143 did
= pci_get_device(dev
);
145 for (d
= iwl_devices
; d
->info
!= NULL
; ++d
) {
146 if (d
->did
== did
&& d
->vid
== vid
) {
147 struct iwl_softc
*sc
= device_get_softc(dev
);
149 device_set_desc(dev
, d
->info
->desc
);
150 sc
->sc_info
= d
->info
;
158 iwl_attach(device_t dev
)
160 struct iwl_softc
*sc
= device_get_softc(dev
);
161 struct iwlcom
*iwl
= &sc
->u
.common
;
162 struct ifnet
*ifp
= &iwl
->iwl_ic
.ic_if
;
165 if_initname(ifp
, device_get_name(dev
), device_get_unit(dev
));
166 bar
= sc
->sc_info
->bar
;
169 if (pci_get_powerstate(dev
) != PCI_POWERSTATE_D0
) {
172 irq
= pci_read_config(dev
, PCIR_INTLINE
, 4);
173 mem
= pci_read_config(dev
, bar
, 4);
175 device_printf(dev
, "chip is in D%d power mode "
176 "-- setting to D0\n", pci_get_powerstate(dev
));
178 pci_set_powerstate(dev
, PCI_POWERSTATE_D0
);
180 pci_write_config(dev
, PCIR_INTLINE
, irq
, 4);
181 pci_write_config(dev
, bar
, mem
, 4);
183 #endif /* !BURN_BRIDGES */
185 /* Enable bus mastering */
186 pci_enable_busmaster(dev
);
191 iwl
->iwl_mem_rid
= bar
;
192 iwl
->iwl_mem_res
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
,
193 &iwl
->iwl_mem_rid
, RF_ACTIVE
);
194 if (iwl
->iwl_mem_res
== NULL
) {
195 device_printf(dev
, "can't allocate IO memory\n");
198 iwl
->iwl_mem_bt
= rman_get_bustag(iwl
->iwl_mem_res
);
199 iwl
->iwl_mem_bh
= rman_get_bushandle(iwl
->iwl_mem_res
);
204 iwl
->iwl_irq_rid
= 0;
205 iwl
->iwl_irq_res
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
207 RF_SHAREABLE
| RF_ACTIVE
);
208 if (iwl
->iwl_irq_res
== NULL
) {
209 device_printf(dev
, "can't allocate irq\n");
217 sysctl_ctx_init(&iwl
->iwl_sysctl_ctx
);
218 iwl
->iwl_sysctl_tree
= SYSCTL_ADD_NODE(&iwl
->iwl_sysctl_ctx
,
219 SYSCTL_STATIC_CHILDREN(_hw
),
221 device_get_nameunit(dev
),
223 if (iwl
->iwl_sysctl_tree
== NULL
) {
224 device_printf(dev
, "can't add sysctl node\n");
230 * Device specific attach
232 error
= sc
->sc_info
->attach(dev
);
240 iwl_detach(device_t dev
)
242 struct iwl_softc
*sc
= device_get_softc(dev
);
243 struct iwlcom
*iwl
= &sc
->u
.common
;
245 sc
->sc_info
->detach(dev
);
247 if (iwl
->iwl_sysctl_tree
!= NULL
)
248 sysctl_ctx_free(&iwl
->iwl_sysctl_ctx
);
250 if (iwl
->iwl_irq_res
!= NULL
) {
251 bus_release_resource(dev
, SYS_RES_IRQ
, iwl
->iwl_irq_rid
,
255 if (iwl
->iwl_mem_res
!= NULL
) {
256 bus_release_resource(dev
, SYS_RES_MEMORY
, iwl
->iwl_mem_rid
,
263 iwl_shutdown(device_t dev
)
265 struct iwl_softc
*sc
= device_get_softc(dev
);
267 return sc
->sc_info
->shutdown(dev
);
271 iwl_ind_write_4(struct iwlcom
*iwl
, uint32_t addr
, uint32_t data
)
273 IWL_WRITE_4(iwl
, IWL_IND_ADDR
, addr
);
274 IWL_WRITE_4(iwl
, IWL_IND_DATA
, data
);
278 iwl_ind_write_2(struct iwlcom
*iwl
, uint32_t addr
, uint16_t data
)
280 IWL_WRITE_4(iwl
, IWL_IND_ADDR
, addr
);
281 IWL_WRITE_2(iwl
, IWL_IND_DATA
, data
);
285 iwl_ind_write_1(struct iwlcom
*iwl
, uint32_t addr
, uint8_t data
)
287 IWL_WRITE_4(iwl
, IWL_IND_ADDR
, addr
);
288 IWL_WRITE_1(iwl
, IWL_IND_DATA
, data
);
292 iwl_ind_read_4(struct iwlcom
*iwl
, uint32_t addr
)
294 IWL_WRITE_4(iwl
, IWL_IND_ADDR
, addr
);
295 return IWL_READ_4(iwl
, IWL_IND_DATA
);
299 iwl_ind_read_2(struct iwlcom
*iwl
, uint32_t addr
)
301 IWL_WRITE_4(iwl
, IWL_IND_ADDR
, addr
);
302 return IWL_READ_2(iwl
, IWL_IND_DATA
);
306 iwl_ind_read_1(struct iwlcom
*iwl
, uint32_t addr
)
308 IWL_WRITE_4(iwl
, IWL_IND_ADDR
, addr
);
309 return IWL_READ_1(iwl
, IWL_IND_DATA
);
312 #define EEPROM_WRITE(iwl, data) \
314 iwl_ind_write_4((iwl), IWL_EEPROM_IND_CSR, (data)); \
318 #define EEPROM_SET_BIT(iwl) \
320 EEPROM_WRITE((iwl), IWL_EEBIT_CS | IWL_EEBIT_DI); \
321 EEPROM_WRITE((iwl), IWL_EEBIT_CS | IWL_EEBIT_DI | IWL_EEBIT_SK); \
324 #define EEPROM_CLR_BIT(iwl) \
326 EEPROM_WRITE((iwl), IWL_EEBIT_CS); \
327 EEPROM_WRITE((iwl), IWL_EEBIT_CS | IWL_EEBIT_SK); \
331 iwl_read_eeprom(struct iwlcom
*iwl
, uint8_t ofs
)
337 EEPROM_WRITE(iwl
, 0);
338 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
);
339 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
| IWL_EEBIT_SK
);
340 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
);
342 /* Send READ opcode (0x2) */
344 EEPROM_SET_BIT(iwl
); /* READ opcode */
345 EEPROM_CLR_BIT(iwl
); /* READ opcode */
348 for (i
= NBBY
- 1; i
>= 0; --i
) {
356 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
);
360 for (i
= 0; i
< (sizeof(ret
) * NBBY
); ++i
) {
361 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
| IWL_EEBIT_SK
);
362 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
);
365 if (iwl_ind_read_4(iwl
, IWL_EEPROM_IND_CSR
) & IWL_EEBIT_DO
)
370 EEPROM_WRITE(iwl
, 0);
373 EEPROM_WRITE(iwl
, IWL_EEBIT_CS
);
374 EEPROM_WRITE(iwl
, 0);
375 EEPROM_WRITE(iwl
, IWL_EEBIT_SK
);
381 iwl_dma_ring_addr(void *arg
, bus_dma_segment_t
*seg
, int nseg
, int error
)
383 KASSERT(nseg
== 1, ("too many segments\n"));
384 *((bus_addr_t
*)arg
) = seg
->ds_addr
;
388 iwl_dma_mem_create(device_t dev
, bus_dma_tag_t parent
, bus_size_t size
,
389 bus_dma_tag_t
*dtag
, void **addr
, bus_addr_t
*paddr
,
394 error
= bus_dma_tag_create(parent
, IWL_ALIGN
, 0,
395 BUS_SPACE_MAXADDR
, BUS_SPACE_MAXADDR
,
397 size
, 1, BUS_SPACE_MAXSIZE_32BIT
,
400 device_printf(dev
, "can't create DMA tag\n");
404 error
= bus_dmamem_alloc(*dtag
, addr
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
,
407 device_printf(dev
, "can't allocate DMA mem\n");
408 bus_dma_tag_destroy(*dtag
);
413 error
= bus_dmamap_load(*dtag
, *dmap
, *addr
, size
,
414 iwl_dma_ring_addr
, paddr
, BUS_DMA_WAITOK
);
416 device_printf(dev
, "can't load DMA mem\n");
417 bus_dmamem_free(*dtag
, *addr
, *dmap
);
418 bus_dma_tag_destroy(*dtag
);
426 iwl_dma_mem_destroy(bus_dma_tag_t dtag
, void *addr
, bus_dmamap_t dmap
)
429 bus_dmamap_unload(dtag
, dmap
);
430 bus_dmamem_free(dtag
, addr
, dmap
);
431 bus_dma_tag_destroy(dtag
);
436 iwl_dma_buf_addr(void *xctx
, bus_dma_segment_t
*segs
, int nsegs
,
437 bus_size_t mapsz __unused
, int error
)
439 struct iwl_dmamap_ctx
*ctx
= xctx
;
445 if (nsegs
> ctx
->nsegs
) {
451 for (i
= 0; i
< nsegs
; ++i
)
452 ctx
->segs
[i
] = segs
[i
];
456 iwl_put_port(struct lwkt_port
*port
, struct lwkt_msg
*lmsg
)
458 struct iwlmsg
*msg
= (struct iwlmsg
*)lmsg
;
459 struct iwlcom
*iwl
= msg
->iwlm_softc
;
461 ASSERT_SERIALIZED(port
->mpu_serialize
);
463 if ((lmsg
->ms_flags
& MSGF_SYNC
) && curthread
== &iwl
->iwl_thread
) {
464 msg
->iwlm_nmsg
.nm_dispatch(&msg
->iwlm_nmsg
);
465 if ((lmsg
->ms_flags
& MSGF_DONE
) == 0) {
466 panic("%s: self-referential deadlock on "
467 "iwl thread port\n", __func__
);
471 return iwl
->iwl_fwd_port(port
, lmsg
);
476 iwl_service_loop(void *arg
)
478 struct iwlcom
*iwl
= arg
;
479 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
);
494 iwl_create_thread(struct iwlcom
*iwl
, int unit
)
496 struct ifnet
*ifp
= &iwl
->iwl_ic
.ic_if
;
498 lwkt_initport_serialize(&iwl
->iwl_reply_port
, ifp
->if_serializer
);
499 lwkt_initport_serialize(&iwl
->iwl_thread_port
, ifp
->if_serializer
);
501 /* NB: avoid self-reference domsg */
502 iwl
->iwl_fwd_port
= iwl
->iwl_thread_port
.mp_putport
;
503 iwl
->iwl_thread_port
.mp_putport
= iwl_put_port
;
505 lwkt_create(iwl_service_loop
, iwl
, NULL
, &iwl
->iwl_thread
,
506 0, unit
% ncpus
, "iwl%d", unit
);
510 iwl_destroy_thread_dispatch(struct netmsg
*nmsg
)
512 struct iwlmsg
*msg
= (struct iwlmsg
*)nmsg
;
513 struct iwlcom
*iwl
= msg
->iwlm_softc
;
515 ASSERT_SERIALIZED(iwl
->iwl_ic
.ic_if
.if_serializer
);
518 lwkt_replymsg(&nmsg
->nm_lmsg
, 0);
522 iwl_destroy_thread(struct iwlcom
*iwl
)
526 ASSERT_SERIALIZED(iwl
->iwl_ic
.ic_if
.if_serializer
);
528 iwlmsg_init(&msg
, &iwl
->iwl_reply_port
,
529 iwl_destroy_thread_dispatch
, iwl
);
530 lwkt_domsg(&iwl
->iwl_thread_port
, &msg
.iwlm_nmsg
.nm_lmsg
, 0);
534 iwlmsg_init(struct iwlmsg
*msg
, struct lwkt_port
*rport
, netisr_fn_t dispatch
,
537 netmsg_init(&msg
->iwlm_nmsg
, rport
, 0, dispatch
);
538 msg
->iwlm_softc
= sc
;
542 iwlmsg_send(struct iwlmsg
*msg
, struct lwkt_port
*port
)
544 struct lwkt_msg
*lmsg
;
546 lmsg
= &msg
->iwlm_nmsg
.nm_lmsg
;
547 if (lmsg
->ms_flags
& MSGF_DONE
)
548 lwkt_sendmsg(port
, lmsg
);