summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath/ah_osdep.c
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2011-11-09 22:39:44 +0000
committeradrian <adrian@FreeBSD.org>2011-11-09 22:39:44 +0000
commite5b49f0c7ed315e158898613578059687b2a1746 (patch)
tree8b602c0352d0beaefbd8d0506f3665295a64a4b2 /sys/dev/ath/ah_osdep.c
parent8e06d9e08e0ba646624564499631f71633de7e1c (diff)
downloadFreeBSD-src-e5b49f0c7ed315e158898613578059687b2a1746.zip
FreeBSD-src-e5b49f0c7ed315e158898613578059687b2a1746.tar.gz
Introduce a work-around for issues with the AR5416 based MAC on SMP devices.
The AR5416 MAC (which shows up in the AR5008, AR9001, AR9002 devices) has issues with PCI transactions on SMP machines. This work-around enforces that register access is serialised through a (global for now) spinlock. This should stop the hangs people have seen with the AR5416 PCI devices on SMP hosts. Obtained by: Linux, Atheros
Diffstat (limited to 'sys/dev/ath/ah_osdep.c')
-rw-r--r--sys/dev/ath/ah_osdep.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/sys/dev/ath/ah_osdep.c b/sys/dev/ath/ah_osdep.c
index 0272f6b..37b07c1 100644
--- a/sys/dev/ath/ah_osdep.c
+++ b/sys/dev/ath/ah_osdep.c
@@ -38,6 +38,8 @@
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/stdarg.h>
@@ -59,6 +61,17 @@
#define BUSTAG(ah) ((ah)->ah_st)
#endif
+/*
+ * This lock is used to seralise register access for chips which have
+ * problems w/ SMP CPUs issuing concurrent PCI transactions.
+ *
+ * XXX This is a global lock for now; it should be pushed to
+ * a per-device lock in some platform-independent fashion.
+ */
+struct mtx ah_regser_mtx;
+MTX_SYSINIT(ah_regser, &ah_regser_mtx, "Atheros register access mutex",
+ MTX_SPIN);
+
extern void ath_hal_printf(struct ath_hal *, const char*, ...)
__printflike(2,3);
extern void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
@@ -250,12 +263,16 @@ ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
alq_post(ath_hal_alq, ale);
}
}
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
#if _BYTE_ORDER == _BIG_ENDIAN
if (OS_REG_UNSWAPPED(reg))
bus_space_write_4(tag, h, reg, val);
else
#endif
bus_space_write_stream_4(tag, h, reg, val);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
}
u_int32_t
@@ -265,12 +282,16 @@ ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
bus_space_handle_t h = ah->ah_sh;
u_int32_t val;
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
#if _BYTE_ORDER == _BIG_ENDIAN
if (OS_REG_UNSWAPPED(reg))
val = bus_space_read_4(tag, h, reg);
else
#endif
val = bus_space_read_stream_4(tag, h, reg);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
if (ath_hal_alq) {
struct ale *ale = ath_hal_alq_get(ah);
if (ale) {
@@ -316,12 +337,16 @@ ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
bus_space_tag_t tag = BUSTAG(ah);
bus_space_handle_t h = ah->ah_sh;
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
#if _BYTE_ORDER == _BIG_ENDIAN
if (OS_REG_UNSWAPPED(reg))
bus_space_write_4(tag, h, reg, val);
else
#endif
bus_space_write_stream_4(tag, h, reg, val);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
}
u_int32_t
@@ -331,12 +356,16 @@ ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
bus_space_handle_t h = ah->ah_sh;
u_int32_t val;
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
#if _BYTE_ORDER == _BIG_ENDIAN
if (OS_REG_UNSWAPPED(reg))
val = bus_space_read_4(tag, h, reg);
else
#endif
val = bus_space_read_stream_4(tag, h, reg);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
return val;
}
#endif /* AH_DEBUG || AH_REGOPS_FUNC */
OpenPOWER on IntegriCloud