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