Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/if_ath_pci.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
5
* 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
* without modification.
13
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
14
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15
* redistribution must be conditioned upon including a substantially
16
* similar Disclaimer requirement for further binary redistribution.
17
*
18
* NO WARRANTY
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29
* THE POSSIBILITY OF SUCH DAMAGES.
30
*/
31
32
#include <sys/cdefs.h>
33
/*
34
* PCI/Cardbus front-end for the Atheros Wireless LAN controller driver.
35
*/
36
#include "opt_ath.h"
37
38
#include <sys/param.h>
39
#include <sys/systm.h>
40
#include <sys/malloc.h>
41
#include <sys/module.h>
42
#include <sys/kernel.h>
43
#include <sys/lock.h>
44
#include <sys/mutex.h>
45
#include <sys/errno.h>
46
47
#include <machine/bus.h>
48
#include <machine/resource.h>
49
#include <sys/bus.h>
50
#include <sys/rman.h>
51
52
#include <sys/socket.h>
53
54
#include <net/if.h>
55
#include <net/if_media.h>
56
#include <net/if_arp.h>
57
#include <net/ethernet.h>
58
59
#include <net80211/ieee80211_var.h>
60
61
#include <dev/ath/if_athvar.h>
62
63
#include <dev/pci/pcivar.h>
64
#include <dev/pci/pcireg.h>
65
66
/* For EEPROM firmware */
67
#ifdef ATH_EEPROM_FIRMWARE
68
#include <sys/linker.h>
69
#include <sys/firmware.h>
70
#endif /* ATH_EEPROM_FIRMWARE */
71
72
/*
73
* PCI glue.
74
*/
75
76
struct ath_pci_softc {
77
struct ath_softc sc_sc;
78
struct resource *sc_sr; /* memory resource */
79
struct resource *sc_irq; /* irq resource */
80
void *sc_ih; /* interrupt handler */
81
};
82
83
#define PCI_VDEVICE(v, d) \
84
PCI_DEV(v,d)
85
86
#define PCI_DEVICE_SUB(v, d, sv, sd) \
87
PCI_DEV(v, d), PCI_SUBDEV(sv, sd)
88
89
#define PCI_VENDOR_ID_ATHEROS 0x168c
90
#define PCI_VENDOR_ID_SAMSUNG 0x144d
91
#define PCI_VENDOR_ID_AZWAVE 0x1a3b
92
#define PCI_VENDOR_ID_FOXCONN 0x105b
93
#define PCI_VENDOR_ID_ATTANSIC 0x1969
94
#define PCI_VENDOR_ID_ASUSTEK 0x1043
95
#define PCI_VENDOR_ID_DELL 0x1028
96
#define PCI_VENDOR_ID_QMI 0x1a32
97
#define PCI_VENDOR_ID_LENOVO 0x17aa
98
#define PCI_VENDOR_ID_HP 0x103c
99
100
#include "if_ath_pci_devlist.h"
101
102
#define BS_BAR 0x10
103
#define PCIR_RETRY_TIMEOUT 0x41
104
#define PCIR_CFG_PMCSR 0x48
105
106
#define DEFAULT_CACHESIZE 32
107
108
static void
109
ath_pci_setup(device_t dev)
110
{
111
uint8_t cz;
112
113
/* XXX TODO: need to override the _system_ saved copies of this */
114
115
/*
116
* If the cache line size is 0, force it to a reasonable
117
* value.
118
*/
119
cz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
120
if (cz == 0) {
121
pci_write_config(dev, PCIR_CACHELNSZ,
122
DEFAULT_CACHESIZE / 4, 1);
123
}
124
125
/* Override the system latency timer */
126
pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1);
127
128
/* If a PCI NIC, force wakeup */
129
#ifdef ATH_PCI_WAKEUP_WAR
130
/* XXX TODO: don't do this for non-PCI (ie, PCIe, Cardbus!) */
131
if (1) {
132
uint16_t pmcsr;
133
pmcsr = pci_read_config(dev, PCIR_CFG_PMCSR, 2);
134
pmcsr |= 3;
135
pci_write_config(dev, PCIR_CFG_PMCSR, pmcsr, 2);
136
pmcsr &= ~3;
137
pci_write_config(dev, PCIR_CFG_PMCSR, pmcsr, 2);
138
}
139
#endif
140
141
/*
142
* Disable retry timeout to keep PCI Tx retries from
143
* interfering with C3 CPU state.
144
*/
145
pci_write_config(dev, PCIR_RETRY_TIMEOUT, 0, 1);
146
}
147
148
static int
149
ath_pci_probe(device_t dev)
150
{
151
const char* devname;
152
153
devname = ath_hal_probe(pci_get_vendor(dev), pci_get_device(dev));
154
if (devname != NULL) {
155
device_set_desc(dev, devname);
156
return BUS_PROBE_DEFAULT;
157
}
158
return ENXIO;
159
}
160
161
static int
162
ath_pci_attach(device_t dev)
163
{
164
struct ath_pci_softc *psc = device_get_softc(dev);
165
struct ath_softc *sc = &psc->sc_sc;
166
int error = ENXIO;
167
int rid;
168
#ifdef ATH_EEPROM_FIRMWARE
169
const struct firmware *fw = NULL;
170
const char *buf;
171
#endif
172
const struct pci_device_table *pd;
173
174
sc->sc_dev = dev;
175
176
/* Do this lookup anyway; figure out what to do with it later */
177
pd = PCI_MATCH(dev, ath_pci_id_table);
178
if (pd)
179
sc->sc_pci_devinfo = pd->driver_data;
180
181
/*
182
* Enable bus mastering.
183
*/
184
pci_enable_busmaster(dev);
185
186
/*
187
* Setup other PCI bus configuration parameters.
188
*/
189
ath_pci_setup(dev);
190
191
/*
192
* Setup memory-mapping of PCI registers.
193
*/
194
rid = BS_BAR;
195
psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
196
RF_ACTIVE);
197
if (psc->sc_sr == NULL) {
198
device_printf(dev, "cannot map register space\n");
199
goto bad;
200
}
201
sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr);
202
sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr);
203
/*
204
* Mark device invalid so any interrupts (shared or otherwise)
205
* that arrive before the HAL is setup are discarded.
206
*/
207
sc->sc_invalid = 1;
208
209
ATH_LOCK_INIT(sc);
210
ATH_PCU_LOCK_INIT(sc);
211
ATH_RX_LOCK_INIT(sc);
212
ATH_TX_LOCK_INIT(sc);
213
ATH_TXSTATUS_LOCK_INIT(sc);
214
215
/*
216
* Arrange interrupt line.
217
*/
218
rid = 0;
219
psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
220
RF_SHAREABLE|RF_ACTIVE);
221
if (psc->sc_irq == NULL) {
222
device_printf(dev, "could not map interrupt\n");
223
goto bad1;
224
}
225
if (bus_setup_intr(dev, psc->sc_irq,
226
INTR_TYPE_NET | INTR_MPSAFE,
227
NULL, ath_intr, sc, &psc->sc_ih)) {
228
device_printf(dev, "could not establish interrupt\n");
229
goto bad2;
230
}
231
232
/*
233
* Setup DMA descriptor area.
234
*/
235
if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
236
1, 0, /* alignment, bounds */
237
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
238
BUS_SPACE_MAXADDR, /* highaddr */
239
NULL, NULL, /* filter, filterarg */
240
0x3ffff, /* maxsize XXX */
241
ATH_MAX_SCATTER, /* nsegments */
242
0x3ffff, /* maxsegsize XXX */
243
BUS_DMA_ALLOCNOW, /* flags */
244
NULL, /* lockfunc */
245
NULL, /* lockarg */
246
&sc->sc_dmat)) {
247
device_printf(dev, "cannot allocate DMA tag\n");
248
goto bad3;
249
}
250
251
#ifdef ATH_EEPROM_FIRMWARE
252
/*
253
* If there's an EEPROM firmware image, load that in.
254
*/
255
if (resource_string_value(device_get_name(dev), device_get_unit(dev),
256
"eeprom_firmware", &buf) == 0) {
257
if (bootverbose)
258
device_printf(dev, "%s: looking up firmware @ '%s'\n",
259
__func__, buf);
260
261
fw = firmware_get(buf);
262
if (fw == NULL) {
263
device_printf(dev, "%s: couldn't find firmware\n",
264
__func__);
265
goto bad4;
266
}
267
268
device_printf(dev, "%s: EEPROM firmware @ %p\n",
269
__func__, fw->data);
270
sc->sc_eepromdata =
271
malloc(fw->datasize, M_TEMP, M_WAITOK | M_ZERO);
272
memcpy(sc->sc_eepromdata, fw->data, fw->datasize);
273
firmware_put(fw, 0);
274
}
275
#endif /* ATH_EEPROM_FIRMWARE */
276
277
error = ath_attach(pci_get_device(dev), sc);
278
if (error == 0) /* success */
279
return 0;
280
281
#ifdef ATH_EEPROM_FIRMWARE
282
bad4:
283
#endif
284
bus_dma_tag_destroy(sc->sc_dmat);
285
bad3:
286
bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
287
bad2:
288
bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
289
bad1:
290
bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr);
291
292
ATH_TXSTATUS_LOCK_DESTROY(sc);
293
ATH_PCU_LOCK_DESTROY(sc);
294
ATH_RX_LOCK_DESTROY(sc);
295
ATH_TX_LOCK_DESTROY(sc);
296
ATH_LOCK_DESTROY(sc);
297
298
bad:
299
return (error);
300
}
301
302
static int
303
ath_pci_detach(device_t dev)
304
{
305
struct ath_pci_softc *psc = device_get_softc(dev);
306
struct ath_softc *sc = &psc->sc_sc;
307
308
/* check if device was removed */
309
sc->sc_invalid = !bus_child_present(dev);
310
311
/*
312
* Do a config read to clear pre-existing pci error status.
313
*/
314
(void) pci_read_config(dev, PCIR_COMMAND, 4);
315
316
ath_detach(sc);
317
318
bus_generic_detach(dev);
319
bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
320
bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
321
322
bus_dma_tag_destroy(sc->sc_dmat);
323
bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr);
324
325
if (sc->sc_eepromdata)
326
free(sc->sc_eepromdata, M_TEMP);
327
328
ATH_TXSTATUS_LOCK_DESTROY(sc);
329
ATH_PCU_LOCK_DESTROY(sc);
330
ATH_RX_LOCK_DESTROY(sc);
331
ATH_TX_LOCK_DESTROY(sc);
332
ATH_LOCK_DESTROY(sc);
333
334
return (0);
335
}
336
337
static int
338
ath_pci_shutdown(device_t dev)
339
{
340
struct ath_pci_softc *psc = device_get_softc(dev);
341
342
ath_shutdown(&psc->sc_sc);
343
return (0);
344
}
345
346
static int
347
ath_pci_suspend(device_t dev)
348
{
349
struct ath_pci_softc *psc = device_get_softc(dev);
350
351
ath_suspend(&psc->sc_sc);
352
353
return (0);
354
}
355
356
static int
357
ath_pci_resume(device_t dev)
358
{
359
struct ath_pci_softc *psc = device_get_softc(dev);
360
361
/*
362
* Suspend/resume resets the PCI configuration space.
363
*/
364
ath_pci_setup(dev);
365
366
ath_resume(&psc->sc_sc);
367
368
return (0);
369
}
370
371
static device_method_t ath_pci_methods[] = {
372
/* Device interface */
373
DEVMETHOD(device_probe, ath_pci_probe),
374
DEVMETHOD(device_attach, ath_pci_attach),
375
DEVMETHOD(device_detach, ath_pci_detach),
376
DEVMETHOD(device_shutdown, ath_pci_shutdown),
377
DEVMETHOD(device_suspend, ath_pci_suspend),
378
DEVMETHOD(device_resume, ath_pci_resume),
379
{ 0,0 }
380
};
381
382
static driver_t ath_pci_driver = {
383
"ath",
384
ath_pci_methods,
385
sizeof (struct ath_pci_softc)
386
};
387
388
DRIVER_MODULE(if_ath_pci, pci, ath_pci_driver, 0, 0);
389
MODULE_VERSION(if_ath_pci, 1);
390
MODULE_DEPEND(if_ath_pci, wlan, 1, 1, 1); /* 802.11 media layer */
391
MODULE_DEPEND(if_ath_pci, ath_main, 1, 1, 1); /* if_ath driver */
392
MODULE_DEPEND(if_ath_pci, ath_hal, 1, 1, 1); /* ath HAL */
393
394