Date: Wed, 9 Nov 2011 22:39:44 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r227410 - in head/sys/dev/ath: . ath_hal ath_hal/ar5416 Message-ID: <201111092239.pA9Mdiq2003078@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Wed Nov 9 22:39:44 2011 New Revision: 227410 URL: http://svn.freebsd.org/changeset/base/227410 Log: 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 Modified: head/sys/dev/ath/ah_osdep.c head/sys/dev/ath/ath_hal/ah.c head/sys/dev/ath/ath_hal/ah.h head/sys/dev/ath/ath_hal/ah_internal.h head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c head/sys/dev/ath/if_ath.c head/sys/dev/ath/if_ath_sysctl.c Modified: head/sys/dev/ath/ah_osdep.c ============================================================================== --- head/sys/dev/ath/ah_osdep.c Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/ah_osdep.c Wed Nov 9 22:39:44 2011 (r227410) @@ -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_ 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_i 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_ 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_i 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 */ Modified: head/sys/dev/ath/ath_hal/ah.c ============================================================================== --- head/sys/dev/ath/ath_hal/ah.c Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/ath_hal/ah.c Wed Nov 9 22:39:44 2011 (r227410) @@ -665,6 +665,8 @@ ath_hal_getcapability(struct ath_hal *ah return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP; case HAL_CAP_BB_READ_WAR: /* Baseband read WAR */ return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_SERIALISE_WAR: /* PCI register serialisation */ + return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP; default: return HAL_EINVAL; } Modified: head/sys/dev/ath/ath_hal/ah.h ============================================================================== --- head/sys/dev/ath/ath_hal/ah.h Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/ath_hal/ah.h Wed Nov 9 22:39:44 2011 (r227410) @@ -150,6 +150,7 @@ typedef enum { HAL_CAP_RXDESC_SELFLINK = 242, /* support a self-linked tail RX descriptor */ HAL_CAP_LONG_RXDESC_TSF = 243, /* hardware supports 32bit TSF in RX descriptor */ HAL_CAP_BB_READ_WAR = 244, /* baseband read WAR */ + HAL_CAP_SERIALISE_WAR = 245, /* serialise register access on PCI */ } HAL_CAPABILITY_TYPE; /* @@ -781,6 +782,7 @@ typedef struct int ah_sw_beacon_response_time; /* in TU's */ int ah_additional_swba_backoff; /* in TU's */ int ah_force_full_reset; /* force full chip reset rather then warm reset */ + int ah_serialise_reg_war; /* force serialisation of register IO */ } HAL_OPS_CONFIG; /* Modified: head/sys/dev/ath/ath_hal/ah_internal.h ============================================================================== --- head/sys/dev/ath/ath_hal/ah_internal.h Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/ath_hal/ah_internal.h Wed Nov 9 22:39:44 2011 (r227410) @@ -210,7 +210,8 @@ typedef struct { halHasRxSelfLinkedTail : 1, halSupportsFastClock5GHz : 1, /* Hardware supports 5ghz fast clock; check eeprom/channel before using */ halHasLongRxDescTsf : 1, - halHasBBReadWar : 1; + halHasBBReadWar : 1, + halSerialiseRegWar : 1; uint32_t halWirelessModes; uint16_t halTotalQueues; uint16_t halKeyCacheSize; Modified: head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c ============================================================================== --- head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c Wed Nov 9 22:39:44 2011 (r227410) @@ -908,8 +908,24 @@ ar5416FillCapabilityInfo(struct ath_hal pCap->halRfSilentSupport = AH_TRUE; } + /* + * The MAC will mark frames as RXed if there's a descriptor + * to write them to. So if it hits a self-linked final descriptor, + * it'll keep ACKing frames even though they're being silently + * dropped. Thus, this particular feature of the driver can't + * be used for 802.11n devices. + */ ahpriv->ah_rxornIsFatal = AH_FALSE; + /* + * If it's a PCI NIC, ask the HAL OS layer to serialise + * register access, or SMP machines may cause the hardware + * to hang. This is applicable to AR5416 and AR9220; I'm not + * sure about AR9160 or AR9227. + */ + if (! AH_PRIVATE(ah)->ah_ispcie) + pCap->halSerialiseRegWar = 1; + return AH_TRUE; } Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/if_ath.c Wed Nov 9 22:39:44 2011 (r227410) @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <sys/priv.h> #include <sys/module.h> #include <sys/ktr.h> +#include <sys/smp.h> /* for mp_ncpus */ #include <machine/bus.h> @@ -675,6 +676,17 @@ ath_attach(u_int16_t devid, struct ath_s #endif /* + * Check if the hardware requires PCI register serialisation. + * Some of the Owl based MACs require this. + */ + if (mp_ncpus > 1 && + ath_hal_getcapability(ah, HAL_CAP_SERIALISE_WAR, + 0, NULL) == HAL_OK) { + sc->sc_ah->ah_config.ah_serialise_reg_war = 1; + device_printf(sc->sc_dev, "Enabling register serialisation\n"); + } + + /* * Indicate we need the 802.11 header padded to a * 32-bit boundary for 4-address and QoS frames. */ Modified: head/sys/dev/ath/if_ath_sysctl.c ============================================================================== --- head/sys/dev/ath/if_ath_sysctl.c Wed Nov 9 21:53:49 2011 (r227409) +++ head/sys/dev/ath/if_ath_sysctl.c Wed Nov 9 22:39:44 2011 (r227410) @@ -898,4 +898,11 @@ ath_sysctl_hal_attach(struct ath_softc * SYSCTL_ADD_INT(ctx, child, OID_AUTO, "force_full_reset", CTLFLAG_RW, &sc->sc_ah->ah_config.ah_force_full_reset, 0, "Force full chip reset rather than a warm reset"); + + /* + * This is initialised by the driver. + */ + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "serialise_reg_war", CTLFLAG_RW, + &sc->sc_ah->ah_config.ah_serialise_reg_war, 0, + "Force register access serialisation"); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201111092239.pA9Mdiq2003078>