1145247Sdamien/*-
2156321Sdamien * Copyright (c) 2005, 2006
3145247Sdamien *	Damien Bergamini <damien.bergamini@free.fr>
4145247Sdamien *
5145247Sdamien * Permission to use, copy, modify, and distribute this software for any
6145247Sdamien * purpose with or without fee is hereby granted, provided that the above
7145247Sdamien * copyright notice and this permission notice appear in all copies.
8145247Sdamien *
9145247Sdamien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10145247Sdamien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11145247Sdamien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12145247Sdamien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13145247Sdamien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14145247Sdamien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15145247Sdamien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16145247Sdamien */
17145247Sdamien
18145247Sdamien#include <sys/cdefs.h>
19145247Sdamien__FBSDID("$FreeBSD: stable/11/sys/dev/ral/if_ral_pci.c 352563 2019-09-20 19:56:55Z mizhka $");
20145247Sdamien
21145247Sdamien/*
22156321Sdamien * PCI/Cardbus front-end for the Ralink RT2560/RT2561/RT2561S/RT2661 driver.
23145247Sdamien */
24145247Sdamien
25145247Sdamien#include <sys/param.h>
26260061Smarius#include <sys/systm.h>
27260061Smarius#include <sys/bus.h>
28145247Sdamien#include <sys/kernel.h>
29260061Smarius#include <sys/lock.h>
30145247Sdamien#include <sys/malloc.h>
31287197Sglebius#include <sys/mbuf.h>
32145247Sdamien#include <sys/module.h>
33260061Smarius#include <sys/mutex.h>
34260061Smarius#include <sys/rman.h>
35260061Smarius#include <sys/socket.h>
36145247Sdamien
37145247Sdamien#include <machine/bus.h>
38145247Sdamien#include <machine/resource.h>
39145247Sdamien
40260061Smarius#include <net/ethernet.h>
41145247Sdamien#include <net/if.h>
42145247Sdamien#include <net/if_media.h>
43260061Smarius#include <net/route.h>
44145247Sdamien
45145247Sdamien#include <net80211/ieee80211_var.h>
46145247Sdamien#include <net80211/ieee80211_radiotap.h>
47145247Sdamien
48145247Sdamien#include <dev/pci/pcireg.h>
49145247Sdamien#include <dev/pci/pcivar.h>
50145247Sdamien
51156327Ssilby#include <dev/ral/rt2560var.h>
52156327Ssilby#include <dev/ral/rt2661var.h>
53235233Sbschmidt#include <dev/ral/rt2860var.h>
54145247Sdamien
55145247SdamienMODULE_DEPEND(ral, pci, 1, 1, 1);
56178354SsamMODULE_DEPEND(ral, firmware, 1, 1, 1);
57145247SdamienMODULE_DEPEND(ral, wlan, 1, 1, 1);
58178354SsamMODULE_DEPEND(ral, wlan_amrr, 1, 1, 1);
59145247Sdamien
60260061Smariusstatic int ral_msi_disable;
61260061SmariusTUNABLE_INT("hw.ral.msi_disable", &ral_msi_disable);
62260061Smarius
63145247Sdamienstruct ral_pci_ident {
64145247Sdamien	uint16_t	vendor;
65145247Sdamien	uint16_t	device;
66145247Sdamien	const char	*name;
67145247Sdamien};
68145247Sdamien
69145247Sdamienstatic const struct ral_pci_ident ral_pci_ids[] = {
70235233Sbschmidt	{ 0x1432, 0x7708, "Edimax RT2860" },
71235233Sbschmidt	{ 0x1432, 0x7711, "Edimax RT3591" },
72235233Sbschmidt	{ 0x1432, 0x7722, "Edimax RT3591" },
73235233Sbschmidt	{ 0x1432, 0x7727, "Edimax RT2860" },
74235233Sbschmidt	{ 0x1432, 0x7728, "Edimax RT2860" },
75235233Sbschmidt	{ 0x1432, 0x7738, "Edimax RT2860" },
76235233Sbschmidt	{ 0x1432, 0x7748, "Edimax RT2860" },
77235233Sbschmidt	{ 0x1432, 0x7758, "Edimax RT2860" },
78235233Sbschmidt	{ 0x1432, 0x7768, "Edimax RT2860" },
79235233Sbschmidt	{ 0x1462, 0x891a, "MSI RT3090" },
80156321Sdamien	{ 0x1814, 0x0201, "Ralink Technology RT2560" },
81156321Sdamien	{ 0x1814, 0x0301, "Ralink Technology RT2561S" },
82156321Sdamien	{ 0x1814, 0x0302, "Ralink Technology RT2561" },
83156321Sdamien	{ 0x1814, 0x0401, "Ralink Technology RT2661" },
84235233Sbschmidt	{ 0x1814, 0x0601, "Ralink Technology RT2860" },
85235233Sbschmidt	{ 0x1814, 0x0681, "Ralink Technology RT2890" },
86235233Sbschmidt	{ 0x1814, 0x0701, "Ralink Technology RT2760" },
87235233Sbschmidt	{ 0x1814, 0x0781, "Ralink Technology RT2790" },
88235233Sbschmidt	{ 0x1814, 0x3060, "Ralink Technology RT3060" },
89235233Sbschmidt	{ 0x1814, 0x3062, "Ralink Technology RT3062" },
90235233Sbschmidt	{ 0x1814, 0x3090, "Ralink Technology RT3090" },
91235233Sbschmidt	{ 0x1814, 0x3091, "Ralink Technology RT3091" },
92235233Sbschmidt	{ 0x1814, 0x3092, "Ralink Technology RT3092" },
93235233Sbschmidt	{ 0x1814, 0x3390, "Ralink Technology RT3390" },
94235233Sbschmidt	{ 0x1814, 0x3562, "Ralink Technology RT3562" },
95235233Sbschmidt	{ 0x1814, 0x3592, "Ralink Technology RT3592" },
96235233Sbschmidt	{ 0x1814, 0x3593, "Ralink Technology RT3593" },
97278551Skevlo	{ 0x1814, 0x5360, "Ralink Technology RT5390" },
98278551Skevlo	{ 0x1814, 0x5362, "Ralink Technology RT5392" },
99235233Sbschmidt	{ 0x1814, 0x5390, "Ralink Technology RT5390" },
100278551Skevlo	{ 0x1814, 0x5392, "Ralink Technology RT5392" },
101235233Sbschmidt	{ 0x1814, 0x539a, "Ralink Technology RT5390" },
102352563Smizhka	{ 0x1814, 0x539b, "Ralink Technology RT5390" },
103235233Sbschmidt	{ 0x1814, 0x539f, "Ralink Technology RT5390" },
104235233Sbschmidt	{ 0x1a3b, 0x1059, "AWT RT2890" },
105145247Sdamien	{ 0, 0, NULL }
106145247Sdamien};
107145247Sdamien
108260061Smariusstatic const 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
147260061Smarius	const struct ral_opns	*sc_opns;
148156321Sdamien	struct resource		*irq;
149156321Sdamien	struct resource		*mem;
150156321Sdamien	void			*sc_ih;
151156321Sdamien};
152156321Sdamien
153145247Sdamienstatic int ral_pci_probe(device_t);
154145247Sdamienstatic int ral_pci_attach(device_t);
155156321Sdamienstatic int ral_pci_detach(device_t);
156156321Sdamienstatic int ral_pci_shutdown(device_t);
157145247Sdamienstatic int ral_pci_suspend(device_t);
158145247Sdamienstatic int ral_pci_resume(device_t);
159145247Sdamien
160145247Sdamienstatic device_method_t ral_pci_methods[] = {
161145247Sdamien	/* Device interface */
162145247Sdamien	DEVMETHOD(device_probe,		ral_pci_probe),
163145247Sdamien	DEVMETHOD(device_attach,	ral_pci_attach),
164156321Sdamien	DEVMETHOD(device_detach,	ral_pci_detach),
165156321Sdamien	DEVMETHOD(device_shutdown,	ral_pci_shutdown),
166145247Sdamien	DEVMETHOD(device_suspend,	ral_pci_suspend),
167145247Sdamien	DEVMETHOD(device_resume,	ral_pci_resume),
168145247Sdamien
169260061Smarius	DEVMETHOD_END
170145247Sdamien};
171145247Sdamien
172145247Sdamienstatic driver_t ral_pci_driver = {
173145247Sdamien	"ral",
174145247Sdamien	ral_pci_methods,
175156321Sdamien	sizeof (struct ral_pci_softc)
176145247Sdamien};
177145247Sdamien
178156321Sdamienstatic devclass_t ral_devclass;
179156321Sdamien
180260061SmariusDRIVER_MODULE(ral, pci, ral_pci_driver, ral_devclass, NULL, NULL);
181145247Sdamien
182145247Sdamienstatic int
183145247Sdamienral_pci_probe(device_t dev)
184145247Sdamien{
185145247Sdamien	const struct ral_pci_ident *ident;
186145247Sdamien
187145247Sdamien	for (ident = ral_pci_ids; ident->name != NULL; ident++) {
188145247Sdamien		if (pci_get_vendor(dev) == ident->vendor &&
189145247Sdamien		    pci_get_device(dev) == ident->device) {
190145247Sdamien			device_set_desc(dev, ident->name);
191260061Smarius			return (BUS_PROBE_DEFAULT);
192145247Sdamien		}
193145247Sdamien	}
194145247Sdamien	return ENXIO;
195145247Sdamien}
196145247Sdamien
197145247Sdamienstatic int
198145247Sdamienral_pci_attach(device_t dev)
199145247Sdamien{
200156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
201156321Sdamien	struct rt2560_softc *sc = &psc->u.sc_rt2560;
202260061Smarius	int count, error, rid;
203145247Sdamien
204145247Sdamien	pci_enable_busmaster(dev);
205145247Sdamien
206235233Sbschmidt	switch (pci_get_device(dev)) {
207235233Sbschmidt	case 0x0201:
208235233Sbschmidt		psc->sc_opns = &ral_rt2560_opns;
209235233Sbschmidt		break;
210235233Sbschmidt	case 0x0301:
211235233Sbschmidt	case 0x0302:
212235233Sbschmidt	case 0x0401:
213235233Sbschmidt		psc->sc_opns = &ral_rt2661_opns;
214235233Sbschmidt		break;
215235233Sbschmidt	default:
216235233Sbschmidt		psc->sc_opns = &ral_rt2860_opns;
217235233Sbschmidt		break;
218235233Sbschmidt	}
219156321Sdamien
220260061Smarius	rid = PCIR_BAR(0);
221260061Smarius	psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
222156321Sdamien	    RF_ACTIVE);
223156321Sdamien	if (psc->mem == NULL) {
224156321Sdamien		device_printf(dev, "could not allocate memory resource\n");
225156321Sdamien		return ENXIO;
226156321Sdamien	}
227156321Sdamien
228156321Sdamien	sc->sc_st = rman_get_bustag(psc->mem);
229156321Sdamien	sc->sc_sh = rman_get_bushandle(psc->mem);
230170530Ssam	sc->sc_invalid = 1;
231170530Ssam
232260061Smarius	rid = 0;
233260061Smarius	if (ral_msi_disable == 0) {
234260061Smarius		count = 1;
235260061Smarius		if (pci_alloc_msi(dev, &count) == 0)
236260061Smarius			rid = 1;
237260061Smarius	}
238260061Smarius	psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
239260061Smarius	    (rid != 0 ? 0 : RF_SHAREABLE));
240156321Sdamien	if (psc->irq == NULL) {
241156321Sdamien		device_printf(dev, "could not allocate interrupt resource\n");
242260061Smarius		pci_release_msi(dev);
243260061Smarius		bus_release_resource(dev, SYS_RES_MEMORY,
244260061Smarius		    rman_get_rid(psc->mem), psc->mem);
245156321Sdamien		return ENXIO;
246156321Sdamien	}
247156321Sdamien
248156321Sdamien	error = (*psc->sc_opns->attach)(dev, pci_get_device(dev));
249260061Smarius	if (error != 0) {
250260061Smarius		(void)ral_pci_detach(dev);
251145247Sdamien		return error;
252260061Smarius	}
253145247Sdamien
254156321Sdamien	/*
255156321Sdamien	 * Hook our interrupt after all initialization is complete.
256156321Sdamien	 */
257156321Sdamien	error = bus_setup_intr(dev, psc->irq, INTR_TYPE_NET | INTR_MPSAFE,
258166901Spiso	    NULL, psc->sc_opns->intr, psc, &psc->sc_ih);
259156321Sdamien	if (error != 0) {
260156321Sdamien		device_printf(dev, "could not set up interrupt\n");
261260061Smarius		(void)ral_pci_detach(dev);
262156321Sdamien		return error;
263156321Sdamien	}
264170530Ssam	sc->sc_invalid = 0;
265170530Ssam
266156321Sdamien	return 0;
267145247Sdamien}
268145247Sdamien
269145247Sdamienstatic int
270156321Sdamienral_pci_detach(device_t dev)
271156321Sdamien{
272156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
273170530Ssam	struct rt2560_softc *sc = &psc->u.sc_rt2560;
274170530Ssam
275170530Ssam	/* check if device was removed */
276170530Ssam	sc->sc_invalid = !bus_child_present(dev);
277260061Smarius
278260061Smarius	if (psc->sc_ih != NULL)
279260061Smarius		bus_teardown_intr(dev, psc->irq, psc->sc_ih);
280156321Sdamien	(*psc->sc_opns->detach)(psc);
281156321Sdamien
282156321Sdamien	bus_generic_detach(dev);
283260061Smarius	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(psc->irq),
284260061Smarius	    psc->irq);
285260061Smarius	pci_release_msi(dev);
286156321Sdamien
287260061Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(psc->mem),
288260061Smarius	    psc->mem);
289156321Sdamien
290156321Sdamien	return 0;
291156321Sdamien}
292156321Sdamien
293156321Sdamienstatic int
294156321Sdamienral_pci_shutdown(device_t dev)
295156321Sdamien{
296156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
297156321Sdamien
298156321Sdamien	(*psc->sc_opns->shutdown)(psc);
299156321Sdamien
300156321Sdamien	return 0;
301156321Sdamien}
302156321Sdamien
303156321Sdamienstatic int
304145247Sdamienral_pci_suspend(device_t dev)
305145247Sdamien{
306156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
307145247Sdamien
308156321Sdamien	(*psc->sc_opns->suspend)(psc);
309145247Sdamien
310145247Sdamien	return 0;
311145247Sdamien}
312145247Sdamien
313145247Sdamienstatic int
314145247Sdamienral_pci_resume(device_t dev)
315145247Sdamien{
316156321Sdamien	struct ral_pci_softc *psc = device_get_softc(dev);
317145247Sdamien
318156321Sdamien	(*psc->sc_opns->resume)(psc);
319145247Sdamien
320145247Sdamien	return 0;
321145247Sdamien}
322