]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/siba/siba_bwn.c
Merge ^/head r319801 through r320041.
[FreeBSD/FreeBSD.git] / sys / dev / 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$");
32
33 /*
34  * Sonics Silicon Backplane front-end for bwn(4).
35  */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/errno.h>
45 #include <machine/bus.h>
46 #include <machine/resource.h>
47 #include <sys/bus.h>
48 #include <sys/rman.h>
49 #include <sys/socket.h>
50
51 #include <net/if.h>
52 #include <net/if_media.h>
53 #include <net/if_arp.h>
54
55 #include <dev/pci/pcivar.h>
56 #include <dev/pci/pcireg.h>
57
58 #include <dev/siba/siba_ids.h>
59 #include <dev/siba/sibareg.h>
60 #include <dev/siba/sibavar.h>
61
62 /*
63  * PCI glue.
64  */
65
66 struct siba_bwn_softc {
67         /* Child driver using MSI. */
68         device_t                        ssc_msi_child;
69         struct siba_softc               ssc_siba;
70 };
71
72 #define BS_BAR                          0x10
73 #define PCI_VENDOR_BROADCOM             0x14e4
74 #define N(a)                            (sizeof(a) / sizeof(a[0]))
75
76 static const struct siba_dev {
77         uint16_t        vid;
78         uint16_t        did;
79         const char      *desc;
80 } siba_devices[] = {
81         { PCI_VENDOR_BROADCOM, 0x4301, "Broadcom BCM4301 802.11b Wireless" },
82         { PCI_VENDOR_BROADCOM, 0x4306, "Unknown" },
83         { PCI_VENDOR_BROADCOM, 0x4307, "Broadcom BCM4307 802.11b Wireless" },
84         { PCI_VENDOR_BROADCOM, 0x4311, "Broadcom BCM4311 802.11b/g Wireless" },
85         { PCI_VENDOR_BROADCOM, 0x4312,
86           "Broadcom BCM4312 802.11a/b/g Wireless" },
87         { PCI_VENDOR_BROADCOM, 0x4315, "Broadcom BCM4312 802.11b/g Wireless" },
88         { PCI_VENDOR_BROADCOM, 0x4318, "Broadcom BCM4318 802.11b/g Wireless" },
89         { PCI_VENDOR_BROADCOM, 0x4319,
90           "Broadcom BCM4318 802.11a/b/g Wireless" },
91         { PCI_VENDOR_BROADCOM, 0x4320, "Broadcom BCM4306 802.11b/g Wireless" },
92         { PCI_VENDOR_BROADCOM, 0x4321, "Broadcom BCM4306 802.11a Wireless" },
93         { PCI_VENDOR_BROADCOM, 0x4324,
94           "Broadcom BCM4309 802.11a/b/g Wireless" },
95         { PCI_VENDOR_BROADCOM, 0x4325, "Broadcom BCM4306 802.11b/g Wireless" },
96         { PCI_VENDOR_BROADCOM, 0x4328, "Broadcom BCM4321 802.11a/b/g/n Wireless" },
97         { PCI_VENDOR_BROADCOM, 0x4329, "Unknown" },
98         { PCI_VENDOR_BROADCOM, 0x432b, "Broadcom BCM4322 802.11a/b/g/n Wireless" }
99 };
100
101 int             siba_core_attach(struct siba_softc *);
102 int             siba_core_detach(struct siba_softc *);
103 int             siba_core_suspend(struct siba_softc *);
104 int             siba_core_resume(struct siba_softc *);
105
106 static int
107 siba_bwn_probe(device_t dev)
108 {
109         int i;
110         uint16_t did, vid;
111
112         did = pci_get_device(dev);
113         vid = pci_get_vendor(dev);
114
115         for (i = 0; i < N(siba_devices); i++) {
116                 if (siba_devices[i].did == did && siba_devices[i].vid == vid) {
117                         device_set_desc(dev, siba_devices[i].desc);
118                         return (BUS_PROBE_DEFAULT);
119                 }
120         }
121         return (ENXIO);
122 }
123
124 static int
125 siba_bwn_attach(device_t dev)
126 {
127         struct siba_bwn_softc *ssc = device_get_softc(dev);
128         struct siba_softc *siba = &ssc->ssc_siba;
129
130         siba->siba_dev = dev;
131         siba->siba_type = SIBA_TYPE_PCI;
132
133         /*
134          * Enable bus mastering.
135          */
136         pci_enable_busmaster(dev);
137
138         /* 
139          * Setup memory-mapping of PCI registers.
140          */
141         siba->siba_mem_rid = SIBA_PCIR_BAR;
142         siba->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
143                 &siba->siba_mem_rid, RF_ACTIVE);
144         if (siba->siba_mem_res == NULL) {
145                 device_printf(dev, "cannot map register space\n");
146                 return (ENXIO);
147         }
148         siba->siba_mem_bt = rman_get_bustag(siba->siba_mem_res);
149         siba->siba_mem_bh = rman_get_bushandle(siba->siba_mem_res);
150
151         /* Get more PCI information */
152         siba->siba_pci_did = pci_get_device(dev);
153         siba->siba_pci_vid = pci_get_vendor(dev);
154         siba->siba_pci_subvid = pci_get_subvendor(dev);
155         siba->siba_pci_subdid = pci_get_subdevice(dev);
156         siba->siba_pci_revid = pci_get_revid(dev);
157
158         return (siba_core_attach(siba));
159 }
160
161 static int
162 siba_bwn_detach(device_t dev)
163 {
164         struct siba_bwn_softc *ssc = device_get_softc(dev);
165         struct siba_softc *siba = &ssc->ssc_siba;
166
167         /* check if device was removed */
168         siba->siba_invalid = !bus_child_present(dev);
169
170         pci_disable_busmaster(dev);
171         bus_generic_detach(dev);
172         siba_core_detach(siba);
173
174         bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, siba->siba_mem_res);
175
176         return (0);
177 }
178
179 static int
180 siba_bwn_suspend(device_t dev)
181 {
182         struct siba_bwn_softc *ssc = device_get_softc(dev);
183         struct siba_softc *siba = &ssc->ssc_siba;
184         int error;
185
186         error = bus_generic_suspend(dev);
187
188         if (error != 0)
189                 return (error);
190
191         return (siba_core_suspend(siba));
192 }
193
194 static int
195 siba_bwn_resume(device_t dev)
196 {
197         struct siba_bwn_softc *ssc = device_get_softc(dev);
198         struct siba_softc *siba = &ssc->ssc_siba;
199         int error;
200
201         error = siba_core_resume(siba);
202         if (error != 0)
203                 return (error);
204
205         bus_generic_resume(dev);
206
207         return (0);
208 }
209
210 /* proxying to the parent */
211 static struct resource *
212 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid,
213     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
214 {
215
216         return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
217             type, rid, start, end, count, flags));
218 }
219
220 /* proxying to the parent */
221 static int
222 siba_bwn_release_resource(device_t dev, device_t child, int type,
223     int rid, struct resource *r)
224 {
225
226         return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type,
227             rid, r));
228 }
229
230 /* proxying to the parent */
231 static int
232 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq,
233     int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
234     void **cookiep)
235 {
236
237         return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
238             filter, intr, arg, cookiep));
239 }
240
241 /* proxying to the parent */
242 static int
243 siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq,
244     void *cookie)
245 {
246
247         return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
248 }
249
250 static int
251 siba_bwn_find_cap(device_t dev, device_t child, int capability,
252     int *capreg)
253 {
254
255         return (pci_find_cap(dev, capability, capreg));
256 }
257
258 static int
259 siba_bwn_find_extcap(device_t dev, device_t child, int capability,
260     int *capreg)
261 {
262
263         return (pci_find_extcap(dev, capability, capreg));
264 }
265
266 static int
267 siba_bwn_find_htcap(device_t dev, device_t child, int capability,
268     int *capreg)
269 {
270
271         return (pci_find_htcap(dev, capability, capreg));
272 }
273
274 static int
275 siba_bwn_alloc_msi(device_t dev, device_t child, int *count)
276 {
277         struct siba_bwn_softc *ssc;
278         int error;
279
280         ssc = device_get_softc(dev);
281         if (ssc->ssc_msi_child != NULL)
282                 return (EBUSY);
283         error = pci_alloc_msi(dev, count);
284         if (error == 0)
285                 ssc->ssc_msi_child = child;
286         return (error);
287 }
288
289 static int
290 siba_bwn_release_msi(device_t dev, device_t child)
291 {
292         struct siba_bwn_softc *ssc;
293         int error;
294
295         ssc = device_get_softc(dev);
296         if (ssc->ssc_msi_child != child)
297                 return (ENXIO);
298         error = pci_release_msi(dev);
299         if (error == 0)
300                 ssc->ssc_msi_child = NULL;
301         return (error);
302 }
303
304 static int
305 siba_bwn_msi_count(device_t dev, device_t child)
306 {
307
308         return (pci_msi_count(dev));
309 }
310
311 static int
312 siba_bwn_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
313 {
314         struct siba_dev_softc *sd;
315         struct siba_softc *siba;
316
317         sd = device_get_ivars(child);
318         siba = sd->sd_bus;
319
320         switch (which) {
321         case SIBA_IVAR_VENDOR:
322                 *result = sd->sd_id.sd_vendor;
323                 break;
324         case SIBA_IVAR_DEVICE:
325                 *result = sd->sd_id.sd_device;
326                 break;
327         case SIBA_IVAR_REVID:
328                 *result = sd->sd_id.sd_rev;
329                 break;
330         case SIBA_IVAR_PCI_VENDOR:
331                 *result = siba->siba_pci_vid;
332                 break;
333         case SIBA_IVAR_PCI_DEVICE:
334                 *result = siba->siba_pci_did;
335                 break;
336         case SIBA_IVAR_PCI_SUBVENDOR:
337                 *result = siba->siba_pci_subvid;
338                 break;
339         case SIBA_IVAR_PCI_SUBDEVICE:
340                 *result = siba->siba_pci_subdid;
341                 break;
342         case SIBA_IVAR_PCI_REVID:
343                 *result = siba->siba_pci_revid;
344                 break;
345         case SIBA_IVAR_CHIPID:
346                 *result = siba->siba_chipid;
347                 break;
348         case SIBA_IVAR_CHIPREV:
349                 *result = siba->siba_chiprev;
350                 break;
351         case SIBA_IVAR_CHIPPKG:
352                 *result = siba->siba_chippkg;
353                 break;
354         case SIBA_IVAR_TYPE:
355                 *result = siba->siba_type;
356                 break;
357         case SIBA_IVAR_CC_PMUFREQ:
358                 *result = siba->siba_cc.scc_pmu.freq;
359                 break;
360         case SIBA_IVAR_CC_CAPS:
361                 *result = siba->siba_cc.scc_caps;
362                 break;
363         case SIBA_IVAR_CC_POWERDELAY:
364                 *result = siba->siba_cc.scc_powerup_delay;
365                 break;
366         case SIBA_IVAR_PCICORE_REVID:
367                 *result = siba->siba_pci.spc_dev->sd_id.sd_rev;
368                 break;
369         default:
370                 return (ENOENT);
371         }
372
373         return (0);
374 }
375
376 static device_method_t siba_bwn_methods[] = {
377         /* Device interface */
378         DEVMETHOD(device_probe,         siba_bwn_probe),
379         DEVMETHOD(device_attach,        siba_bwn_attach),
380         DEVMETHOD(device_detach,        siba_bwn_detach),
381         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
382         DEVMETHOD(device_suspend,       siba_bwn_suspend),
383         DEVMETHOD(device_resume,        siba_bwn_resume),
384
385         /* Bus interface */
386         DEVMETHOD(bus_alloc_resource,   siba_bwn_alloc_resource),
387         DEVMETHOD(bus_release_resource, siba_bwn_release_resource),
388         DEVMETHOD(bus_read_ivar,        siba_bwn_read_ivar),
389         DEVMETHOD(bus_setup_intr,       siba_bwn_setup_intr),
390         DEVMETHOD(bus_teardown_intr,    siba_bwn_teardown_intr),
391
392         /* PCI interface */
393         DEVMETHOD(pci_find_cap,         siba_bwn_find_cap),
394         DEVMETHOD(pci_find_extcap,      siba_bwn_find_extcap),
395         DEVMETHOD(pci_find_htcap,       siba_bwn_find_htcap),
396         DEVMETHOD(pci_alloc_msi,        siba_bwn_alloc_msi),
397         DEVMETHOD(pci_release_msi,      siba_bwn_release_msi),
398         DEVMETHOD(pci_msi_count,        siba_bwn_msi_count),
399
400         DEVMETHOD_END
401 };
402 static driver_t siba_bwn_driver = {
403         "siba_bwn",
404         siba_bwn_methods,
405         sizeof(struct siba_bwn_softc)
406 };
407 static devclass_t siba_bwn_devclass;
408 DRIVER_MODULE(siba_bwn, pci, siba_bwn_driver, siba_bwn_devclass, 0, 0);
409 MODULE_VERSION(siba_bwn, 1);