xref: /dragonfly/sys/dev/netif/bwn/siba/siba_bwn.c (revision 0fe46dc6)
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 #define	N(a)				(sizeof(a) / sizeof(a[0]))
92 
93 static const struct siba_dev {
94 	uint16_t	vid;
95 	uint16_t	did;
96 	const char	*desc;
97 } siba_devices[] = {
98 	{ PCI_VENDOR_BROADCOM, 0x4301, "Broadcom BCM4301 802.11b Wireless" },
99 	{ PCI_VENDOR_BROADCOM, 0x4306, "Unknown" },
100 	{ PCI_VENDOR_BROADCOM, 0x4307, "Broadcom BCM4307 802.11b Wireless" },
101 	{ PCI_VENDOR_BROADCOM, 0x4311, "Broadcom BCM4311 802.11b/g Wireless" },
102 	{ PCI_VENDOR_BROADCOM, 0x4312,
103 	  "Broadcom BCM4312 802.11a/b/g Wireless" },
104 	{ PCI_VENDOR_BROADCOM, 0x4315, "Broadcom BCM4312 802.11b/g Wireless" },
105 	{ PCI_VENDOR_BROADCOM, 0x4318, "Broadcom BCM4318 802.11b/g Wireless" },
106 	{ PCI_VENDOR_BROADCOM, 0x4319,
107 	  "Broadcom BCM4318 802.11a/b/g Wireless" },
108 	{ PCI_VENDOR_BROADCOM, 0x4320, "Broadcom BCM4306 802.11b/g Wireless" },
109 	{ PCI_VENDOR_BROADCOM, 0x4321, "Broadcom BCM4306 802.11a Wireless" },
110 	{ PCI_VENDOR_BROADCOM, 0x4324,
111 	  "Broadcom BCM4309 802.11a/b/g Wireless" },
112 	{ PCI_VENDOR_BROADCOM, 0x4325, "Broadcom BCM4306 802.11b/g Wireless" },
113 	{ PCI_VENDOR_BROADCOM, 0x4328, "Broadcom BCM4321 802.11a/b/g Wireless" },
114 	{ PCI_VENDOR_BROADCOM, 0x4329, "Unknown" },
115 	{ PCI_VENDOR_BROADCOM, 0x432b, "Unknown" }
116 };
117 
118 int		siba_core_attach(struct siba_softc *);
119 int		siba_core_detach(struct siba_softc *);
120 int		siba_core_suspend(struct siba_softc *);
121 int		siba_core_resume(struct siba_softc *);
122 
123 static int
124 siba_bwn_probe(device_t dev)
125 {
126 	int i;
127 	uint16_t did, vid;
128 
129 	did = pci_get_device(dev);
130 	vid = pci_get_vendor(dev);
131 
132 	for (i = 0; i < N(siba_devices); i++) {
133 		if (siba_devices[i].did == did && siba_devices[i].vid == vid) {
134 			device_set_desc(dev, siba_devices[i].desc);
135 			return (BUS_PROBE_DEFAULT);
136 		}
137 	}
138 	return (ENXIO);
139 }
140 
141 static int
142 siba_bwn_attach(device_t dev)
143 {
144 	struct siba_bwn_softc *ssc = device_get_softc(dev);
145 	struct siba_softc *siba = &ssc->ssc_siba;
146 
147 	siba->siba_dev = dev;
148 	siba->siba_type = SIBA_TYPE_PCI;
149 
150 	/*
151 	 * Enable bus mastering.
152 	 */
153 	pci_enable_busmaster(dev);
154 
155 	/*
156 	 * Setup memory-mapping of PCI registers.
157 	 */
158 	siba->siba_mem_rid = SIBA_PCIR_BAR;
159 	siba->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
160 		&siba->siba_mem_rid, RF_ACTIVE);
161 	if (siba->siba_mem_res == NULL) {
162 		device_printf(dev, "cannot map register space\n");
163 		return (ENXIO);
164 	}
165 	siba->siba_mem_bt = rman_get_bustag(siba->siba_mem_res);
166 	siba->siba_mem_bh = rman_get_bushandle(siba->siba_mem_res);
167 
168 	/* Get more PCI information */
169 	siba->siba_pci_did = pci_get_device(dev);
170 	siba->siba_pci_vid = pci_get_vendor(dev);
171 	siba->siba_pci_subvid = pci_get_subvendor(dev);
172 	siba->siba_pci_subdid = pci_get_subdevice(dev);
173 	siba->siba_pci_revid = pci_get_revid(dev);
174 
175 	return (siba_core_attach(siba));
176 }
177 
178 static int
179 siba_bwn_detach(device_t dev)
180 {
181 	struct siba_bwn_softc *ssc = device_get_softc(dev);
182 	struct siba_softc *siba = &ssc->ssc_siba;
183 
184 	/* check if device was removed */
185 	siba->siba_invalid = !bus_child_present(dev);
186 
187 	pci_disable_busmaster(dev);
188 	bus_generic_detach(dev);
189 	siba_core_detach(siba);
190 
191 	bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, siba->siba_mem_res);
192 
193 	return (0);
194 }
195 
196 static int
197 siba_bwn_shutdown(device_t dev)
198 {
199 	device_t *devlistp;
200 	int devcnt, error = 0, i;
201 
202 	error = device_get_children(dev, &devlistp, &devcnt);
203 	if (error != 0)
204 		return (error);
205 
206 	for (i = 0 ; i < devcnt ; i++)
207 		device_shutdown(devlistp[i]);
208 	kfree(devlistp, M_TEMP);
209 	return (0);
210 }
211 
212 static int
213 siba_bwn_suspend(device_t dev)
214 {
215 	struct siba_bwn_softc *ssc = device_get_softc(dev);
216 	struct siba_softc *siba = &ssc->ssc_siba;
217 	device_t *devlistp;
218 	int devcnt, error = 0, i, j;
219 
220 	error = device_get_children(dev, &devlistp, &devcnt);
221 	if (error != 0)
222 		return (error);
223 
224 	for (i = 0 ; i < devcnt ; i++) {
225 		error = DEVICE_SUSPEND(devlistp[i]);
226 		if (error) {
227 			for (j = 0; j < i; j++)
228 				DEVICE_RESUME(devlistp[j]);
229 			kfree(devlistp, M_TEMP);
230 			return (error);
231 		}
232 	}
233 	kfree(devlistp, M_TEMP);
234 	return (siba_core_suspend(siba));
235 }
236 
237 static int
238 siba_bwn_resume(device_t dev)
239 {
240 	struct siba_bwn_softc *ssc = device_get_softc(dev);
241 	struct siba_softc *siba = &ssc->ssc_siba;
242 	device_t *devlistp;
243 	int devcnt, error = 0, i;
244 
245 	error = siba_core_resume(siba);
246 	if (error != 0)
247 		return (error);
248 
249 	error = device_get_children(dev, &devlistp, &devcnt);
250 	if (error != 0)
251 		return (error);
252 
253 	for (i = 0 ; i < devcnt ; i++)
254 		DEVICE_RESUME(devlistp[i]);
255 	kfree(devlistp, M_TEMP);
256 	return (0);
257 }
258 
259 /* proxying to the parent */
260 #if defined(__DragonFly__)
261 static struct resource *
262 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid,
263     u_long start, u_long end, u_long count, u_int flags, int cpuid)
264 {
265 
266 	return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
267 	    type, rid, start, end, count, flags, cpuid));
268 }
269 #else
270 static struct resource *
271 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid,
272     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
273 {
274 
275 	return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
276 	    type, rid, start, end, count, flags));
277 }
278 #endif
279 
280 /* proxying to the parent */
281 static int
282 siba_bwn_release_resource(device_t dev, device_t child, int type,
283     int rid, struct resource *r)
284 {
285 
286 	return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type,
287 	    rid, r));
288 }
289 
290 #if defined(__DragonFly__)
291 /* proxying to the parent */
292 static int
293 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq,
294     int flags, driver_intr_t *intr, void *arg, void **cookiep,
295     lwkt_serialize_t serializer)
296 {
297 
298 	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
299 	    intr, arg, cookiep, serializer, NULL));
300 }
301 #else
302 static int
303 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq,
304     int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
305     void **cookiep)
306 {
307 
308 	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
309 	    filter, intr, arg, cookiep));
310 }
311 #endif
312 
313 /* proxying to the parent */
314 static int
315 siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq,
316     void *cookie)
317 {
318 
319 	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
320 }
321 
322 #if !defined(__DragonFly__)
323 static int
324 siba_bwn_find_cap(device_t dev, device_t child, int capability,
325     int *capreg)
326 {
327 
328 	return (pci_find_cap(dev, capability, capreg));
329 }
330 #endif
331 
332 static int
333 siba_bwn_find_extcap(device_t dev, device_t child, int capability,
334     int *capreg)
335 {
336 
337 	return (pci_find_extcap(dev, capability, capreg));
338 }
339 
340 #if !defined(__DragonFly__)
341 static int
342 siba_bwn_find_htcap(device_t dev, device_t child, int capability,
343     int *capreg)
344 {
345 
346 	return (pci_find_htcap(dev, capability, capreg));
347 }
348 #endif
349 
350 #if defined(__DragonFly__)
351 static int
352 siba_bwn_alloc_msi(device_t dev, device_t child, int *rid, int count,
353     int cpuid)
354 #else
355 static int
356 siba_bwn_alloc_msi(device_t dev, device_t child, int *count)
357 #endif
358 {
359 	struct siba_bwn_softc *ssc;
360 	int error;
361 
362 	ssc = device_get_softc(dev);
363 	if (ssc->ssc_msi_child != NULL)
364 		return (EBUSY);
365 #if defined(__DragonFly__)
366 	error = pci_alloc_msi(dev, rid, count, cpuid);
367 #else
368 	error = pci_alloc_msi(dev, count);
369 #endif
370 	if (error == 0)
371 		ssc->ssc_msi_child = child;
372 	return (error);
373 }
374 
375 static int
376 siba_bwn_release_msi(device_t dev, device_t child)
377 {
378 	struct siba_bwn_softc *ssc;
379 	int error;
380 
381 	ssc = device_get_softc(dev);
382 	if (ssc->ssc_msi_child != child)
383 		return (ENXIO);
384 	error = pci_release_msi(dev);
385 	if (error == 0)
386 		ssc->ssc_msi_child = NULL;
387 	return (error);
388 }
389 
390 static int
391 siba_bwn_msi_count(device_t dev, device_t child)
392 {
393 
394 	return (pci_msi_count(dev));
395 }
396 
397 static int
398 siba_bwn_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
399 {
400 	struct siba_dev_softc *sd;
401 	struct siba_softc *siba;
402 
403 	sd = device_get_ivars(child);
404 	siba = sd->sd_bus;
405 
406 	switch (which) {
407 	case SIBA_IVAR_VENDOR:
408 		*result = sd->sd_id.sd_vendor;
409 		break;
410 	case SIBA_IVAR_DEVICE:
411 		*result = sd->sd_id.sd_device;
412 		break;
413 	case SIBA_IVAR_REVID:
414 		*result = sd->sd_id.sd_rev;
415 		break;
416 	case SIBA_IVAR_PCI_VENDOR:
417 		*result = siba->siba_pci_vid;
418 		break;
419 	case SIBA_IVAR_PCI_DEVICE:
420 		*result = siba->siba_pci_did;
421 		break;
422 	case SIBA_IVAR_PCI_SUBVENDOR:
423 		*result = siba->siba_pci_subvid;
424 		break;
425 	case SIBA_IVAR_PCI_SUBDEVICE:
426 		*result = siba->siba_pci_subdid;
427 		break;
428 	case SIBA_IVAR_PCI_REVID:
429 		*result = siba->siba_pci_revid;
430 		break;
431 	case SIBA_IVAR_CHIPID:
432 		*result = siba->siba_chipid;
433 		break;
434 	case SIBA_IVAR_CHIPREV:
435 		*result = siba->siba_chiprev;
436 		break;
437 	case SIBA_IVAR_CHIPPKG:
438 		*result = siba->siba_chippkg;
439 		break;
440 	case SIBA_IVAR_TYPE:
441 		*result = siba->siba_type;
442 		break;
443 	case SIBA_IVAR_CC_PMUFREQ:
444 		*result = siba->siba_cc.scc_pmu.freq;
445 		break;
446 	case SIBA_IVAR_CC_CAPS:
447 		*result = siba->siba_cc.scc_caps;
448 		break;
449 	case SIBA_IVAR_CC_POWERDELAY:
450 		*result = siba->siba_cc.scc_powerup_delay;
451 		break;
452 	case SIBA_IVAR_PCICORE_REVID:
453 		*result = siba->siba_pci.spc_dev->sd_id.sd_rev;
454 		break;
455 	default:
456 		return (ENOENT);
457 	}
458 
459 	return (0);
460 }
461 
462 static device_method_t siba_bwn_methods[] = {
463 	/* Device interface */
464 	DEVMETHOD(device_probe,		siba_bwn_probe),
465 	DEVMETHOD(device_attach,	siba_bwn_attach),
466 	DEVMETHOD(device_detach,	siba_bwn_detach),
467 	DEVMETHOD(device_shutdown,	siba_bwn_shutdown),
468 	DEVMETHOD(device_suspend,	siba_bwn_suspend),
469 	DEVMETHOD(device_resume,	siba_bwn_resume),
470 
471 	/* Bus interface */
472 	DEVMETHOD(bus_alloc_resource,   siba_bwn_alloc_resource),
473 	DEVMETHOD(bus_release_resource, siba_bwn_release_resource),
474 	DEVMETHOD(bus_read_ivar,	siba_bwn_read_ivar),
475 	DEVMETHOD(bus_setup_intr,       siba_bwn_setup_intr),
476 	DEVMETHOD(bus_teardown_intr,    siba_bwn_teardown_intr),
477 
478 	/* PCI interface */
479 #if !defined(__DragonFly__)
480 	DEVMETHOD(pci_find_cap,		siba_bwn_find_cap),
481 #endif
482 	DEVMETHOD(pci_find_extcap,	siba_bwn_find_extcap),
483 #if !defined(__DragonFly__)
484 	DEVMETHOD(pci_find_htcap,	siba_bwn_find_htcap),
485 #endif
486 	DEVMETHOD(pci_alloc_msi,	siba_bwn_alloc_msi),
487 	DEVMETHOD(pci_release_msi,	siba_bwn_release_msi),
488 	DEVMETHOD(pci_msi_count,	siba_bwn_msi_count),
489 
490 	DEVMETHOD_END
491 };
492 static driver_t siba_bwn_driver = {
493 	"siba_bwn",
494 	siba_bwn_methods,
495 	sizeof(struct siba_bwn_softc)
496 };
497 static devclass_t siba_bwn_devclass;
498 DRIVER_MODULE(siba_bwn, pci, siba_bwn_driver, siba_bwn_devclass, NULL, NULL);
499 MODULE_VERSION(siba_bwn, 1);
500