if_wi_pci.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) 1997, 1998, 1999
5 *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Bill Paul.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * $FreeBSD: stable/11/sys/dev/wi/if_wi_pci.c 330897 2018-03-14 03:19:51Z eadler $
35 */
36
37/*
38 * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD.
39 *
40 * Written by Bill Paul <wpaul@ctr.columbia.edu>
41 * Electrical Engineering Department
42 * Columbia University, New York City
43 */
44
45#include <sys/param.h>
46#include <sys/kernel.h>
47#include <sys/malloc.h>
48#include <sys/socket.h>
49#include <sys/systm.h>
50#include <sys/module.h>
51#include <sys/bus.h>
52
53#include <machine/bus.h>
54#include <machine/resource.h>
55#include <sys/rman.h>
56
57#include <dev/pci/pcireg.h>
58#include <dev/pci/pcivar.h>
59
60#include <net/if.h>
61#include <net/if_var.h>
62#include <net/if_arp.h>
63#include <net/ethernet.h>
64#include <net/if_media.h>
65#include <net/if_types.h>
66
67#include <net80211/ieee80211_var.h>
68#include <net80211/ieee80211_radiotap.h>
69
70#include <dev/wi/if_wavelan_ieee.h>
71#include <dev/wi/if_wireg.h>
72#include <dev/wi/if_wivar.h>
73
74static int wi_pci_probe(device_t);
75static int wi_pci_attach(device_t);
76static int wi_pci_suspend(device_t);
77static int wi_pci_resume(device_t);
78
79static device_method_t wi_pci_methods[] = {
80	/* Device interface */
81	DEVMETHOD(device_probe,		wi_pci_probe),
82	DEVMETHOD(device_attach,	wi_pci_attach),
83	DEVMETHOD(device_detach,	wi_detach),
84	DEVMETHOD(device_shutdown,	wi_shutdown),
85	DEVMETHOD(device_suspend,	wi_pci_suspend),
86	DEVMETHOD(device_resume,	wi_pci_resume),
87
88	{ 0, 0 }
89};
90
91static driver_t wi_pci_driver = {
92	"wi",
93	wi_pci_methods,
94	sizeof(struct wi_softc)
95};
96
97static struct {
98	unsigned int vendor,device;
99	int bus_type;
100	char *desc;
101} pci_ids[] = {
102	/* Sorted by description */
103	{0x10b7, 0x7770, WI_BUS_PCI_PLX, "3Com Airconnect"},
104	{0x16ab, 0x1101, WI_BUS_PCI_PLX, "GLPRISM2 WaveLAN"},
105	{0x1260, 0x3872, WI_BUS_PCI_NATIVE, "Intersil Prism3"},
106	{0x1260, 0x3873, WI_BUS_PCI_NATIVE, "Intersil Prism2.5"},
107	{0x16ab, 0x1102, WI_BUS_PCI_PLX, "Linksys WDT11"},
108	{0x1385, 0x4100, WI_BUS_PCI_PLX, "Netgear MA301"},
109	{0x1638, 0x1100, WI_BUS_PCI_PLX, "PRISM2STA WaveLAN"},
110	{0x111a, 0x1023, WI_BUS_PCI_PLX, "Siemens SpeedStream"},
111	{0x10b5, 0x9050, WI_BUS_PCI_PLX, "SMC 2602W"},
112	{0x16ec, 0x3685, WI_BUS_PCI_PLX, "US Robotics 2415"},
113	{0x4033, 0x7001, WI_BUS_PCI_PLX, "Addtron AWA-100 PCI"},
114	{0, 0, 0, NULL}
115};
116
117DRIVER_MODULE(wi, pci, wi_pci_driver, wi_devclass, 0, 0);
118MODULE_DEPEND(wi, pci, 1, 1, 1);
119MODULE_DEPEND(wi, wlan, 1, 1, 1);
120
121static int
122wi_pci_probe(dev)
123	device_t	dev;
124{
125	struct wi_softc		*sc;
126	int i;
127
128	sc = device_get_softc(dev);
129	for(i=0; pci_ids[i].vendor != 0; i++) {
130		if ((pci_get_vendor(dev) == pci_ids[i].vendor) &&
131			(pci_get_device(dev) == pci_ids[i].device)) {
132			sc->wi_bus_type = pci_ids[i].bus_type;
133			device_set_desc(dev, pci_ids[i].desc);
134			return (BUS_PROBE_DEFAULT);
135		}
136	}
137	return(ENXIO);
138}
139
140static int
141wi_pci_attach(device_t dev)
142{
143	struct wi_softc		*sc;
144	u_int32_t		command;
145	u_int16_t		reg;
146	int			error;
147	int			timeout;
148
149	sc = device_get_softc(dev);
150
151	if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) {
152		error = wi_alloc(dev, WI_PCI_IORES);
153		if (error)
154			return (error);
155
156		/* Make sure interrupts are disabled. */
157		CSR_WRITE_2(sc, WI_INT_EN, 0);
158		CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
159
160		/* We have to do a magic PLX poke to enable interrupts */
161		sc->local_rid = WI_PCI_LOCALRES;
162		sc->local = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
163		    &sc->local_rid, RF_ACTIVE);
164		sc->wi_localtag = rman_get_bustag(sc->local);
165		sc->wi_localhandle = rman_get_bushandle(sc->local);
166		command = bus_space_read_4(sc->wi_localtag, sc->wi_localhandle,
167		    WI_LOCAL_INTCSR);
168		command |= WI_LOCAL_INTEN;
169		bus_space_write_4(sc->wi_localtag, sc->wi_localhandle,
170		    WI_LOCAL_INTCSR, command);
171		bus_release_resource(dev, SYS_RES_IOPORT, sc->local_rid,
172		    sc->local);
173		sc->local = NULL;
174
175		sc->mem_rid = WI_PCI_MEMRES;
176		sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
177					&sc->mem_rid, RF_ACTIVE);
178		if (sc->mem == NULL) {
179			device_printf(dev, "couldn't allocate memory\n");
180			wi_free(dev);
181			return (ENXIO);
182		}
183		sc->wi_bmemtag = rman_get_bustag(sc->mem);
184		sc->wi_bmemhandle = rman_get_bushandle(sc->mem);
185
186		/*
187		 * Write COR to enable PC card
188		 * This is a subset of the protocol that the pccard bus code
189		 * would do.  In theory, we should parse the CIS to find the
190		 * COR offset.  In practice, the COR_OFFSET is always 0x3e0.
191		 */
192		CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE);
193		reg = CSM_READ_1(sc, WI_COR_OFFSET);
194		if (reg != WI_COR_VALUE) {
195			device_printf(dev, "CSM_READ_1(WI_COR_OFFSET) "
196			    "wanted %d, got %d\n", WI_COR_VALUE, reg);
197			wi_free(dev);
198			return (ENXIO);
199		}
200	} else {
201		error = wi_alloc(dev, WI_PCI_LMEMRES);
202		if (error)
203			return (error);
204
205		CSR_WRITE_2(sc, WI_PCICOR_OFF, WI_PCICOR_RESET);
206		DELAY(250000);
207
208		CSR_WRITE_2(sc, WI_PCICOR_OFF, 0x0000);
209		DELAY(500000);
210
211		timeout=2000000;
212		while ((--timeout > 0) &&
213		    (CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
214			DELAY(10);
215
216		if (timeout == 0) {
217			device_printf(dev, "couldn't reset prism pci core.\n");
218			wi_free(dev);
219			return(ENXIO);
220		}
221	}
222
223	CSR_WRITE_2(sc, WI_HFA384X_SWSUPPORT0_OFF, WI_PRISM2STA_MAGIC);
224	reg = CSR_READ_2(sc, WI_HFA384X_SWSUPPORT0_OFF);
225	if (reg != WI_PRISM2STA_MAGIC) {
226		device_printf(dev,
227		    "CSR_READ_2(WI_HFA384X_SWSUPPORT0_OFF) "
228		    "wanted %d, got %d\n", WI_PRISM2STA_MAGIC, reg);
229		wi_free(dev);
230		return (ENXIO);
231	}
232
233	error = wi_attach(dev);
234	if (error != 0)
235		wi_free(dev);
236	return (error);
237}
238
239static int
240wi_pci_suspend(device_t dev)
241{
242	struct wi_softc	*sc = device_get_softc(dev);
243
244	WI_LOCK(sc);
245	wi_stop(sc, 1);
246	WI_UNLOCK(sc);
247
248	return (0);
249}
250
251static int
252wi_pci_resume(device_t dev)
253{
254	struct wi_softc	*sc = device_get_softc(dev);
255	struct ieee80211com *ic = &sc->sc_ic;
256
257	WI_LOCK(sc);
258	if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) {
259		WI_UNLOCK(sc);
260		return (0);
261	}
262	if (ic->ic_nrunning > 0)
263		wi_init(sc);
264	WI_UNLOCK(sc);
265	return (0);
266}
267