xref: /freebsd/sys/dev/ral/if_ral_pci.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1ceaec73dSDamien Bergamini /*-
29c6307b1SDamien Bergamini  * Copyright (c) 2005, 2006
3ceaec73dSDamien Bergamini  *	Damien Bergamini <damien.bergamini@free.fr>
4ceaec73dSDamien Bergamini  *
5ceaec73dSDamien Bergamini  * Permission to use, copy, modify, and distribute this software for any
6ceaec73dSDamien Bergamini  * purpose with or without fee is hereby granted, provided that the above
7ceaec73dSDamien Bergamini  * copyright notice and this permission notice appear in all copies.
8ceaec73dSDamien Bergamini  *
9ceaec73dSDamien Bergamini  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ceaec73dSDamien Bergamini  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ceaec73dSDamien Bergamini  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ceaec73dSDamien Bergamini  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ceaec73dSDamien Bergamini  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ceaec73dSDamien Bergamini  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ceaec73dSDamien Bergamini  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ceaec73dSDamien Bergamini  */
17ceaec73dSDamien Bergamini 
18ceaec73dSDamien Bergamini #include <sys/cdefs.h>
19ceaec73dSDamien Bergamini /*
209c6307b1SDamien Bergamini  * PCI/Cardbus front-end for the Ralink RT2560/RT2561/RT2561S/RT2661 driver.
21ceaec73dSDamien Bergamini  */
22ceaec73dSDamien Bergamini 
23ceaec73dSDamien Bergamini #include <sys/param.h>
24ceaec73dSDamien Bergamini #include <sys/systm.h>
2597db2528SMarius Strobl #include <sys/bus.h>
2697db2528SMarius Strobl #include <sys/kernel.h>
2797db2528SMarius Strobl #include <sys/lock.h>
28ceaec73dSDamien Bergamini #include <sys/malloc.h>
297a79cebfSGleb Smirnoff #include <sys/mbuf.h>
30ceaec73dSDamien Bergamini #include <sys/module.h>
3197db2528SMarius Strobl #include <sys/mutex.h>
3297db2528SMarius Strobl #include <sys/rman.h>
3397db2528SMarius Strobl #include <sys/socket.h>
34ceaec73dSDamien Bergamini 
35ceaec73dSDamien Bergamini #include <machine/bus.h>
36ceaec73dSDamien Bergamini #include <machine/resource.h>
37ceaec73dSDamien Bergamini 
38ceaec73dSDamien Bergamini #include <net/ethernet.h>
3997db2528SMarius Strobl #include <net/if.h>
40ceaec73dSDamien Bergamini #include <net/if_media.h>
4197db2528SMarius Strobl #include <net/route.h>
42ceaec73dSDamien Bergamini 
43ceaec73dSDamien Bergamini #include <net80211/ieee80211_var.h>
44ceaec73dSDamien Bergamini #include <net80211/ieee80211_radiotap.h>
45f6930becSAndriy Voskoboinyk #include <net80211/ieee80211_ratectl.h>
46ceaec73dSDamien Bergamini 
47ceaec73dSDamien Bergamini #include <dev/pci/pcireg.h>
48ceaec73dSDamien Bergamini #include <dev/pci/pcivar.h>
49ceaec73dSDamien Bergamini 
502017e1cbSMike Silbersack #include <dev/ral/rt2560var.h>
512017e1cbSMike Silbersack #include <dev/ral/rt2661var.h>
524310d6deSBernhard Schmidt #include <dev/ral/rt2860var.h>
53ceaec73dSDamien Bergamini 
54ceaec73dSDamien Bergamini MODULE_DEPEND(ral, pci, 1, 1, 1);
55b032f27cSSam Leffler MODULE_DEPEND(ral, firmware, 1, 1, 1);
56ceaec73dSDamien Bergamini MODULE_DEPEND(ral, wlan, 1, 1, 1);
57b032f27cSSam Leffler MODULE_DEPEND(ral, wlan_amrr, 1, 1, 1);
58ceaec73dSDamien Bergamini 
5997db2528SMarius Strobl static int ral_msi_disable;
6097db2528SMarius Strobl TUNABLE_INT("hw.ral.msi_disable", &ral_msi_disable);
6197db2528SMarius Strobl 
62ceaec73dSDamien Bergamini struct ral_pci_ident {
63ceaec73dSDamien Bergamini 	uint16_t	vendor;
64ceaec73dSDamien Bergamini 	uint16_t	device;
65ceaec73dSDamien Bergamini 	const char	*name;
66ceaec73dSDamien Bergamini };
67ceaec73dSDamien Bergamini 
68ceaec73dSDamien Bergamini static const struct ral_pci_ident ral_pci_ids[] = {
694310d6deSBernhard Schmidt 	{ 0x1432, 0x7708, "Edimax RT2860" },
704310d6deSBernhard Schmidt 	{ 0x1432, 0x7711, "Edimax RT3591" },
714310d6deSBernhard Schmidt 	{ 0x1432, 0x7722, "Edimax RT3591" },
724310d6deSBernhard Schmidt 	{ 0x1432, 0x7727, "Edimax RT2860" },
734310d6deSBernhard Schmidt 	{ 0x1432, 0x7728, "Edimax RT2860" },
744310d6deSBernhard Schmidt 	{ 0x1432, 0x7738, "Edimax RT2860" },
754310d6deSBernhard Schmidt 	{ 0x1432, 0x7748, "Edimax RT2860" },
764310d6deSBernhard Schmidt 	{ 0x1432, 0x7758, "Edimax RT2860" },
774310d6deSBernhard Schmidt 	{ 0x1432, 0x7768, "Edimax RT2860" },
784310d6deSBernhard Schmidt 	{ 0x1462, 0x891a, "MSI RT3090" },
799c6307b1SDamien Bergamini 	{ 0x1814, 0x0201, "Ralink Technology RT2560" },
809c6307b1SDamien Bergamini 	{ 0x1814, 0x0301, "Ralink Technology RT2561S" },
819c6307b1SDamien Bergamini 	{ 0x1814, 0x0302, "Ralink Technology RT2561" },
829c6307b1SDamien Bergamini 	{ 0x1814, 0x0401, "Ralink Technology RT2661" },
834310d6deSBernhard Schmidt 	{ 0x1814, 0x0601, "Ralink Technology RT2860" },
844310d6deSBernhard Schmidt 	{ 0x1814, 0x0681, "Ralink Technology RT2890" },
854310d6deSBernhard Schmidt 	{ 0x1814, 0x0701, "Ralink Technology RT2760" },
864310d6deSBernhard Schmidt 	{ 0x1814, 0x0781, "Ralink Technology RT2790" },
874310d6deSBernhard Schmidt 	{ 0x1814, 0x3060, "Ralink Technology RT3060" },
884310d6deSBernhard Schmidt 	{ 0x1814, 0x3062, "Ralink Technology RT3062" },
894310d6deSBernhard Schmidt 	{ 0x1814, 0x3090, "Ralink Technology RT3090" },
904310d6deSBernhard Schmidt 	{ 0x1814, 0x3091, "Ralink Technology RT3091" },
914310d6deSBernhard Schmidt 	{ 0x1814, 0x3092, "Ralink Technology RT3092" },
924310d6deSBernhard Schmidt 	{ 0x1814, 0x3390, "Ralink Technology RT3390" },
934310d6deSBernhard Schmidt 	{ 0x1814, 0x3562, "Ralink Technology RT3562" },
944310d6deSBernhard Schmidt 	{ 0x1814, 0x3592, "Ralink Technology RT3592" },
954310d6deSBernhard Schmidt 	{ 0x1814, 0x3593, "Ralink Technology RT3593" },
966fc44dabSKevin Lo 	{ 0x1814, 0x5360, "Ralink Technology RT5390" },
976fc44dabSKevin Lo 	{ 0x1814, 0x5362, "Ralink Technology RT5392" },
984310d6deSBernhard Schmidt 	{ 0x1814, 0x5390, "Ralink Technology RT5390" },
996fc44dabSKevin Lo 	{ 0x1814, 0x5392, "Ralink Technology RT5392" },
1004310d6deSBernhard Schmidt 	{ 0x1814, 0x539a, "Ralink Technology RT5390" },
101cfd47479SMichael Zhilin 	{ 0x1814, 0x539b, "Ralink Technology RT5390" },
1024310d6deSBernhard Schmidt 	{ 0x1814, 0x539f, "Ralink Technology RT5390" },
1034310d6deSBernhard Schmidt 	{ 0x1a3b, 0x1059, "AWT RT2890" },
104ceaec73dSDamien Bergamini 	{ 0, 0, NULL }
105ceaec73dSDamien Bergamini };
106ceaec73dSDamien Bergamini 
10797db2528SMarius Strobl static const struct ral_opns {
1089c6307b1SDamien Bergamini 	int	(*attach)(device_t, int);
1099c6307b1SDamien Bergamini 	int	(*detach)(void *);
1109c6307b1SDamien Bergamini 	void	(*shutdown)(void *);
1119c6307b1SDamien Bergamini 	void	(*suspend)(void *);
1129c6307b1SDamien Bergamini 	void	(*resume)(void *);
1139c6307b1SDamien Bergamini 	void	(*intr)(void *);
1149c6307b1SDamien Bergamini 
1159c6307b1SDamien Bergamini }  ral_rt2560_opns = {
1169c6307b1SDamien Bergamini 	rt2560_attach,
1179c6307b1SDamien Bergamini 	rt2560_detach,
11868e8e04eSSam Leffler 	rt2560_stop,
11968e8e04eSSam Leffler 	rt2560_stop,
1209c6307b1SDamien Bergamini 	rt2560_resume,
1219c6307b1SDamien Bergamini 	rt2560_intr
1229c6307b1SDamien Bergamini 
1239c6307b1SDamien Bergamini }, ral_rt2661_opns = {
1249c6307b1SDamien Bergamini 	rt2661_attach,
1259c6307b1SDamien Bergamini 	rt2661_detach,
1269c6307b1SDamien Bergamini 	rt2661_shutdown,
1279c6307b1SDamien Bergamini 	rt2661_suspend,
1289c6307b1SDamien Bergamini 	rt2661_resume,
1299c6307b1SDamien Bergamini 	rt2661_intr
1304310d6deSBernhard Schmidt }, ral_rt2860_opns = {
1314310d6deSBernhard Schmidt 	rt2860_attach,
1324310d6deSBernhard Schmidt 	rt2860_detach,
1334310d6deSBernhard Schmidt 	rt2860_shutdown,
1344310d6deSBernhard Schmidt 	rt2860_suspend,
1354310d6deSBernhard Schmidt 	rt2860_resume,
1364310d6deSBernhard Schmidt 	rt2860_intr
1379c6307b1SDamien Bergamini };
1389c6307b1SDamien Bergamini 
1399c6307b1SDamien Bergamini struct ral_pci_softc {
1409c6307b1SDamien Bergamini 	union {
1419c6307b1SDamien Bergamini 		struct rt2560_softc sc_rt2560;
1429c6307b1SDamien Bergamini 		struct rt2661_softc sc_rt2661;
1434310d6deSBernhard Schmidt 		struct rt2860_softc sc_rt2860;
1449c6307b1SDamien Bergamini 	} u;
1459c6307b1SDamien Bergamini 
14697db2528SMarius Strobl 	const struct ral_opns	*sc_opns;
1479c6307b1SDamien Bergamini 	struct resource		*irq;
1489c6307b1SDamien Bergamini 	struct resource		*mem;
1499c6307b1SDamien Bergamini 	void			*sc_ih;
1509c6307b1SDamien Bergamini };
1519c6307b1SDamien Bergamini 
152ceaec73dSDamien Bergamini static int ral_pci_probe(device_t);
153ceaec73dSDamien Bergamini static int ral_pci_attach(device_t);
1549c6307b1SDamien Bergamini static int ral_pci_detach(device_t);
1559c6307b1SDamien Bergamini static int ral_pci_shutdown(device_t);
156ceaec73dSDamien Bergamini static int ral_pci_suspend(device_t);
157ceaec73dSDamien Bergamini static int ral_pci_resume(device_t);
158ceaec73dSDamien Bergamini 
159ceaec73dSDamien Bergamini static device_method_t ral_pci_methods[] = {
160ceaec73dSDamien Bergamini 	/* Device interface */
161ceaec73dSDamien Bergamini 	DEVMETHOD(device_probe,		ral_pci_probe),
162ceaec73dSDamien Bergamini 	DEVMETHOD(device_attach,	ral_pci_attach),
1639c6307b1SDamien Bergamini 	DEVMETHOD(device_detach,	ral_pci_detach),
1649c6307b1SDamien Bergamini 	DEVMETHOD(device_shutdown,	ral_pci_shutdown),
165ceaec73dSDamien Bergamini 	DEVMETHOD(device_suspend,	ral_pci_suspend),
166ceaec73dSDamien Bergamini 	DEVMETHOD(device_resume,	ral_pci_resume),
167ceaec73dSDamien Bergamini 
16897db2528SMarius Strobl 	DEVMETHOD_END
169ceaec73dSDamien Bergamini };
170ceaec73dSDamien Bergamini 
171ceaec73dSDamien Bergamini static driver_t ral_pci_driver = {
172ceaec73dSDamien Bergamini 	"ral",
173ceaec73dSDamien Bergamini 	ral_pci_methods,
1749c6307b1SDamien Bergamini 	sizeof (struct ral_pci_softc)
175ceaec73dSDamien Bergamini };
176ceaec73dSDamien Bergamini 
177*aed8cdc8SJohn Baldwin DRIVER_MODULE(ral, pci, ral_pci_driver, NULL, NULL);
1780dc34160SWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, ral, ral_pci_ids,
1790dc34160SWarner Losh     nitems(ral_pci_ids) - 1);
180ceaec73dSDamien Bergamini 
181ceaec73dSDamien Bergamini static int
ral_pci_probe(device_t dev)182ceaec73dSDamien Bergamini ral_pci_probe(device_t dev)
183ceaec73dSDamien Bergamini {
184ceaec73dSDamien Bergamini 	const struct ral_pci_ident *ident;
185ceaec73dSDamien Bergamini 
186ceaec73dSDamien Bergamini 	for (ident = ral_pci_ids; ident->name != NULL; ident++) {
187ceaec73dSDamien Bergamini 		if (pci_get_vendor(dev) == ident->vendor &&
188ceaec73dSDamien Bergamini 		    pci_get_device(dev) == ident->device) {
189ceaec73dSDamien Bergamini 			device_set_desc(dev, ident->name);
19097db2528SMarius Strobl 			return (BUS_PROBE_DEFAULT);
191ceaec73dSDamien Bergamini 		}
192ceaec73dSDamien Bergamini 	}
193ceaec73dSDamien Bergamini 	return ENXIO;
194ceaec73dSDamien Bergamini }
195ceaec73dSDamien Bergamini 
196ceaec73dSDamien Bergamini static int
ral_pci_attach(device_t dev)197ceaec73dSDamien Bergamini ral_pci_attach(device_t dev)
198ceaec73dSDamien Bergamini {
1999c6307b1SDamien Bergamini 	struct ral_pci_softc *psc = device_get_softc(dev);
2009c6307b1SDamien Bergamini 	struct rt2560_softc *sc = &psc->u.sc_rt2560;
20197db2528SMarius Strobl 	int count, error, rid;
202ceaec73dSDamien Bergamini 
203ceaec73dSDamien Bergamini 	pci_enable_busmaster(dev);
204ceaec73dSDamien Bergamini 
2054310d6deSBernhard Schmidt 	switch (pci_get_device(dev)) {
2064310d6deSBernhard Schmidt 	case 0x0201:
2074310d6deSBernhard Schmidt 		psc->sc_opns = &ral_rt2560_opns;
2084310d6deSBernhard Schmidt 		break;
2094310d6deSBernhard Schmidt 	case 0x0301:
2104310d6deSBernhard Schmidt 	case 0x0302:
2114310d6deSBernhard Schmidt 	case 0x0401:
2124310d6deSBernhard Schmidt 		psc->sc_opns = &ral_rt2661_opns;
2134310d6deSBernhard Schmidt 		break;
2144310d6deSBernhard Schmidt 	default:
2154310d6deSBernhard Schmidt 		psc->sc_opns = &ral_rt2860_opns;
2164310d6deSBernhard Schmidt 		break;
2174310d6deSBernhard Schmidt 	}
2189c6307b1SDamien Bergamini 
21997db2528SMarius Strobl 	rid = PCIR_BAR(0);
22097db2528SMarius Strobl 	psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
2219c6307b1SDamien Bergamini 	    RF_ACTIVE);
2229c6307b1SDamien Bergamini 	if (psc->mem == NULL) {
2239c6307b1SDamien Bergamini 		device_printf(dev, "could not allocate memory resource\n");
2249c6307b1SDamien Bergamini 		return ENXIO;
2259c6307b1SDamien Bergamini 	}
2269c6307b1SDamien Bergamini 
2279c6307b1SDamien Bergamini 	sc->sc_st = rman_get_bustag(psc->mem);
2289c6307b1SDamien Bergamini 	sc->sc_sh = rman_get_bushandle(psc->mem);
22968e8e04eSSam Leffler 	sc->sc_invalid = 1;
2309c6307b1SDamien Bergamini 
23197db2528SMarius Strobl 	rid = 0;
23297db2528SMarius Strobl 	if (ral_msi_disable == 0) {
23397db2528SMarius Strobl 		count = 1;
23497db2528SMarius Strobl 		if (pci_alloc_msi(dev, &count) == 0)
23597db2528SMarius Strobl 			rid = 1;
23697db2528SMarius Strobl 	}
23797db2528SMarius Strobl 	psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
23897db2528SMarius Strobl 	    (rid != 0 ? 0 : RF_SHAREABLE));
2399c6307b1SDamien Bergamini 	if (psc->irq == NULL) {
2409c6307b1SDamien Bergamini 		device_printf(dev, "could not allocate interrupt resource\n");
24197db2528SMarius Strobl 		pci_release_msi(dev);
24297db2528SMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
24397db2528SMarius Strobl 		    rman_get_rid(psc->mem), psc->mem);
2449c6307b1SDamien Bergamini 		return ENXIO;
2459c6307b1SDamien Bergamini 	}
2469c6307b1SDamien Bergamini 
2479c6307b1SDamien Bergamini 	error = (*psc->sc_opns->attach)(dev, pci_get_device(dev));
24897db2528SMarius Strobl 	if (error != 0) {
24997db2528SMarius Strobl 		(void)ral_pci_detach(dev);
250ceaec73dSDamien Bergamini 		return error;
25197db2528SMarius Strobl 	}
252ceaec73dSDamien Bergamini 
2539c6307b1SDamien Bergamini 	/*
2549c6307b1SDamien Bergamini 	 * Hook our interrupt after all initialization is complete.
2559c6307b1SDamien Bergamini 	 */
2569c6307b1SDamien Bergamini 	error = bus_setup_intr(dev, psc->irq, INTR_TYPE_NET | INTR_MPSAFE,
257ef544f63SPaolo Pisati 	    NULL, psc->sc_opns->intr, psc, &psc->sc_ih);
2589c6307b1SDamien Bergamini 	if (error != 0) {
2599c6307b1SDamien Bergamini 		device_printf(dev, "could not set up interrupt\n");
26097db2528SMarius Strobl 		(void)ral_pci_detach(dev);
261ceaec73dSDamien Bergamini 		return error;
262ceaec73dSDamien Bergamini 	}
26368e8e04eSSam Leffler 	sc->sc_invalid = 0;
264ceaec73dSDamien Bergamini 
2659c6307b1SDamien Bergamini 	return 0;
2669c6307b1SDamien Bergamini }
2679c6307b1SDamien Bergamini 
2689c6307b1SDamien Bergamini static int
ral_pci_detach(device_t dev)2699c6307b1SDamien Bergamini ral_pci_detach(device_t dev)
2709c6307b1SDamien Bergamini {
2719c6307b1SDamien Bergamini 	struct ral_pci_softc *psc = device_get_softc(dev);
27268e8e04eSSam Leffler 	struct rt2560_softc *sc = &psc->u.sc_rt2560;
27368e8e04eSSam Leffler 
27468e8e04eSSam Leffler 	/* check if device was removed */
27568e8e04eSSam Leffler 	sc->sc_invalid = !bus_child_present(dev);
2769c6307b1SDamien Bergamini 
27797db2528SMarius Strobl 	if (psc->sc_ih != NULL)
27897db2528SMarius Strobl 		bus_teardown_intr(dev, psc->irq, psc->sc_ih);
2799c6307b1SDamien Bergamini 	(*psc->sc_opns->detach)(psc);
2809c6307b1SDamien Bergamini 
2819c6307b1SDamien Bergamini 	bus_generic_detach(dev);
28297db2528SMarius Strobl 	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(psc->irq),
28397db2528SMarius Strobl 	    psc->irq);
28497db2528SMarius Strobl 	pci_release_msi(dev);
2859c6307b1SDamien Bergamini 
28697db2528SMarius Strobl 	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(psc->mem),
28797db2528SMarius Strobl 	    psc->mem);
2889c6307b1SDamien Bergamini 
2899c6307b1SDamien Bergamini 	return 0;
2909c6307b1SDamien Bergamini }
2919c6307b1SDamien Bergamini 
2929c6307b1SDamien Bergamini static int
ral_pci_shutdown(device_t dev)2939c6307b1SDamien Bergamini ral_pci_shutdown(device_t dev)
2949c6307b1SDamien Bergamini {
2959c6307b1SDamien Bergamini 	struct ral_pci_softc *psc = device_get_softc(dev);
2969c6307b1SDamien Bergamini 
2979c6307b1SDamien Bergamini 	(*psc->sc_opns->shutdown)(psc);
2989c6307b1SDamien Bergamini 
2999c6307b1SDamien Bergamini 	return 0;
3009c6307b1SDamien Bergamini }
3019c6307b1SDamien Bergamini 
302ceaec73dSDamien Bergamini static int
ral_pci_suspend(device_t dev)303ceaec73dSDamien Bergamini ral_pci_suspend(device_t dev)
304ceaec73dSDamien Bergamini {
3059c6307b1SDamien Bergamini 	struct ral_pci_softc *psc = device_get_softc(dev);
306ceaec73dSDamien Bergamini 
3079c6307b1SDamien Bergamini 	(*psc->sc_opns->suspend)(psc);
308ceaec73dSDamien Bergamini 
309ceaec73dSDamien Bergamini 	return 0;
310ceaec73dSDamien Bergamini }
311ceaec73dSDamien Bergamini 
312ceaec73dSDamien Bergamini static int
ral_pci_resume(device_t dev)313ceaec73dSDamien Bergamini ral_pci_resume(device_t dev)
314ceaec73dSDamien Bergamini {
3159c6307b1SDamien Bergamini 	struct ral_pci_softc *psc = device_get_softc(dev);
316ceaec73dSDamien Bergamini 
3179c6307b1SDamien Bergamini 	(*psc->sc_opns->resume)(psc);
318ceaec73dSDamien Bergamini 
319ceaec73dSDamien Bergamini 	return 0;
320ceaec73dSDamien Bergamini }
321