1145247Sdamien/*	$FreeBSD$	*/
2145247Sdamien
3145247Sdamien/*-
4156321Sdamien * Copyright (c) 2005, 2006
5145247Sdamien *	Damien Bergamini <damien.bergamini@free.fr>
6145247Sdamien *
7145247Sdamien * Permission to use, copy, modify, and distribute this software for any
8145247Sdamien * purpose with or without fee is hereby granted, provided that the above
9145247Sdamien * copyright notice and this permission notice appear in all copies.
10145247Sdamien *
11145247Sdamien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12145247Sdamien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13145247Sdamien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14145247Sdamien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15145247Sdamien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16145247Sdamien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17145247Sdamien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18145247Sdamien */
19145247Sdamien
20145247Sdamien#include <sys/cdefs.h>
21145247Sdamien__FBSDID("$FreeBSD$");
22145247Sdamien
23145247Sdamien/*
24156321Sdamien * PCI/Cardbus front-end for the Ralink RT2560/RT2561/RT2561S/RT2661 driver.
25145247Sdamien */
26145247Sdamien
27145247Sdamien#include <sys/param.h>
28145247Sdamien#include <sys/sysctl.h>
29145247Sdamien#include <sys/sockio.h>
30145247Sdamien#include <sys/mbuf.h>
31145247Sdamien#include <sys/kernel.h>
32145247Sdamien#include <sys/socket.h>
33145247Sdamien#include <sys/systm.h>
34145247Sdamien#include <sys/malloc.h>
35145247Sdamien#include <sys/module.h>
36145247Sdamien#include <sys/bus.h>
37145247Sdamien#include <sys/endian.h>
38145247Sdamien
39145247Sdamien#include <machine/bus.h>
40145247Sdamien#include <machine/resource.h>
41145247Sdamien#include <sys/rman.h>
42145247Sdamien
43145247Sdamien#include <net/bpf.h>
44145247Sdamien#include <net/if.h>
45145247Sdamien#include <net/if_arp.h>
46145247Sdamien#include <net/ethernet.h>
47145247Sdamien#include <net/if_dl.h>
48145247Sdamien#include <net/if_media.h>
49145247Sdamien#include <net/if_types.h>
50145247Sdamien
51145247Sdamien#include <net80211/ieee80211_var.h>
52145247Sdamien#include <net80211/ieee80211_radiotap.h>
53178354Ssam#include <net80211/ieee80211_amrr.h>
54145247Sdamien
55145247Sdamien#include <dev/pci/pcireg.h>
56145247Sdamien#include <dev/pci/pcivar.h>
57145247Sdamien
58156327Ssilby#include <dev/ral/rt2560var.h>
59156327Ssilby#include <dev/ral/rt2661var.h>
60235233Sbschmidt#include <dev/ral/rt2860var.h>
61145247Sdamien
62145247SdamienMODULE_DEPEND(ral, pci, 1, 1, 1);
63178354SsamMODULE_DEPEND(ral, firmware, 1, 1, 1);
64145247SdamienMODULE_DEPEND(ral, wlan, 1, 1, 1);
65178354SsamMODULE_DEPEND(ral, wlan_amrr, 1, 1, 1);
66145247Sdamien
67145247Sdamienstruct ral_pci_ident {
68145247Sdamien	uint16_t	vendor;
69145247Sdamien	uint16_t	device;
70145247Sdamien	const char	*name;
71145247Sdamien};
72145247Sdamien
73145247Sdamienstatic const struct ral_pci_ident ral_pci_ids[] = {
74235233Sbschmidt	{ 0x1432, 0x7708, "Edimax RT2860" },
75235233Sbschmidt	{ 0x1432, 0x7711, "Edimax RT3591" },
76235233Sbschmidt	{ 0x1432, 0x7722, "Edimax RT3591" },
77235233Sbschmidt	{ 0x1432, 0x7727, "Edimax RT2860" },
78235233Sbschmidt	{ 0x1432, 0x7728, "Edimax RT2860" },
79235233Sbschmidt	{ 0x1432, 0x7738, "Edimax RT2860" },
80235233Sbschmidt	{ 0x1432, 0x7748, "Edimax RT2860" },
81235233Sbschmidt	{ 0x1432, 0x7758, "Edimax RT2860" },
82235233Sbschmidt	{ 0x1432, 0x7768, "Edimax RT2860" },
83235233Sbschmidt	{ 0x1462, 0x891a, "MSI RT3090" },
84156321Sdamien	{ 0x1814, 0x0201, "Ralink Technology RT2560" },
85156321Sdamien	{ 0x1814, 0x0301, "Ralink Technology RT2561S" },
86156321Sdamien	{ 0x1814, 0x0302, "Ralink Technology RT2561" },
87156321Sdamien	{ 0x1814, 0x0401, "Ralink Technology RT2661" },
88235233Sbschmidt	{ 0x1814, 0x0601, "Ralink Technology RT2860" },
89235233Sbschmidt	{ 0x1814, 0x0681, "Ralink Technology RT2890" },
90235233Sbschmidt	{ 0x1814, 0x0701, "Ralink Technology RT2760" },
91235233Sbschmidt	{ 0x1814, 0x0781, "Ralink Technology RT2790" },
92235233Sbschmidt	{ 0x1814, 0x3060, "Ralink Technology RT3060" },
93235233Sbschmidt	{ 0x1814, 0x3062, "Ralink Technology RT3062" },
94235233Sbschmidt	{ 0x1814, 0x3090, "Ralink Technology RT3090" },
95235233Sbschmidt	{ 0x1814, 0x3091, "Ralink Technology RT3091" },
96235233Sbschmidt	{ 0x1814, 0x3092, "Ralink Technology RT3092" },
97235233Sbschmidt	{ 0x1814, 0x3390, "Ralink Technology RT3390" },
98235233Sbschmidt	{ 0x1814, 0x3562, "Ralink Technology RT3562" },
99235233Sbschmidt	{ 0x1814, 0x3592, "Ralink Technology RT3592" },
100235233Sbschmidt	{ 0x1814, 0x3593, "Ralink Technology RT3593" },
101235233Sbschmidt	{ 0x1814, 0x5390, "Ralink Technology RT5390" },
102235233Sbschmidt	{ 0x1814, 0x539a, "Ralink Technology RT5390" },
103235233Sbschmidt	{ 0x1814, 0x539f, "Ralink Technology RT5390" },
104235233Sbschmidt	{ 0x1a3b, 0x1059, "AWT RT2890" },
105145247Sdamien	{ 0, 0, NULL }
106145247Sdamien};
107145247Sdamien
108156321Sdamienstatic struct ral_opns {
109156321Sdamien	int	(*attach)(device_t, int);
110156321Sdamien	int	(*detach)(void *);
111156321Sdamien	void	(*shutdown)(void *);
112156321Sdamien	void	(*suspend)(void *);
113156321Sdamien	void	(*resume)(void *);
114156321Sdamien	void	(*intr)(void *);
115156321Sdamien
116156321Sdamien}  ral_rt2560_opns = {
117156321Sdamien	rt2560_attach,
118156321Sdamien	rt2560_detach,
119170530Ssam	rt2560_stop,
120170530Ssam	rt2560_stop,
121156321Sdamien	rt2560_resume,
122156321Sdamien	rt2560_intr
123156321Sdamien
124156321Sdamien}, ral_rt2661_opns = {
125156321Sdamien	rt2661_attach,
126156321Sdamien	rt2661_detach,
127156321Sdamien	rt2661_shutdown,
128156321Sdamien	rt2661_suspend,
129156321Sdamien	rt2661_resume,
130156321Sdamien	rt2661_intr
131235233Sbschmidt}, ral_rt2860_opns = {
132235233Sbschmidt	rt2860_attach,
133235233Sbschmidt	rt2860_detach,
134235233Sbschmidt	rt2860_shutdown,
135235233Sbschmidt	rt2860_suspend,
136235233Sbschmidt	rt2860_resume,
137235233Sbschmidt	rt2860_intr
138156321Sdamien};
139156321Sdamien
140156321Sdamienstruct ral_pci_softc {
141156321Sdamien	union {
142156321Sdamien		struct rt2560_softc sc_rt2560;
143156321Sdamien		struct rt2661_softc sc_rt2661;
144235233Sbschmidt		struct rt2860_softc sc_rt2860;
145156321Sdamien	} u;
146156321Sdamien
147156321Sdamien	struct ral_opns		*sc_opns;
148156321Sdamien	int			irq_rid;
149156321Sdamien	int			mem_rid;
150156321Sdamien	struct resource		*irq;
151156321Sdamien	struct resource		*mem;
152156321Sdamien	void			*sc_ih;
153156321Sdamien};
154156321Sdamien
155145247Sdamienstatic int ral_pci_probe(device_t);
156145247Sdamienstatic int ral_pci_attach(device_t);
157156321Sdamienstatic int ral_pci_detach(device_t);
158156321Sdamienstatic int ral_pci_shutdown(device_t);
159145247Sdamienstatic int ral_pci_suspend(device_t);
160145247Sdamienstatic int ral_pci_resume(device_t);
161145247Sdamien
162145247Sdamienstatic device_method_t ral_pci_methods[] = {
163145247Sdamien	/* Device interface */
164145247Sdamien	DEVMETHOD(device_probe,		ral_pci_probe),
165145247Sdamien	DEVMETHOD(device_attach,	ral_pci_attach),
166156321Sdamien	DEVMETHOD(device_detach,	ral_pci_detach),
167156321Sdamien	DEVMETHOD(device_shutdown,	ral_pci_shutdown),
168145247Sdamien	DEVMETHOD(device_suspend,	ral_pci_suspend),
169145247Sdamien	DEVMETHOD(device_resume,	ral_pci_resume),
170145247Sdamien
171145247Sdamien	{ 0, 0 }
172145247Sdamien};
173145247Sdamien
174145247Sdamienstatic driver_t ral_pci_driver = {
175145247Sdamien	"ral",
176145247Sdamien	ral_pci_methods,
177156321Sdamien	sizeof (struct ral_pci_softc)
178145247Sdamien};
179145247Sdamien
180156321Sdamienstatic devclass_t ral_devclass;
181156321Sdamien
182145247SdamienDRIVER_MODULE(ral, pci, ral_pci_driver, ral_devclass, 0, 0);
183145247Sdamien
184145247Sdamienstatic int
185145247Sdamienral_pci_probe(device_t dev)
186145247Sdamien{
187145247Sdamien	const struct ral_pci_ident *ident;
188145247Sdamien
189145247Sdamien	for (ident = ral_pci_ids; ident->name != NULL; ident++) {
190145247Sdamien		if (pci_get_vendor(dev) == ident->vendor &&
191145247Sdamien		    pci_get_device(dev) == ident->device) {
192145247Sdamien			device_set_desc(dev, ident->name);
193145247Sdamien			return 0;
194145247Sdamien		}
195145247Sdamien	}
196145247Sdamien	return ENXIO;
197145247Sdamien}
198145247Sdamien
199145247Sdamien/* Base Address Register */
200145247Sdamien#define RAL_PCI_BAR0	0x10
201145247Sdamien
202145247Sdamienstatic int
203145247Sdamienral_pci_attach(device_t dev)
204145247Sdamien{
205156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
206156321Sdamien	struct rt2560_softc *sc = &psc->u.sc_rt2560;
207145247Sdamien	int error;
208145247Sdamien
209145247Sdamien	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
210145247Sdamien		device_printf(dev, "chip is in D%d power mode "
211145247Sdamien		    "-- setting to D0\n", pci_get_powerstate(dev));
212145247Sdamien		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
213145247Sdamien	}
214145247Sdamien
215145247Sdamien	/* enable bus-mastering */
216145247Sdamien	pci_enable_busmaster(dev);
217145247Sdamien
218235233Sbschmidt	switch (pci_get_device(dev)) {
219235233Sbschmidt	case 0x0201:
220235233Sbschmidt		psc->sc_opns = &ral_rt2560_opns;
221235233Sbschmidt		break;
222235233Sbschmidt	case 0x0301:
223235233Sbschmidt	case 0x0302:
224235233Sbschmidt	case 0x0401:
225235233Sbschmidt		psc->sc_opns = &ral_rt2661_opns;
226235233Sbschmidt		break;
227235233Sbschmidt	default:
228235233Sbschmidt		psc->sc_opns = &ral_rt2860_opns;
229235233Sbschmidt		break;
230235233Sbschmidt	}
231156321Sdamien
232156321Sdamien	psc->mem_rid = RAL_PCI_BAR0;
233156321Sdamien	psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &psc->mem_rid,
234156321Sdamien	    RF_ACTIVE);
235156321Sdamien	if (psc->mem == NULL) {
236156321Sdamien		device_printf(dev, "could not allocate memory resource\n");
237156321Sdamien		return ENXIO;
238156321Sdamien	}
239156321Sdamien
240156321Sdamien	sc->sc_st = rman_get_bustag(psc->mem);
241156321Sdamien	sc->sc_sh = rman_get_bushandle(psc->mem);
242170530Ssam	sc->sc_invalid = 1;
243170530Ssam
244156321Sdamien	psc->irq_rid = 0;
245156321Sdamien	psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &psc->irq_rid,
246156321Sdamien	    RF_ACTIVE | RF_SHAREABLE);
247156321Sdamien	if (psc->irq == NULL) {
248156321Sdamien		device_printf(dev, "could not allocate interrupt resource\n");
249156321Sdamien		return ENXIO;
250156321Sdamien	}
251156321Sdamien
252156321Sdamien	error = (*psc->sc_opns->attach)(dev, pci_get_device(dev));
253145247Sdamien	if (error != 0)
254145247Sdamien		return error;
255145247Sdamien
256156321Sdamien	/*
257156321Sdamien	 * Hook our interrupt after all initialization is complete.
258156321Sdamien	 */
259156321Sdamien	error = bus_setup_intr(dev, psc->irq, INTR_TYPE_NET | INTR_MPSAFE,
260166901Spiso	    NULL, psc->sc_opns->intr, psc, &psc->sc_ih);
261156321Sdamien	if (error != 0) {
262156321Sdamien		device_printf(dev, "could not set up interrupt\n");
263156321Sdamien		return error;
264156321Sdamien	}
265170530Ssam	sc->sc_invalid = 0;
266170530Ssam
267156321Sdamien	return 0;
268145247Sdamien}
269145247Sdamien
270145247Sdamienstatic int
271156321Sdamienral_pci_detach(device_t dev)
272156321Sdamien{
273156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
274170530Ssam	struct rt2560_softc *sc = &psc->u.sc_rt2560;
275170530Ssam
276170530Ssam	/* check if device was removed */
277170530Ssam	sc->sc_invalid = !bus_child_present(dev);
278170530Ssam
279156321Sdamien	(*psc->sc_opns->detach)(psc);
280156321Sdamien
281156321Sdamien	bus_generic_detach(dev);
282156321Sdamien	bus_teardown_intr(dev, psc->irq, psc->sc_ih);
283156321Sdamien	bus_release_resource(dev, SYS_RES_IRQ, psc->irq_rid, psc->irq);
284156321Sdamien
285156321Sdamien	bus_release_resource(dev, SYS_RES_MEMORY, psc->mem_rid, psc->mem);
286156321Sdamien
287156321Sdamien	return 0;
288156321Sdamien}
289156321Sdamien
290156321Sdamienstatic int
291156321Sdamienral_pci_shutdown(device_t dev)
292156321Sdamien{
293156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
294156321Sdamien
295156321Sdamien	(*psc->sc_opns->shutdown)(psc);
296156321Sdamien
297156321Sdamien	return 0;
298156321Sdamien}
299156321Sdamien
300156321Sdamienstatic int
301145247Sdamienral_pci_suspend(device_t dev)
302145247Sdamien{
303156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
304145247Sdamien
305156321Sdamien	(*psc->sc_opns->suspend)(psc);
306145247Sdamien
307145247Sdamien	return 0;
308145247Sdamien}
309145247Sdamien
310145247Sdamienstatic int
311145247Sdamienral_pci_resume(device_t dev)
312145247Sdamien{
313156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
314145247Sdamien
315156321Sdamien	(*psc->sc_opns->resume)(psc);
316145247Sdamien
317145247Sdamien	return 0;
318145247Sdamien}
319