kernel: Use nitems() from <sys/param.h> instead of custom define
[dragonfly.git] / sys / dev / netif / bwn / siba / siba_bwn.c
1 /*-
2  * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: head/sys/dev/siba/siba_bwn.c 299409 2016-05-11 06:27:46Z adrian $");
32
33 /*
34  * Sonics Silicon Backplane front-end for bwn(4).
35  */
36
37 #if defined(__DragonFly__)
38 #include <opt_siba.h>
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/module.h>
45 #include <sys/kernel.h>
46 #include <sys/lock.h>
47 #include <sys/mutex.h>
48 #include <sys/errno.h>
49 #if !defined(__DragonFly__)
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52 #endif
53 #include <sys/bus.h>
54 #include <sys/rman.h>
55 #include <sys/socket.h>
56
57 #include <net/if.h>
58 #include <net/if_media.h>
59 #include <net/if_arp.h>
60
61 #if defined(__DragonFly__)
62 #include <bus/pci/pcivar.h>
63 #include <bus/pci/pcireg.h>
64 #else
65 #include <dev/pci/pcivar.h>
66 #include <dev/pci/pcireg.h>
67 #endif
68
69 #if defined(__DragonFly__)
70 #include "siba_ids.h"
71 #include "sibareg.h"
72 #include "sibavar.h"
73 #else
74 #include <dev/siba/siba_ids.h>
75 #include <dev/siba/sibareg.h>
76 #include <dev/siba/sibavar.h>
77 #endif
78
79 /*
80  * PCI glue.
81  */
82
83 struct siba_bwn_softc {
84         /* Child driver using MSI. */
85         device_t                        ssc_msi_child;
86         struct siba_softc               ssc_siba;
87 };
88
89 #define BS_BAR                          0x10
90 #define PCI_VENDOR_BROADCOM             0x14e4
91
92 static const struct siba_dev {
93         uint16_t        vid;
94         uint16_t        did;
95         const char      *desc;
96 } siba_devices[] = {
97         { PCI_VENDOR_BROADCOM, 0x4301, "Broadcom BCM4301 802.11b Wireless" },
98         { PCI_VENDOR_BROADCOM, 0x4306, "Unknown" },
99         { PCI_VENDOR_BROADCOM, 0x4307, "Broadcom BCM4307 802.11b Wireless" },
100         { PCI_VENDOR_BROADCOM, 0x4311, "Broadcom BCM4311 802.11b/g Wireless" },
101         { PCI_VENDOR_BROADCOM, 0x4312,
102           "Broadcom BCM4312 802.11a/b/g Wireless" },
103         { PCI_VENDOR_BROADCOM, 0x4315, "Broadcom BCM4312 802.11b/g Wireless" },
104         { PCI_VENDOR_BROADCOM, 0x4318, "Broadcom BCM4318 802.11b/g Wireless" },
105         { PCI_VENDOR_BROADCOM, 0x4319,
106           "Broadcom BCM4318 802.11a/b/g Wireless" },
107         { PCI_VENDOR_BROADCOM, 0x4320, "Broadcom BCM4306 802.11b/g Wireless" },
108         { PCI_VENDOR_BROADCOM, 0x4321, "Broadcom BCM4306 802.11a Wireless" },
109         { PCI_VENDOR_BROADCOM, 0x4324,
110           "Broadcom BCM4309 802.11a/b/g Wireless" },
111         { PCI_VENDOR_BROADCOM, 0x4325, "Broadcom BCM4306 802.11b/g Wireless" },
112         { PCI_VENDOR_BROADCOM, 0x4328, "Broadcom BCM4321 802.11a/b/g Wireless" },
113         { PCI_VENDOR_BROADCOM, 0x4329, "Unknown" },
114         { PCI_VENDOR_BROADCOM, 0x432b, "Unknown" }
115 };
116
117 int             siba_core_attach(struct siba_softc *);
118 int             siba_core_detach(struct siba_softc *);
119 int             siba_core_suspend(struct siba_softc *);
120 int             siba_core_resume(struct siba_softc *);
121
122 static int
123 siba_bwn_probe(device_t dev)
124 {
125         int i;
126         uint16_t did, vid;
127
128         did = pci_get_device(dev);
129         vid = pci_get_vendor(dev);
130
131         for (i = 0; i < nitems(siba_devices); i++) {
132                 if (siba_devices[i].did == did && siba_devices[i].vid == vid) {
133                         device_set_desc(dev, siba_devices[i].desc);
134                         return (BUS_PROBE_DEFAULT);
135                 }
136         }
137         return (ENXIO);
138 }
139
140 static int
141 siba_bwn_attach(device_t dev)
142 {
143         struct siba_bwn_softc *ssc = device_get_softc(dev);
144         struct siba_softc *siba = &ssc->ssc_siba;
145
146         siba->siba_dev = dev;
147         siba->siba_type = SIBA_TYPE_PCI;
148
149         /*
150          * Enable bus mastering.
151          */
152         pci_enable_busmaster(dev);
153
154         /*
155          * Setup memory-mapping of PCI registers.
156          */
157         siba->siba_mem_rid = SIBA_PCIR_BAR;
158         siba->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
159                 &siba->siba_mem_rid, RF_ACTIVE);
160         if (siba->siba_mem_res == NULL) {
161                 device_printf(dev, "cannot map register space\n");
162                 return (ENXIO);
163         }
164         siba->siba_mem_bt = rman_get_bustag(siba->siba_mem_res);
165         siba->siba_mem_bh = rman_get_bushandle(siba->siba_mem_res);
166
167         /* Get more PCI information */
168         siba->siba_pci_did = pci_get_device(dev);
169         siba->siba_pci_vid = pci_get_vendor(dev);
170         siba->siba_pci_subvid = pci_get_subvendor(dev);
171         siba->siba_pci_subdid = pci_get_subdevice(dev);
172         siba->siba_pci_revid = pci_get_revid(dev);
173
174         return (siba_core_attach(siba));
175 }
176
177 static int
178 siba_bwn_detach(device_t dev)
179 {
180         struct siba_bwn_softc *ssc = device_get_softc(dev);
181         struct siba_softc *siba = &ssc->ssc_siba;
182
183         /* check if device was removed */
184         siba->siba_invalid = !bus_child_present(dev);
185
186         pci_disable_busmaster(dev);
187         bus_generic_detach(dev);
188         siba_core_detach(siba);
189
190         bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, siba->siba_mem_res);
191
192         return (0);
193 }
194
195 static int
196 siba_bwn_shutdown(device_t dev)
197 {
198         device_t *devlistp;
199         int devcnt, error = 0, i;
200
201         error = device_get_children(dev, &devlistp, &devcnt);
202         if (error != 0)
203                 return (error);
204
205         for (i = 0 ; i < devcnt ; i++)
206                 device_shutdown(devlistp[i]);
207         kfree(devlistp, M_TEMP);
208         return (0);
209 }
210
211 static int
212 siba_bwn_suspend(device_t dev)
213 {
214         struct siba_bwn_softc *ssc = device_get_softc(dev);
215         struct siba_softc *siba = &ssc->ssc_siba;
216         device_t *devlistp;
217         int devcnt, error = 0, i, j;
218
219         error = device_get_children(dev, &devlistp, &devcnt);
220         if (error != 0)
221                 return (error);
222
223         for (i = 0 ; i < devcnt ; i++) {
224                 error = DEVICE_SUSPEND(devlistp[i]);
225                 if (error) {
226                         for (j = 0; j < i; j++)
227                                 DEVICE_RESUME(devlistp[j]);
228                         kfree(devlistp, M_TEMP);
229                         return (error);
230                 }
231         }
232         kfree(devlistp, M_TEMP);
233         return (siba_core_suspend(siba));
234 }
235
236 static int
237 siba_bwn_resume(device_t dev)
238 {
239         struct siba_bwn_softc *ssc = device_get_softc(dev);
240         struct siba_softc *siba = &ssc->ssc_siba;
241         device_t *devlistp;
242         int devcnt, error = 0, i;
243
244         error = siba_core_resume(siba);
245         if (error != 0)
246                 return (error);
247
248         error = device_get_children(dev, &devlistp, &devcnt);
249         if (error != 0)
250                 return (error);
251
252         for (i = 0 ; i < devcnt ; i++)
253                 DEVICE_RESUME(devlistp[i]);
254         kfree(devlistp, M_TEMP);
255         return (0);
256 }
257
258 /* proxying to the parent */
259 #if defined(__DragonFly__)
260 static struct resource *
261 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid,
262     u_long start, u_long end, u_long count, u_int flags, int cpuid)
263 {
264
265         return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
266             type, rid, start, end, count, flags, cpuid));
267 }
268 #else
269 static struct resource *
270 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid,
271     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
272 {
273
274         return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
275             type, rid, start, end, count, flags));
276 }
277 #endif
278
279 /* proxying to the parent */
280 static int
281 siba_bwn_release_resource(device_t dev, device_t child, int type,
282     int rid, struct resource *r)
283 {
284
285         return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type,
286             rid, r));
287 }
288
289 #if defined(__DragonFly__)
290 /* proxying to the parent */
291 static int
292 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq,
293     int flags, driver_intr_t *intr, void *arg, void **cookiep,
294     lwkt_serialize_t serializer)
295 {
296
297         return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
298             intr, arg, cookiep, serializer, NULL));
299 }
300 #else
301 static int
302 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq,
303     int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
304     void **cookiep)
305 {
306
307         return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
308             filter, intr, arg, cookiep));
309 }
310 #endif
311
312 /* proxying to the parent */
313 static int
314 siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq,
315     void *cookie)
316 {
317
318         return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
319 }
320
321 #if !defined(__DragonFly__)
322 static int
323 siba_bwn_find_cap(device_t dev, device_t child, int capability,
324     int *capreg)
325 {
326
327         return (pci_find_cap(dev, capability, capreg));
328 }
329 #endif
330
331 static int
332 siba_bwn_find_extcap(device_t dev, device_t child, int capability,
333     int *capreg)
334 {
335
336         return (pci_find_extcap(dev, capability, capreg));
337 }
338
339 #if !defined(__DragonFly__)
340 static int
341 siba_bwn_find_htcap(device_t dev, device_t child, int capability,
342     int *capreg)
343 {
344
345         return (pci_find_htcap(dev, capability, capreg));
346 }
347 #endif
348
349 #if defined(__DragonFly__)
350 static int
351 siba_bwn_alloc_msi(device_t dev, device_t child, int *rid, int count,
352     int cpuid)
353 #else
354 static int
355 siba_bwn_alloc_msi(device_t dev, device_t child, int *count)
356 #endif
357 {
358         struct siba_bwn_softc *ssc;
359         int error;
360
361         ssc = device_get_softc(dev);
362         if (ssc->ssc_msi_child != NULL)
363                 return (EBUSY);
364 #if defined(__DragonFly__)
365         error = pci_alloc_msi(dev, rid, count, cpuid);
366 #else
367         error = pci_alloc_msi(dev, count);
368 #endif
369         if (error == 0)
370                 ssc->ssc_msi_child = child;
371         return (error);
372 }
373
374 static int
375 siba_bwn_release_msi(device_t dev, device_t child)
376 {
377         struct siba_bwn_softc *ssc;
378         int error;
379
380         ssc = device_get_softc(dev);
381         if (ssc->ssc_msi_child != child)
382                 return (ENXIO);
383         error = pci_release_msi(dev);
384         if (error == 0)
385                 ssc->ssc_msi_child = NULL;
386         return (error);
387 }
388
389 static int
390 siba_bwn_msi_count(device_t dev, device_t child)
391 {
392
393         return (pci_msi_count(dev));
394 }
395
396 static int
397 siba_bwn_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
398 {
399         struct siba_dev_softc *sd;
400         struct siba_softc *siba;
401
402         sd = device_get_ivars(child);
403         siba = sd->sd_bus;
404
405         switch (which) {
406         case SIBA_IVAR_VENDOR:
407                 *result = sd->sd_id.sd_vendor;
408                 break;
409         case SIBA_IVAR_DEVICE:
410                 *result = sd->sd_id.sd_device;
411                 break;
412         case SIBA_IVAR_REVID:
413                 *result = sd->sd_id.sd_rev;
414                 break;
415         case SIBA_IVAR_PCI_VENDOR:
416                 *result = siba->siba_pci_vid;
417                 break;
418         case SIBA_IVAR_PCI_DEVICE:
419                 *result = siba->siba_pci_did;
420                 break;
421         case SIBA_IVAR_PCI_SUBVENDOR:
422                 *result = siba->siba_pci_subvid;
423                 break;
424         case SIBA_IVAR_PCI_SUBDEVICE:
425                 *result = siba->siba_pci_subdid;
426                 break;
427         case SIBA_IVAR_PCI_REVID:
428                 *result = siba->siba_pci_revid;
429                 break;
430         case SIBA_IVAR_CHIPID:
431                 *result = siba->siba_chipid;
432                 break;
433         case SIBA_IVAR_CHIPREV:
434                 *result = siba->siba_chiprev;
435                 break;
436         case SIBA_IVAR_CHIPPKG:
437                 *result = siba->siba_chippkg;
438                 break;
439         case SIBA_IVAR_TYPE:
440                 *result = siba->siba_type;
441                 break;
442         case SIBA_IVAR_CC_PMUFREQ:
443                 *result = siba->siba_cc.scc_pmu.freq;
444                 break;
445         case SIBA_IVAR_CC_CAPS:
446                 *result = siba->siba_cc.scc_caps;
447                 break;
448         case SIBA_IVAR_CC_POWERDELAY:
449                 *result = siba->siba_cc.scc_powerup_delay;
450                 break;
451         case SIBA_IVAR_PCICORE_REVID:
452                 *result = siba->siba_pci.spc_dev->sd_id.sd_rev;
453                 break;
454         default:
455                 return (ENOENT);
456         }
457
458         return (0);
459 }
460
461 static device_method_t siba_bwn_methods[] = {
462         /* Device interface */
463         DEVMETHOD(device_probe,         siba_bwn_probe),
464         DEVMETHOD(device_attach,        siba_bwn_attach),
465         DEVMETHOD(device_detach,        siba_bwn_detach),
466         DEVMETHOD(device_shutdown,      siba_bwn_shutdown),
467         DEVMETHOD(device_suspend,       siba_bwn_suspend),
468         DEVMETHOD(device_resume,        siba_bwn_resume),
469
470         /* Bus interface */
471         DEVMETHOD(bus_alloc_resource,   siba_bwn_alloc_resource),
472         DEVMETHOD(bus_release_resource, siba_bwn_release_resource),
473         DEVMETHOD(bus_read_ivar,        siba_bwn_read_ivar),
474         DEVMETHOD(bus_setup_intr,       siba_bwn_setup_intr),
475         DEVMETHOD(bus_teardown_intr,    siba_bwn_teardown_intr),
476
477         /* PCI interface */
478 #if !defined(__DragonFly__)
479         DEVMETHOD(pci_find_cap,         siba_bwn_find_cap),
480 #endif
481         DEVMETHOD(pci_find_extcap,      siba_bwn_find_extcap),
482 #if !defined(__DragonFly__)
483         DEVMETHOD(pci_find_htcap,       siba_bwn_find_htcap),
484 #endif
485         DEVMETHOD(pci_alloc_msi,        siba_bwn_alloc_msi),
486         DEVMETHOD(pci_release_msi,      siba_bwn_release_msi),
487         DEVMETHOD(pci_msi_count,        siba_bwn_msi_count),
488
489         DEVMETHOD_END
490 };
491 static driver_t siba_bwn_driver = {
492         "siba_bwn",
493         siba_bwn_methods,
494         sizeof(struct siba_bwn_softc)
495 };
496 static devclass_t siba_bwn_devclass;
497 DRIVER_MODULE(siba_bwn, pci, siba_bwn_driver, siba_bwn_devclass, NULL, NULL);
498 MODULE_VERSION(siba_bwn, 1);