Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/ah_osdep.c
39536 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
#include "opt_ah.h"
32
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/kernel.h>
36
#include <sys/module.h>
37
#include <sys/sysctl.h>
38
#include <sys/bus.h>
39
#include <sys/malloc.h>
40
#include <sys/proc.h>
41
#include <sys/pcpu.h>
42
#include <sys/lock.h>
43
#include <sys/mutex.h>
44
#include <sys/conf.h>
45
#include <sys/stdarg.h>
46
47
#include <net/ethernet.h> /* XXX for ether_sprintf */
48
49
#include <dev/ath/ath_hal/ah.h>
50
#include <dev/ath/ath_hal/ah_debug.h>
51
52
/*
53
* WiSoC boards overload the bus tag with information about the
54
* board layout. We must extract the bus space tag from that
55
* indirect structure. For everyone else the tag is passed in
56
* directly.
57
* XXX cache indirect ref privately
58
*/
59
#ifdef AH_SUPPORT_AR5312
60
#define BUSTAG(ah) \
61
((bus_space_tag_t) ((struct ar531x_config *)((ah)->ah_st))->tag)
62
#else
63
#define BUSTAG(ah) ((ah)->ah_st)
64
#endif
65
66
/*
67
* This lock is used to seralise register access for chips which have
68
* problems w/ SMP CPUs issuing concurrent PCI transactions.
69
*
70
* XXX This is a global lock for now; it should be pushed to
71
* a per-device lock in some platform-independent fashion.
72
*/
73
struct mtx ah_regser_mtx;
74
MTX_SYSINIT(ah_regser, &ah_regser_mtx, "Atheros register access mutex",
75
MTX_SPIN);
76
77
extern void ath_hal_printf(struct ath_hal *, const char*, ...)
78
__printflike(2,3);
79
extern void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
80
__printflike(2, 0);
81
extern const char* ath_hal_ether_sprintf(const u_int8_t *mac);
82
extern void *ath_hal_malloc(size_t);
83
extern void ath_hal_free(void *);
84
#ifdef AH_ASSERT
85
extern void ath_hal_assert_failed(const char* filename,
86
int lineno, const char* msg);
87
#endif
88
#ifdef AH_DEBUG
89
extern void DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...);
90
#endif /* AH_DEBUG */
91
92
/* NB: put this here instead of the driver to avoid circular references */
93
SYSCTL_NODE(_hw, OID_AUTO, ath, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
94
"Atheros driver parameters");
95
static SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
96
"Atheros HAL parameters");
97
98
#ifdef AH_DEBUG
99
int ath_hal_debug = 0;
100
SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_hal_debug,
101
0, "Atheros HAL debugging printfs");
102
#endif /* AH_DEBUG */
103
104
static MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data");
105
106
void*
107
ath_hal_malloc(size_t size)
108
{
109
return malloc(size, M_ATH_HAL, M_NOWAIT | M_ZERO);
110
}
111
112
void
113
ath_hal_free(void* p)
114
{
115
free(p, M_ATH_HAL);
116
}
117
118
void
119
ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
120
{
121
vprintf(fmt, ap);
122
}
123
124
void
125
ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
126
{
127
va_list ap;
128
va_start(ap, fmt);
129
ath_hal_vprintf(ah, fmt, ap);
130
va_end(ap);
131
}
132
133
const char*
134
ath_hal_ether_sprintf(const u_int8_t *mac)
135
{
136
return ether_sprintf(mac);
137
}
138
139
#ifdef AH_DEBUG
140
141
/*
142
* XXX This is highly relevant only for the AR5416 and later
143
* PCI/PCIe NICs. It'll need adjustment for other hardware
144
* variations.
145
*/
146
static int
147
ath_hal_reg_whilst_asleep(struct ath_hal *ah, uint32_t reg)
148
{
149
150
if (reg >= 0x4000 && reg < 0x5000)
151
return (1);
152
if (reg >= 0x6000 && reg < 0x7000)
153
return (1);
154
if (reg >= 0x7000 && reg < 0x8000)
155
return (1);
156
return (0);
157
}
158
159
void
160
DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
161
{
162
if ((mask == HAL_DEBUG_UNMASKABLE) ||
163
(ah != NULL && ah->ah_config.ah_debug & mask) ||
164
(ath_hal_debug & mask)) {
165
__va_list ap;
166
va_start(ap, fmt);
167
ath_hal_vprintf(ah, fmt, ap);
168
va_end(ap);
169
}
170
}
171
#undef HAL_DEBUG_UNMASKABLE
172
#endif /* AH_DEBUG */
173
174
#ifdef AH_DEBUG_ALQ
175
/*
176
* ALQ register tracing support.
177
*
178
* Setting hw.ath.hal.alq=1 enables tracing of all register reads and
179
* writes to the file /tmp/ath_hal.log. The file format is a simple
180
* fixed-size array of records. When done logging set hw.ath.hal.alq=0
181
* and then decode the file with the arcode program (that is part of the
182
* HAL). If you start+stop tracing the data will be appended to an
183
* existing file.
184
*
185
* NB: doesn't handle multiple devices properly; only one DEVICE record
186
* is emitted and the different devices are not identified.
187
*/
188
#include <sys/alq.h>
189
#include <sys/pcpu.h>
190
#include <dev/ath/ath_hal/ah_decode.h>
191
192
static struct alq *ath_hal_alq;
193
static int ath_hal_alq_emitdev; /* need to emit DEVICE record */
194
static u_int ath_hal_alq_lost; /* count of lost records */
195
static char ath_hal_logfile[MAXPATHLEN] = "/tmp/ath_hal.log";
196
197
SYSCTL_STRING(_hw_ath_hal, OID_AUTO, alq_logfile, CTLFLAG_RW,
198
&ath_hal_logfile, sizeof(kernelname), "Name of ALQ logfile");
199
200
static u_int ath_hal_alq_qsize = 64*1024;
201
202
static int
203
ath_hal_setlogging(int enable)
204
{
205
int error;
206
207
if (enable) {
208
error = alq_open(&ath_hal_alq, ath_hal_logfile,
209
curthread->td_ucred, ALQ_DEFAULT_CMODE,
210
sizeof (struct athregrec), ath_hal_alq_qsize);
211
ath_hal_alq_lost = 0;
212
ath_hal_alq_emitdev = 1;
213
printf("ath_hal: logging to %s enabled\n",
214
ath_hal_logfile);
215
} else {
216
if (ath_hal_alq)
217
alq_close(ath_hal_alq);
218
ath_hal_alq = NULL;
219
printf("ath_hal: logging disabled\n");
220
error = 0;
221
}
222
return (error);
223
}
224
225
static int
226
sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)
227
{
228
int error, enable;
229
230
enable = (ath_hal_alq != NULL);
231
error = sysctl_handle_int(oidp, &enable, 0, req);
232
if (error || !req->newptr)
233
return (error);
234
else
235
return (ath_hal_setlogging(enable));
236
}
237
SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq,
238
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
239
0, 0, sysctl_hw_ath_hal_log, "I",
240
"Enable HAL register logging");
241
SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW,
242
&ath_hal_alq_qsize, 0, "In-memory log size (#records)");
243
SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW,
244
&ath_hal_alq_lost, 0, "Register operations not logged");
245
246
static struct ale *
247
ath_hal_alq_get(struct ath_hal *ah)
248
{
249
struct ale *ale;
250
251
if (ath_hal_alq_emitdev) {
252
ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
253
if (ale) {
254
struct athregrec *r =
255
(struct athregrec *) ale->ae_data;
256
r->op = OP_DEVICE;
257
r->reg = 0;
258
r->val = ah->ah_devid;
259
alq_post(ath_hal_alq, ale);
260
ath_hal_alq_emitdev = 0;
261
} else
262
ath_hal_alq_lost++;
263
}
264
ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
265
if (!ale)
266
ath_hal_alq_lost++;
267
return ale;
268
}
269
270
void
271
ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
272
{
273
bus_space_tag_t tag = BUSTAG(ah);
274
bus_space_handle_t h = ah->ah_sh;
275
276
#ifdef AH_DEBUG
277
/* Debug - complain if we haven't fully waken things up */
278
if (! ath_hal_reg_whilst_asleep(ah, reg) &&
279
ah->ah_powerMode != HAL_PM_AWAKE) {
280
ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
281
__func__, reg, val, ah->ah_powerMode);
282
}
283
#endif
284
285
if (ath_hal_alq) {
286
struct ale *ale = ath_hal_alq_get(ah);
287
if (ale) {
288
struct athregrec *r = (struct athregrec *) ale->ae_data;
289
r->threadid = curthread->td_tid;
290
r->op = OP_WRITE;
291
r->reg = reg;
292
r->val = val;
293
alq_post(ath_hal_alq, ale);
294
}
295
}
296
if (ah->ah_config.ah_serialise_reg_war)
297
mtx_lock_spin(&ah_regser_mtx);
298
bus_space_write_4(tag, h, reg, val);
299
OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE);
300
if (ah->ah_config.ah_serialise_reg_war)
301
mtx_unlock_spin(&ah_regser_mtx);
302
}
303
304
u_int32_t
305
ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
306
{
307
bus_space_tag_t tag = BUSTAG(ah);
308
bus_space_handle_t h = ah->ah_sh;
309
u_int32_t val;
310
311
#ifdef AH_DEBUG
312
/* Debug - complain if we haven't fully waken things up */
313
if (! ath_hal_reg_whilst_asleep(ah, reg) &&
314
ah->ah_powerMode != HAL_PM_AWAKE) {
315
ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
316
__func__, reg, ah->ah_powerMode);
317
}
318
#endif
319
320
if (ah->ah_config.ah_serialise_reg_war)
321
mtx_lock_spin(&ah_regser_mtx);
322
OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ);
323
val = bus_space_read_4(tag, h, reg);
324
if (ah->ah_config.ah_serialise_reg_war)
325
mtx_unlock_spin(&ah_regser_mtx);
326
if (ath_hal_alq) {
327
struct ale *ale = ath_hal_alq_get(ah);
328
if (ale) {
329
struct athregrec *r = (struct athregrec *) ale->ae_data;
330
r->threadid = curthread->td_tid;
331
r->op = OP_READ;
332
r->reg = reg;
333
r->val = val;
334
alq_post(ath_hal_alq, ale);
335
}
336
}
337
return val;
338
}
339
340
void
341
OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v)
342
{
343
if (ath_hal_alq) {
344
struct ale *ale = ath_hal_alq_get(ah);
345
if (ale) {
346
struct athregrec *r = (struct athregrec *) ale->ae_data;
347
r->threadid = curthread->td_tid;
348
r->op = OP_MARK;
349
r->reg = id;
350
r->val = v;
351
alq_post(ath_hal_alq, ale);
352
}
353
}
354
}
355
#else /* AH_DEBUG_ALQ */
356
357
/*
358
* Memory-mapped device register read/write. These are here
359
* as routines when debugging support is enabled and/or when
360
* explicitly configured to use function calls. The latter is
361
* for architectures that might need to do something before
362
* referencing memory (e.g. remap an i/o window).
363
*
364
* NB: see the comments in ah_osdep.h about byte-swapping register
365
* reads and writes to understand what's going on below.
366
*/
367
368
void
369
ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
370
{
371
bus_space_tag_t tag = BUSTAG(ah);
372
bus_space_handle_t h = ah->ah_sh;
373
374
#ifdef AH_DEBUG
375
/* Debug - complain if we haven't fully waken things up */
376
if (! ath_hal_reg_whilst_asleep(ah, reg) &&
377
ah->ah_powerMode != HAL_PM_AWAKE) {
378
ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
379
__func__, reg, val, ah->ah_powerMode);
380
}
381
#endif
382
383
if (ah->ah_config.ah_serialise_reg_war)
384
mtx_lock_spin(&ah_regser_mtx);
385
bus_space_write_4(tag, h, reg, val);
386
OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE);
387
if (ah->ah_config.ah_serialise_reg_war)
388
mtx_unlock_spin(&ah_regser_mtx);
389
}
390
391
u_int32_t
392
ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
393
{
394
bus_space_tag_t tag = BUSTAG(ah);
395
bus_space_handle_t h = ah->ah_sh;
396
u_int32_t val;
397
398
#ifdef AH_DEBUG
399
/* Debug - complain if we haven't fully waken things up */
400
if (! ath_hal_reg_whilst_asleep(ah, reg) &&
401
ah->ah_powerMode != HAL_PM_AWAKE) {
402
ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
403
__func__, reg, ah->ah_powerMode);
404
}
405
#endif
406
407
if (ah->ah_config.ah_serialise_reg_war)
408
mtx_lock_spin(&ah_regser_mtx);
409
OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ);
410
val = bus_space_read_4(tag, h, reg);
411
if (ah->ah_config.ah_serialise_reg_war)
412
mtx_unlock_spin(&ah_regser_mtx);
413
return val;
414
}
415
#endif /* AH_DEBUG_ALQ */
416
417
#ifdef AH_ASSERT
418
void
419
ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
420
{
421
printf("Atheros HAL assertion failure: %s: line %u: %s\n",
422
filename, lineno, msg);
423
panic("ath_hal_assert");
424
}
425
#endif /* AH_ASSERT */
426
427
static int
428
ath_hal_modevent(module_t mod __unused, int type, void *data __unused)
429
{
430
int error = 0;
431
432
switch (type) {
433
case MOD_LOAD:
434
if (bootverbose)
435
printf("[ath_hal] loaded\n");
436
break;
437
438
case MOD_UNLOAD:
439
if (bootverbose)
440
printf("[ath_hal] unloaded\n");
441
break;
442
443
case MOD_SHUTDOWN:
444
break;
445
446
default:
447
error = EOPNOTSUPP;
448
break;
449
}
450
return (error);
451
}
452
453
DEV_MODULE(ath_hal, ath_hal_modevent, NULL);
454
MODULE_VERSION(ath_hal, 1);
455
#if defined(AH_DEBUG_ALQ)
456
MODULE_DEPEND(ath_hal, alq, 1, 1, 1);
457
#endif
458
459