summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath')
-rw-r--r--sys/dev/ath/ath_hal/ah.c3
-rw-r--r--sys/dev/ath/ath_hal/ah.h18
-rw-r--r--sys/dev/ath/ath_hal/ah_desc.h23
-rw-r--r--sys/dev/ath/ath_hal/ah_internal.h1
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210.h6
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_attach.c4
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c33
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211.h6
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_attach.c4
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c24
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212.h6
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_attach.c4
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c24
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416.h2
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c7
-rw-r--r--sys/dev/ath/ath_rate/amrr/amrr.c8
-rw-r--r--sys/dev/ath/ath_rate/onoe/onoe.c8
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.c107
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.h16
-rw-r--r--sys/dev/ath/if_ath.c328
-rw-r--r--sys/dev/ath/if_ath_ahb.c6
-rw-r--r--sys/dev/ath/if_ath_beacon.c9
-rw-r--r--sys/dev/ath/if_ath_misc.h15
-rw-r--r--sys/dev/ath/if_ath_pci.c6
-rw-r--r--sys/dev/ath/if_ath_rx.c13
-rw-r--r--sys/dev/ath/if_ath_rx_edma.c153
-rw-r--r--sys/dev/ath/if_ath_sysctl.c2
-rw-r--r--sys/dev/ath/if_ath_tx.c212
-rw-r--r--sys/dev/ath/if_ath_tx.h19
-rw-r--r--sys/dev/ath/if_ath_tx_edma.c311
-rw-r--r--sys/dev/ath/if_ath_tx_edma.h36
-rw-r--r--sys/dev/ath/if_ath_tx_ht.c26
-rw-r--r--sys/dev/ath/if_athioctl.h51
-rw-r--r--sys/dev/ath/if_athrate.h12
-rw-r--r--sys/dev/ath/if_athvar.h86
36 files changed, 1341 insertions, 249 deletions
diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c
index dea1736..36815f1 100644
--- a/sys/dev/ath/ath_hal/ah.c
+++ b/sys/dev/ath/ath_hal/ah.c
@@ -657,7 +657,8 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
}
case HAL_CAP_RXBUFSIZE:
case HAL_CAP_NUM_MR_RETRIES:
- return HAL_EINVAL; /* XXX not yet */
+ *result = pCap->halNumMRRetries;
+ return HAL_OK;
case HAL_CAP_BT_COEX:
return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_HT20_SGI:
diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h
index aa3e8b6..a22c25d 100644
--- a/sys/dev/ath/ath_hal/ah.h
+++ b/sys/dev/ath/ath_hal/ah.h
@@ -220,6 +220,8 @@ typedef enum {
#define HAL_NUM_RX_QUEUES 2 /* max possible # of queues */
+#define HAL_TXFIFO_DEPTH 8 /* transmit fifo depth */
+
/*
* Transmit queue subtype. These map directly to
* WME Access Categories (except for UPSD). Refer
@@ -580,13 +582,16 @@ typedef enum {
typedef struct {
u_int Tries;
- u_int Rate;
+ u_int Rate; /* hardware rate code */
+ u_int RateIndex; /* rate series table index */
u_int PktDuration;
u_int ChSel;
u_int RateFlags;
#define HAL_RATESERIES_RTS_CTS 0x0001 /* use rts/cts w/this series */
#define HAL_RATESERIES_2040 0x0002 /* use ext channel for series */
#define HAL_RATESERIES_HALFGI 0x0004 /* use half-gi for series */
+#define HAL_RATESERIES_STBC 0x0008 /* use STBC for series */
+ u_int tx_power_cap;
} HAL_11N_RATE_SERIES;
typedef enum {
@@ -1084,6 +1089,15 @@ struct ath_hal {
void __ahdecl(*ah_reqTxIntrDesc)(struct ath_hal *, struct ath_desc*);
HAL_BOOL __ahdecl(*ah_getTxCompletionRates)(struct ath_hal *,
const struct ath_desc *ds, int *rates, int *tries);
+ void __ahdecl(*ah_setTxDescLink)(struct ath_hal *ah, void *ds,
+ uint32_t link);
+ void __ahdecl(*ah_getTxDescLink)(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+ void __ahdecl(*ah_getTxDescLinkPtr)(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
+ void __ahdecl(*ah_setupTxStatusRing)(struct ath_hal *,
+ void *ts_start, uint32_t ts_paddr_start,
+ uint16_t size);
/* Receive Functions */
uint32_t __ahdecl(*ah_getRxDP)(struct ath_hal*, HAL_RX_QUEUE);
@@ -1224,7 +1238,7 @@ struct ath_hal {
struct ath_desc *, u_int, u_int,
HAL_11N_RATE_SERIES [], u_int, u_int);
void __ahdecl(*ah_set11nAggrFirst)(struct ath_hal *,
- struct ath_desc *, u_int, u_int);
+ struct ath_desc *, u_int);
void __ahdecl(*ah_set11nAggrMiddle)(struct ath_hal *,
struct ath_desc *, u_int);
void __ahdecl(*ah_set11nAggrLast)(struct ath_hal *,
diff --git a/sys/dev/ath/ath_hal/ah_desc.h b/sys/dev/ath/ath_hal/ah_desc.h
index 1203ebb..542453f 100644
--- a/sys/dev/ath/ath_hal/ah_desc.h
+++ b/sys/dev/ath/ath_hal/ah_desc.h
@@ -57,16 +57,19 @@ struct ath_tx_status {
uint8_t ts_finaltsi; /* final transmit series index */
#ifdef AH_SUPPORT_AR5416
/* 802.11n status */
- uint8_t ts_flags; /* misc flags */
- int8_t ts_rssi_ctl[3]; /* tx ack RSSI [ctl, chain 0-2] */
- int8_t ts_rssi_ext[3]; /* tx ack RSSI [ext, chain 0-2] */
-/* #define ts_rssi ts_rssi_combined */
- uint32_t ts_ba_low; /* blockack bitmap low */
- uint32_t ts_ba_high; /* blockack bitmap high */
+ uint8_t ts_flags; /* misc flags */
+ uint8_t ts_queue_id; /* AR9300: TX queue id */
+ uint8_t ts_desc_id; /* AR9300: TX descriptor id */
uint8_t ts_tid; /* TID */
- uint32_t ts_evm0; /* evm bytes */
- uint32_t ts_evm1;
- uint32_t ts_evm2;
+/* #define ts_rssi ts_rssi_combined */
+ uint32_t ts_ba_low; /* blockack bitmap low */
+ uint32_t ts_ba_high; /* blockack bitmap high */
+ uint32_t ts_evm0; /* evm bytes */
+ uint32_t ts_evm1;
+ uint32_t ts_evm2;
+ int8_t ts_rssi_ctl[3]; /* tx ack RSSI [ctl, chain 0-2] */
+ int8_t ts_rssi_ext[3]; /* tx ack RSSI [ext, chain 0-2] */
+ uint8_t ts_pad[2];
#endif /* AH_SUPPORT_AR5416 */
};
@@ -243,6 +246,8 @@ struct ath_desc_status {
#define HAL_TXDESC_EXT_ONLY 0x0080 /* send on ext channel only (11n) */
#define HAL_TXDESC_EXT_AND_CTL 0x0100 /* send on ext + ctl channels (11n) */
#define HAL_TXDESC_VMF 0x0200 /* virtual more frag */
+#define HAL_TXDESC_LOWRXCHAIN 0x0400 /* switch to low RX chain */
+#define HAL_TXDESC_LDPC 0x1000
/* flags passed to rx descriptor setup methods */
#define HAL_RXDESC_INTREQ 0x0020 /* enable per-descriptor interrupt */
diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h
index 65ec50e..200b84e 100644
--- a/sys/dev/ath/ath_hal/ah_internal.h
+++ b/sys/dev/ath/ath_hal/ah_internal.h
@@ -252,6 +252,7 @@ typedef struct {
int halRxStatusLen;
int halRxHpFifoDepth;
int halRxLpFifoDepth;
+ int halNumMRRetries;
} HAL_CAPABILITIES;
struct regDomain;
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210.h b/sys/dev/ath/ath_hal/ar5210/ar5210.h
index 657e250..b7cfea3 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210.h
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210.h
@@ -179,6 +179,12 @@ extern void ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *);
extern void ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
extern HAL_BOOL ar5210GetTxCompletionRates(struct ath_hal *ah,
const struct ath_desc *, int *rates, int *tries);
+extern void ar5210SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5210GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
extern uint32_t ar5210GetRxDP(struct ath_hal *, HAL_RX_QUEUE);
extern void ar5210SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE);
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
index 03c5f93..c62f936 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
@@ -75,6 +75,9 @@ static const struct ath_hal_private ar5210hal = {{
.ah_getTxIntrQueue = ar5210GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5210IntrReqTxDesc,
.ah_getTxCompletionRates = ar5210GetTxCompletionRates,
+ .ah_setTxDescLink = ar5210SetTxDescLink,
+ .ah_getTxDescLink = ar5210GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5210GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5210GetRxDP,
@@ -358,6 +361,7 @@ ar5210FillCapabilityInfo(struct ath_hal *ah)
pCap->halSleepAfterBeaconBroken = AH_TRUE;
pCap->halPSPollBroken = AH_FALSE;
+ pCap->halNumMRRetries = 1; /* No hardware MRR support */
pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
pCap->halKeyCacheSize = 64;
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c b/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
index f7c6030..ac3cb65 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
@@ -630,3 +630,36 @@ ar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *
{
return AH_FALSE;
}
+
+/*
+ * Set the TX descriptor link pointer
+ */
+void
+ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ ads->ds_link = link;
+}
+
+/*
+ * Get the TX descriptor link pointer
+ */
+void
+ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+/*
+ * Get a pointer to the TX descriptor link pointer
+ */
+void
+ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h
index 1d6c8af..2d631fb 100644
--- a/sys/dev/ath/ath_hal/ar5211/ar5211.h
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h
@@ -204,6 +204,12 @@ extern void ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *);
extern void ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
extern HAL_BOOL ar5211GetTxCompletionRates(struct ath_hal *ah,
const struct ath_desc *ds0, int *rates, int *tries);
+extern void ar5211SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5211GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
extern uint32_t ar5211GetRxDP(struct ath_hal *, HAL_RX_QUEUE);
extern void ar5211SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE);
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
index 186ece2..40a1f8a 100644
--- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
@@ -75,6 +75,9 @@ static const struct ath_hal_private ar5211hal = {{
.ah_getTxIntrQueue = ar5211GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5211IntrReqTxDesc,
.ah_getTxCompletionRates = ar5211GetTxCompletionRates,
+ .ah_setTxDescLink = ar5211SetTxDescLink,
+ .ah_getTxDescLink = ar5211GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5211GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5211GetRxDP,
@@ -493,6 +496,7 @@ ar5211FillCapabilityInfo(struct ath_hal *ah)
pCap->halSleepAfterBeaconBroken = AH_TRUE;
pCap->halPSPollBroken = AH_TRUE;
pCap->halVEOLSupport = AH_TRUE;
+ pCap->halNumMRRetries = 1; /* No hardware MRR support */
pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
pCap->halKeyCacheSize = 128;
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
index e1e7f73..da6e5c9 100644
--- a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
@@ -671,3 +671,27 @@ ar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *
return AH_FALSE;
}
+
+void
+ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ ads->ds_link = link;
+}
+
+void
+ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+void
+ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h
index a8b95d1..24770ce 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212.h
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h
@@ -602,6 +602,12 @@ extern void ar5212GetTxIntrQueue(struct ath_hal *ah, uint32_t *);
extern void ar5212IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
extern HAL_BOOL ar5212GetTxCompletionRates(struct ath_hal *ah,
const struct ath_desc *ds0, int *rates, int *tries);
+extern void ar5212SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5212GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5212GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
extern const HAL_RATE_TABLE *ar5212GetRateTable(struct ath_hal *, u_int mode);
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
index 43cbe7f..c3fd1c7 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
@@ -71,6 +71,9 @@ static const struct ath_hal_private ar5212hal = {{
.ah_getTxIntrQueue = ar5212GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5212IntrReqTxDesc,
.ah_getTxCompletionRates = ar5212GetTxCompletionRates,
+ .ah_setTxDescLink = ar5212SetTxDescLink,
+ .ah_getTxDescLink = ar5212GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5212GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5212GetRxDP,
@@ -821,6 +824,7 @@ ar5212FillCapabilityInfo(struct ath_hal *ah)
pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G;
pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */
+ pCap->halNumMRRetries = 4; /* Hardware supports 4 MRR */
pCap->halVEOLSupport = AH_TRUE;
pCap->halBssIdMaskSupport = AH_TRUE;
pCap->halMcastKeySrchSupport = AH_TRUE;
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
index 008330a..773d5f4 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
@@ -971,3 +971,27 @@ ar5212GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *
return AH_TRUE;
}
+
+void
+ar5212SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ ads->ds_link = link;
+}
+
+void
+ar5212GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+void
+ar5212GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.h b/sys/dev/ath/ath_hal/ar5416/ar5416.h
index 5a0e7ef..75cd3df 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416.h
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416.h
@@ -387,7 +387,7 @@ extern void ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
u_int nseries, u_int flags);
extern void ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds,
- u_int aggrLen, u_int numDelims);
+ u_int aggrLen);
extern void ar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims);
extern void ar5416Set11nAggrLast(struct ath_hal *ah, struct ath_desc *ds);
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
index fc5eefb..295124f7 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
@@ -892,6 +892,7 @@ ar5416FillCapabilityInfo(struct ath_hal *ah)
pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G;
pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */
+ pCap->halNumMRRetries = 4; /* Hardware supports 4 MRR */
pCap->halVEOLSupport = AH_TRUE;
pCap->halBssIdMaskSupport = AH_TRUE;
pCap->halMcastKeySrchSupport = AH_TRUE; /* Works on AR5416 and later */
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
index e33a55d..bc1b7ee4 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
@@ -135,6 +135,7 @@ ar5416StopTxDma(struct ath_hal *ah, u_int q)
#define set11nRateFlags(_series, _index) \
((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \
|((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \
+ |((_series)[_index].RateFlags & HAL_RATESERIES_STBC ? AR_STBC##_index : 0) \
|SM((_series)[_index].ChSel, AR_ChainSel##_index)
/*
@@ -727,16 +728,14 @@ ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
}
void
-ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds,
- u_int aggrLen, u_int numDelims)
+ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds, u_int aggrLen)
{
struct ar5416_desc *ads = AR5416DESC(ds);
ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
ads->ds_ctl6 &= ~(AR_AggrLen | AR_PadDelim);
- ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen) |
- SM(numDelims, AR_PadDelim);
+ ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
}
void
diff --git a/sys/dev/ath/ath_rate/amrr/amrr.c b/sys/dev/ath/ath_rate/amrr/amrr.c
index efba5dd..c252009 100644
--- a/sys/dev/ath/ath_rate/amrr/amrr.c
+++ b/sys/dev/ath/ath_rate/amrr/amrr.c
@@ -421,6 +421,14 @@ ath_rate_ctl(void *arg, struct ieee80211_node *ni)
}
}
+static int
+ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *re)
+{
+
+ return (EINVAL);
+}
+
static void
ath_rate_sysctlattach(struct ath_softc *sc)
{
diff --git a/sys/dev/ath/ath_rate/onoe/onoe.c b/sys/dev/ath/ath_rate/onoe/onoe.c
index 7160346..7c73926 100644
--- a/sys/dev/ath/ath_rate/onoe/onoe.c
+++ b/sys/dev/ath/ath_rate/onoe/onoe.c
@@ -407,6 +407,14 @@ ath_rate_sysctlattach(struct ath_softc *sc)
"rate control: # good periods before raising rate");
}
+static int
+ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *re)
+{
+
+ return (EINVAL);
+}
+
struct ath_ratectrl *
ath_rate_attach(struct ath_softc *sc)
{
diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c
index ae77e5e..985551b 100644
--- a/sys/dev/ath/ath_rate/sample/sample.c
+++ b/sys/dev/ath/ath_rate/sample/sample.c
@@ -105,8 +105,6 @@ __FBSDID("$FreeBSD$");
static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
-static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 };
-
static __inline int
size_to_bin(int size)
{
@@ -128,12 +126,6 @@ size_to_bin(int size)
return NUM_PACKET_SIZE_BINS-1;
}
-static __inline int
-bin_to_size(int index)
-{
- return packet_size_bins[index];
-}
-
void
ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
{
@@ -510,8 +502,10 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
goto done;
}
- /* XXX TODO: this doesn't know about 11gn vs 11g protection; teach it */
- mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
+ mrr = sc->sc_mrretry;
+ /* XXX check HT protmode too */
+ if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
+ mrr = 0;
best_rix = pick_best_rate(an, rt, size_bin, !mrr);
if (best_rix >= 0) {
@@ -918,7 +912,11 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
short_tries, long_tries);
return;
}
- mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
+ mrr = sc->sc_mrretry;
+ /* XXX check HT protmode too */
+ if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
+ mrr = 0;
+
if (!mrr || ts->ts_finaltsi == 0) {
if (!IS_RATE_DEFINED(sn, final_rix)) {
badrate(ifp, 0, ts->ts_rate, long_tries, status);
@@ -1198,6 +1196,93 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
#undef DOT11RATE
}
+/*
+ * Fetch the statistics for the given node.
+ *
+ * The ieee80211 node must be referenced and unlocked, however the ath_node
+ * must be locked.
+ *
+ * The main difference here is that we convert the rate indexes
+ * to 802.11 rates, or the userland output won't make much sense
+ * as it has no access to the rix table.
+ */
+int
+ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *rs)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct ath_rateioctl_tlv av;
+ struct ath_rateioctl_rt *tv;
+ int y;
+ int o = 0;
+
+ ATH_NODE_LOCK_ASSERT(an);
+
+ /*
+ * Ensure there's enough space for the statistics.
+ */
+ if (rs->len <
+ sizeof(struct ath_rateioctl_tlv) +
+ sizeof(struct ath_rateioctl_rt) +
+ sizeof(struct ath_rateioctl_tlv) +
+ sizeof(struct sample_node)) {
+ device_printf(sc->sc_dev, "%s: len=%d, too short\n",
+ __func__,
+ rs->len);
+ return (EINVAL);
+ }
+
+ /*
+ * Take a temporary copy of the sample node state so we can
+ * modify it before we copy it.
+ */
+ tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP,
+ M_NOWAIT | M_ZERO);
+ if (tv == NULL) {
+ return (ENOMEM);
+ }
+
+ /*
+ * Populate the rate table mapping TLV.
+ */
+ tv->nentries = rt->rateCount;
+ for (y = 0; y < rt->rateCount; y++) {
+ tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL;
+ if (rt->info[y].phy == IEEE80211_T_HT)
+ tv->ratecode[y] |= IEEE80211_RATE_MCS;
+ }
+
+ o = 0;
+ /*
+ * First TLV - rate code mapping
+ */
+ av.tlv_id = ATH_RATE_TLV_RATETABLE;
+ av.tlv_len = sizeof(struct ath_rateioctl_rt);
+ copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
+ o += sizeof(struct ath_rateioctl_tlv);
+ copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt));
+ o += sizeof(struct ath_rateioctl_rt);
+
+ /*
+ * Second TLV - sample node statistics
+ */
+ av.tlv_id = ATH_RATE_TLV_SAMPLENODE;
+ av.tlv_len = sizeof(struct sample_node);
+ copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
+ o += sizeof(struct ath_rateioctl_tlv);
+
+ /*
+ * Copy the statistics over to the provided buffer.
+ */
+ copyout(sn, rs->buf + o, sizeof(struct sample_node));
+ o += sizeof(struct sample_node);
+
+ free(tv, M_TEMP);
+
+ return (0);
+}
+
static void
sample_stats(void *arg, struct ieee80211_node *ni)
{
diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h
index bb72c0a..b9e7230 100644
--- a/sys/dev/ath/ath_rate/sample/sample.h
+++ b/sys/dev/ath/ath_rate/sample/sample.h
@@ -79,10 +79,18 @@ struct txschedule {
*/
#define NUM_PACKET_SIZE_BINS 2
+static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 };
+
+static inline int
+bin_to_size(int index)
+{
+ return packet_size_bins[index];
+}
+
/* per-node state */
struct sample_node {
int static_rix; /* rate index of fixed tx rate */
-#define SAMPLE_MAXRATES 32 /* NB: corresponds to hal info[32] */
+#define SAMPLE_MAXRATES 64 /* NB: corresponds to hal info[32] */
uint32_t ratemask; /* bit mask of valid rate indices */
const struct txschedule *sched; /* tx schedule table */
@@ -101,6 +109,9 @@ struct sample_node {
int packets_since_sample[NUM_PACKET_SIZE_BINS];
unsigned sample_tt[NUM_PACKET_SIZE_BINS];
};
+
+#ifdef _KERNEL
+
#define ATH_NODE_SAMPLE(an) ((struct sample_node *)&(an)[1])
#define IS_RATE_DEFINED(sn, rix) (((sn)->ratemask & (1<<(rix))) != 0)
@@ -225,4 +236,7 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc,
}
return tt;
}
+
+#endif /* _KERNEL */
+
#endif /* _DEV_ATH_RATE_SAMPLE_H */
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index 965a1fd..caae6308 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -109,6 +109,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ath/if_ath_keycache.h>
#include <dev/ath/if_ath_rx.h>
#include <dev/ath/if_ath_rx_edma.h>
+#include <dev/ath/if_ath_tx_edma.h>
#include <dev/ath/if_ath_beacon.h>
#include <dev/ath/if_athdfs.h>
@@ -253,6 +254,28 @@ SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold,
MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers");
+void
+ath_legacy_attach_comp_func(struct ath_softc *sc)
+{
+
+ /*
+ * Special case certain configurations. Note the
+ * CAB queue is handled by these specially so don't
+ * include them when checking the txq setup mask.
+ */
+ switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) {
+ case 0x01:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc);
+ break;
+ case 0x0f:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc);
+ break;
+ default:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc);
+ break;
+ }
+}
+
#define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20)
#define HAL_MODE_HT40 \
(HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \
@@ -306,8 +329,11 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if (ath_hal_hasedma(sc->sc_ah)) {
sc->sc_isedma = 1;
ath_recv_setup_edma(sc);
- } else
+ ath_xmit_setup_edma(sc);
+ } else {
ath_recv_setup_legacy(sc);
+ ath_xmit_setup_legacy(sc);
+ }
/*
* Check if the MAC has multi-rate retry support.
@@ -367,14 +393,24 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ath_setcurmode(sc, IEEE80211_MODE_11A);
/*
- * Allocate tx+rx descriptors and populate the lists.
+ * Allocate TX descriptors and populate the lists.
*/
error = ath_desc_alloc(sc);
if (error != 0) {
- if_printf(ifp, "failed to allocate descriptors: %d\n", error);
+ if_printf(ifp, "failed to allocate TX descriptors: %d\n",
+ error);
+ goto bad;
+ }
+ error = ath_txdma_setup(sc);
+ if (error != 0) {
+ if_printf(ifp, "failed to allocate TX descriptors: %d\n",
+ error);
goto bad;
}
+ /*
+ * Allocate RX descriptors and populate the lists.
+ */
error = ath_rxdma_setup(sc);
if (error != 0) {
if_printf(ifp, "failed to allocate RX descriptors: %d\n",
@@ -446,21 +482,12 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
}
/*
- * Special case certain configurations. Note the
- * CAB queue is handled by these specially so don't
- * include them when checking the txq setup mask.
+ * Attach the TX completion function.
+ *
+ * The non-EDMA chips may have some special case optimisations;
+ * this method gives everyone a chance to attach cleanly.
*/
- switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) {
- case 0x01:
- TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc);
- break;
- case 0x0f:
- TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc);
- break;
- default:
- TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc);
- break;
- }
+ sc->sc_tx.xmit_attach_comp_func(sc);
/*
* Setup rate control. Some rate control modules
@@ -678,6 +705,12 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
(void) ath_hal_settxchainmask(sc->sc_ah, tx_chainmask);
}
+ /*
+ * Disable MRR with protected frames by default.
+ * Only 802.11n series NICs can handle this.
+ */
+ sc->sc_mrrprot = 0; /* XXX should be a capability */
+
#ifdef ATH_ENABLE_11N
/*
* Query HT capabilities
@@ -687,6 +720,9 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
int rxs, txs;
device_printf(sc->sc_dev, "[HT] enabling HT modes\n");
+
+ sc->sc_mrrprot = 1; /* XXX should be a capability */
+
ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */
| IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */
| IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */
@@ -858,6 +894,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
bad2:
ath_tx_cleanup(sc);
ath_desc_free(sc);
+ ath_txdma_teardown(sc);
ath_rxdma_teardown(sc);
bad:
if (ah)
@@ -901,6 +938,7 @@ ath_detach(struct ath_softc *sc)
ath_dfs_detach(sc);
ath_desc_free(sc);
+ ath_txdma_teardown(sc);
ath_rxdma_teardown(sc);
ath_tx_cleanup(sc);
ath_hal_detach(sc->sc_ah); /* NB: sets chip in full sleep */
@@ -2749,28 +2787,32 @@ ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
*paddr = segs->ds_addr;
}
+/*
+ * Allocate the descriptors and appropriate DMA tag/setup.
+ *
+ * For some situations (eg EDMA TX completion), there isn't a requirement
+ * for the ath_buf entries to be allocated.
+ */
int
-ath_descdma_setup(struct ath_softc *sc,
+ath_descdma_alloc_desc(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head,
- const char *name, int nbuf, int ndesc)
+ const char *name, int ds_size, int ndesc)
{
#define DS2PHYS(_dd, _ds) \
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
#define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
struct ifnet *ifp = sc->sc_ifp;
- uint8_t *ds;
- struct ath_buf *bf;
- int i, bsize, error;
- int desc_len;
+ int error;
- desc_len = sizeof(struct ath_desc);
+ dd->dd_descsize = ds_size;
- DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n",
- __func__, name, nbuf, ndesc);
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: %s DMA: %u desc, %d bytes per descriptor\n",
+ __func__, name, ndesc, dd->dd_descsize);
dd->dd_name = name;
- dd->dd_desc_len = desc_len * nbuf * ndesc;
+ dd->dd_desc_len = dd->dd_descsize * ndesc;
/*
* Merlin work-around:
@@ -2778,8 +2820,8 @@ ath_descdma_setup(struct ath_softc *sc,
* Assume one skipped descriptor per 4KB page.
*/
if (! ath_hal_split4ktrans(sc->sc_ah)) {
- int numdescpage = 4096 / (desc_len * ndesc);
- dd->dd_desc_len = (nbuf / numdescpage + 1) * 4096;
+ int numpages = dd->dd_desc_len / 4096;
+ dd->dd_desc_len += ds_size * numpages;
}
/*
@@ -2815,7 +2857,7 @@ ath_descdma_setup(struct ath_softc *sc,
&dd->dd_dmamap);
if (error != 0) {
if_printf(ifp, "unable to alloc memory for %u %s descriptors, "
- "error %u\n", nbuf * ndesc, dd->dd_name, error);
+ "error %u\n", ndesc, dd->dd_name, error);
goto fail1;
}
@@ -2829,10 +2871,49 @@ ath_descdma_setup(struct ath_softc *sc,
goto fail2;
}
- ds = (uint8_t *) dd->dd_desc;
DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
- __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len,
- (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len);
+ __func__, dd->dd_name, (uint8_t *) dd->dd_desc,
+ (u_long) dd->dd_desc_len, (caddr_t) dd->dd_desc_paddr,
+ /*XXX*/ (u_long) dd->dd_desc_len);
+
+ return (0);
+
+fail2:
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+fail1:
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+fail0:
+ bus_dma_tag_destroy(dd->dd_dmat);
+ memset(dd, 0, sizeof(*dd));
+ return error;
+#undef DS2PHYS
+#undef ATH_DESC_4KB_BOUND_CHECK
+}
+
+int
+ath_descdma_setup(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head,
+ const char *name, int ds_size, int nbuf, int ndesc)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
+ ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
+ struct ifnet *ifp = sc->sc_ifp;
+ uint8_t *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ /* Allocate descriptors */
+ error = ath_descdma_alloc_desc(sc, dd, head, name, ds_size,
+ nbuf * ndesc);
+
+ /* Assume any errors during allocation were dealt with */
+ if (error != 0) {
+ return (error);
+ }
+
+ ds = (uint8_t *) dd->dd_desc;
/* allocate rx buffers */
bsize = sizeof(struct ath_buf) * nbuf;
@@ -2845,7 +2926,7 @@ ath_descdma_setup(struct ath_softc *sc,
dd->dd_bufptr = bf;
TAILQ_INIT(head);
- for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) {
+ for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * dd->dd_descsize)) {
bf->bf_desc = (struct ath_desc *) ds;
bf->bf_daddr = DS2PHYS(dd, ds);
if (! ath_hal_split4ktrans(sc->sc_ah)) {
@@ -2855,7 +2936,7 @@ ath_descdma_setup(struct ath_softc *sc,
* in the descriptor.
*/
if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr,
- desc_len * ndesc)) {
+ dd->dd_descsize)) {
/* Start at the next page */
ds += 0x1000 - (bf->bf_daddr & 0xFFF);
bf->bf_desc = (struct ath_desc *) ds;
@@ -2873,14 +2954,18 @@ ath_descdma_setup(struct ath_softc *sc,
bf->bf_lastds = bf->bf_desc; /* Just an initial value */
TAILQ_INSERT_TAIL(head, bf, bf_list);
}
+
+ /*
+ * XXX TODO: ensure that ds doesn't overflow the descriptor
+ * allocation otherwise weird stuff will occur and crash your
+ * machine.
+ */
return 0;
+ /* XXX this should likely just call ath_descdma_cleanup() */
fail3:
bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
-fail2:
bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
-fail1:
bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
-fail0:
bus_dma_tag_destroy(dd->dd_dmat);
memset(dd, 0, sizeof(*dd));
return error;
@@ -2888,6 +2973,69 @@ fail0:
#undef ATH_DESC_4KB_BOUND_CHECK
}
+/*
+ * Allocate ath_buf entries but no descriptor contents.
+ *
+ * This is for RX EDMA where the descriptors are the header part of
+ * the RX buffer.
+ */
+int
+ath_descdma_setup_rx_edma(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head,
+ const char *name, int nbuf, int rx_status_len)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers\n",
+ __func__, name, nbuf);
+
+ dd->dd_name = name;
+ /*
+ * This is (mostly) purely for show. We're not allocating any actual
+ * descriptors here as EDMA RX has the descriptor be part
+ * of the RX buffer.
+ *
+ * However, dd_desc_len is used by ath_descdma_free() to determine
+ * whether we have already freed this DMA mapping.
+ */
+ dd->dd_desc_len = rx_status_len * nbuf;
+ dd->dd_descsize = rx_status_len;
+
+ /* allocate rx buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
+ if (bf == NULL) {
+ if_printf(ifp, "malloc of %s buffers failed, size %u\n",
+ dd->dd_name, bsize);
+ error = ENOMEM;
+ goto fail3;
+ }
+ dd->dd_bufptr = bf;
+
+ TAILQ_INIT(head);
+ for (i = 0; i < nbuf; i++, bf++) {
+ bf->bf_desc = NULL;
+ bf->bf_daddr = 0;
+ bf->bf_lastds = NULL; /* Just an initial value */
+
+ error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
+ &bf->bf_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s "
+ "buffer %u, error %u\n", dd->dd_name, i, error);
+ ath_descdma_cleanup(sc, dd, head);
+ return error;
+ }
+ TAILQ_INSERT_TAIL(head, bf, bf_list);
+ }
+ return 0;
+fail3:
+ memset(dd, 0, sizeof(*dd));
+ return error;
+}
+
void
ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head)
@@ -2895,32 +3043,39 @@ ath_descdma_cleanup(struct ath_softc *sc,
struct ath_buf *bf;
struct ieee80211_node *ni;
- bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
- bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
- bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
- bus_dma_tag_destroy(dd->dd_dmat);
+ if (dd->dd_dmamap != 0) {
+ bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+ bus_dma_tag_destroy(dd->dd_dmat);
+ }
- TAILQ_FOREACH(bf, head, bf_list) {
- if (bf->bf_m) {
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
- }
- if (bf->bf_dmamap != NULL) {
- bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
- bf->bf_dmamap = NULL;
- }
- ni = bf->bf_node;
- bf->bf_node = NULL;
- if (ni != NULL) {
- /*
- * Reclaim node reference.
- */
- ieee80211_free_node(ni);
+ if (head != NULL) {
+ TAILQ_FOREACH(bf, head, bf_list) {
+ if (bf->bf_m) {
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_dmamap != NULL) {
+ bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
+ bf->bf_dmamap = NULL;
+ }
+ ni = bf->bf_node;
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
}
}
- TAILQ_INIT(head);
- free(dd->dd_bufptr, M_ATHDEV);
+ if (head != NULL)
+ TAILQ_INIT(head);
+
+ if (dd->dd_bufptr != NULL)
+ free(dd->dd_bufptr, M_ATHDEV);
memset(dd, 0, sizeof(*dd));
}
@@ -2930,14 +3085,15 @@ ath_desc_alloc(struct ath_softc *sc)
int error;
error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
- "tx", ath_txbuf, ATH_TXDESC);
+ "tx", sc->sc_tx_desclen, ath_txbuf, ATH_TXDESC);
if (error != 0) {
return error;
}
sc->sc_txbuf_cnt = ath_txbuf;
error = ath_descdma_setup(sc, &sc->sc_txdma_mgmt, &sc->sc_txbuf_mgmt,
- "tx_mgmt", ath_txbuf_mgmt, ATH_TXDESC);
+ "tx_mgmt", sc->sc_tx_desclen, ath_txbuf_mgmt,
+ ATH_TXDESC);
if (error != 0) {
ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
return error;
@@ -2949,7 +3105,7 @@ ath_desc_alloc(struct ath_softc *sc)
*/
error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
- "beacon", ATH_BCBUF, 1);
+ "beacon", sc->sc_tx_desclen, ATH_BCBUF, 1);
if (error != 0) {
ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
ath_descdma_cleanup(sc, &sc->sc_txdma_mgmt,
@@ -3429,8 +3585,8 @@ ath_tx_update_busy(struct ath_softc *sc)
* Kick the packet scheduler if needed. This can occur from this
* particular task.
*/
-static int
-ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
+int
+ath_legacy_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
@@ -3830,7 +3986,7 @@ ath_tx_freebuf(struct ath_softc *sc, struct ath_buf *bf, int status)
}
void
-ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+ath_legacy_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
{
#ifdef ATH_DEBUG
struct ath_hal *ah = sc->sc_ah;
@@ -4861,6 +5017,43 @@ ath_watchdog(void *arg)
callout_schedule(&sc->sc_wd_ch, hz);
}
+/*
+ * Fetch the rate control statistics for the given node.
+ */
+static int
+ath_ioctl_ratestats(struct ath_softc *sc, struct ath_rateioctl *rs)
+{
+ struct ath_node *an;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_node *ni;
+ int error = 0;
+
+ /* Perform a lookup on the given node */
+ ni = ieee80211_find_node(&ic->ic_sta, rs->is_u.macaddr);
+ if (ni == NULL) {
+ error = EINVAL;
+ goto bad;
+ }
+
+ /* Lock the ath_node */
+ an = ATH_NODE(ni);
+ ATH_NODE_LOCK(an);
+
+ /* Fetch the rate control stats for this node */
+ error = ath_rate_fetch_node_stats(sc, an, rs);
+
+ /* No matter what happens here, just drop through */
+
+ /* Unlock the ath_node */
+ ATH_NODE_UNLOCK(an);
+
+ /* Unref the node */
+ ieee80211_node_decref(ni);
+
+bad:
+ return (error);
+}
+
#ifdef ATH_DIAGAPI
/*
* Diagnostic interface to the HAL. This is used by various
@@ -5009,6 +5202,9 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = ath_ioctl_phyerr(sc,(struct ath_diag*) ifr);
break;
#endif
+ case SIOCGATHNODERATESTATS:
+ error = ath_ioctl_ratestats(sc, (struct ath_rateioctl *) ifr);
+ break;
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
diff --git a/sys/dev/ath/if_ath_ahb.c b/sys/dev/ath/if_ath_ahb.c
index a5bb413..1d8d7ac 100644
--- a/sys/dev/ath/if_ath_ahb.c
+++ b/sys/dev/ath/if_ath_ahb.c
@@ -193,11 +193,15 @@ ath_ahb_attach(device_t dev)
ATH_LOCK_INIT(sc);
ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TXSTATUS_LOCK_INIT(sc);
error = ath_attach(AR9130_DEVID, sc);
if (error == 0) /* success */
return 0;
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
bus_dma_tag_destroy(sc->sc_dmat);
@@ -238,6 +242,8 @@ ath_ahb_detach(device_t dev)
if (sc->sc_eepromdata)
free(sc->sc_eepromdata, M_TEMP);
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
diff --git a/sys/dev/ath/if_ath_beacon.c b/sys/dev/ath/if_ath_beacon.c
index c4b159a..4ebdcf0 100644
--- a/sys/dev/ath/if_ath_beacon.c
+++ b/sys/dev/ath/if_ath_beacon.c
@@ -277,14 +277,15 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
flags = HAL_TXDESC_NOACK;
if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) {
- ds->ds_link = bf->bf_daddr; /* self-linked */
+ /* self-linked descriptor */
+ ath_hal_settxdesclink(sc->sc_ah, ds, bf->bf_daddr);
flags |= HAL_TXDESC_VEOL;
/*
* Let hardware handle antenna switching.
*/
antenna = sc->sc_txantenna;
} else {
- ds->ds_link = 0;
+ ath_hal_settxdesclink(sc->sc_ah, ds, 0);
/*
* Switch antenna every 4 beacons.
* XXX assumes two antenna
@@ -405,8 +406,10 @@ ath_beacon_proc(void *arg, int pending)
if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) {
bf = ath_beacon_generate(sc, vap);
if (bf != NULL) {
+ /* XXX should do this using the ds */
*bflink = bf->bf_daddr;
- bflink = &bf->bf_desc->ds_link;
+ ath_hal_gettxdesclinkptr(sc->sc_ah,
+ bf->bf_desc, &bflink);
}
}
}
diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h
index 0a51fee..d34c72c 100644
--- a/sys/dev/ath/if_ath_misc.h
+++ b/sys/dev/ath/if_ath_misc.h
@@ -66,7 +66,6 @@ extern void ath_returnbuf_head(struct ath_softc *sc, struct ath_buf *bf);
extern void ath_returnbuf_tail(struct ath_softc *sc, struct ath_buf *bf);
extern int ath_reset(struct ifnet *, ATH_RESET_TYPE);
-extern void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq);
extern void ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf,
int fail);
extern void ath_tx_update_ratectrl(struct ath_softc *sc,
@@ -84,11 +83,23 @@ extern void ath_setdefantenna(struct ath_softc *sc, u_int antenna);
extern void ath_setslottime(struct ath_softc *sc);
+extern int ath_descdma_alloc_desc(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head, const char *name,
+ int ds_size, int ndesc);
extern int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
- ath_bufhead *head, const char *name, int nbuf, int ndesc);
+ ath_bufhead *head, const char *name, int ds_size, int nbuf,
+ int ndesc);
+extern int ath_descdma_setup_rx_edma(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head, const char *name,
+ int nbuf, int desclen);
extern void ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head);
+extern void ath_legacy_attach_comp_func(struct ath_softc *sc);
+extern void ath_legacy_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq);
+extern int ath_legacy_tx_processq(struct ath_softc *sc, struct ath_txq *txq,
+ int dosched);
+
/*
* This is only here so that the RX proc function can call it.
* It's very likely that the "start TX after RX" call should be
diff --git a/sys/dev/ath/if_ath_pci.c b/sys/dev/ath/if_ath_pci.c
index 773b79d..5973dc3 100644
--- a/sys/dev/ath/if_ath_pci.c
+++ b/sys/dev/ath/if_ath_pci.c
@@ -249,12 +249,16 @@ ath_pci_attach(device_t dev)
ATH_LOCK_INIT(sc);
ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TXSTATUS_LOCK_INIT(sc);
error = ath_attach(pci_get_device(dev), sc);
if (error == 0) /* success */
return 0;
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
bus_dma_tag_destroy(sc->sc_dmat);
bad3:
@@ -293,7 +297,9 @@ ath_pci_detach(device_t dev)
if (sc->sc_eepromdata)
free(sc->sc_eepromdata, M_TEMP);
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
return (0);
diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c
index eba6ba5..4027bfe 100644
--- a/sys/dev/ath/if_ath_rx.c
+++ b/sys/dev/ath/if_ath_rx.c
@@ -534,6 +534,14 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status,
goto rx_accept;
sc->sc_stats.ast_rx_badcrypt++;
}
+ /*
+ * Similar as above - if the failure was a keymiss
+ * just punt it up to the upper layers for now.
+ */
+ if (rs->rs_status & HAL_RXERR_KEYMISS) {
+ sc->sc_stats.ast_rx_keymiss++;
+ goto rx_accept;
+ }
if (rs->rs_status & HAL_RXERR_MIC) {
sc->sc_stats.ast_rx_badmic++;
/*
@@ -1067,7 +1075,7 @@ ath_legacy_dma_rxsetup(struct ath_softc *sc)
device_printf(sc->sc_dev, "%s: called\n", __func__);
error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
- "rx", ath_rxbuf, 1);
+ "rx", sizeof(struct ath_desc), ath_rxbuf, 1);
if (error != 0)
return (error);
@@ -1091,6 +1099,9 @@ ath_recv_setup_legacy(struct ath_softc *sc)
device_printf(sc->sc_dev, "DMA setup: legacy\n");
+ /* Sensible legacy defaults */
+ sc->sc_rx_statuslen = 0;
+
sc->sc_rx.recv_start = ath_legacy_startrecv;
sc->sc_rx.recv_stop = ath_legacy_stoprecv;
sc->sc_rx.recv_flush = ath_legacy_flushrecv;
diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c
index 9e3580d..b6f7dfd 100644
--- a/sys/dev/ath/if_ath_rx_edma.c
+++ b/sys/dev/ath/if_ath_rx_edma.c
@@ -156,6 +156,7 @@ ath_edma_stoprecv(struct ath_softc *sc, int dodelay)
{
struct ath_hal *ah = sc->sc_ah;
+ ATH_RX_LOCK(sc);
ath_hal_stoppcurecv(ah);
ath_hal_setrxfilter(ah, 0);
ath_hal_stopdmarecv(ah);
@@ -173,6 +174,7 @@ ath_edma_stoprecv(struct ath_softc *sc, int dodelay)
m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending);
sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
}
+ ATH_RX_UNLOCK(sc);
}
/*
@@ -187,6 +189,8 @@ ath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype)
struct ath_buf *bf;
int i, j;
+ ATH_RX_LOCK_ASSERT(sc);
+
i = re->m_fifo_head;
for (j = 0; j < re->m_fifo_depth; j++) {
bf = re->m_fifo[i];
@@ -221,6 +225,8 @@ ath_edma_startrecv(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
+ ATH_RX_LOCK(sc);
+
/* Enable RX FIFO */
ath_hal_rxena(ah);
@@ -266,6 +272,9 @@ ath_edma_startrecv(struct ath_softc *sc)
ath_mode_init(sc);
ath_hal_startpcurecv(ah);
+
+ ATH_RX_UNLOCK(sc);
+
return (0);
}
@@ -275,8 +284,16 @@ ath_edma_recv_flush(struct ath_softc *sc)
device_printf(sc->sc_dev, "%s: called\n", __func__);
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 0);
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 0);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
}
/*
@@ -300,16 +317,21 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
struct ath_desc *ds;
struct ath_buf *bf;
struct mbuf *m;
- HAL_STATUS status;
struct ath_hal *ah = sc->sc_ah;
uint64_t tsf;
int16_t nf;
- int ngood = 0;
+ int ngood = 0, npkts = 0;
+ ath_bufhead rxlist;
+ struct ath_buf *next;
+
+ TAILQ_INIT(&rxlist);
tsf = ath_hal_gettsf64(ah);
nf = ath_hal_getchannoise(ah, sc->sc_curchan);
sc->sc_stats.ast_rx_noise = nf;
+ ATH_RX_LOCK(sc);
+
do {
bf = re->m_fifo[re->m_fifo_head];
/* This shouldn't occur! */
@@ -330,12 +352,13 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
rs = &bf->bf_status.ds_rxstat;
- status = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr, NULL, rs);
+ bf->bf_rxstatus = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr,
+ NULL, rs);
#ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
- ath_printrxbuf(sc, bf, 0, status == HAL_OK);
+ ath_printrxbuf(sc, bf, 0, bf->bf_rxstatus == HAL_OK);
#endif
- if (status == HAL_EINPROGRESS)
+ if (bf->bf_rxstatus == HAL_EINPROGRESS)
break;
/*
@@ -347,36 +370,67 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
*/
DPRINTF(sc, ATH_DEBUG_EDMA_RX,
"%s: Q%d: completed!\n", __func__, qtype);
+ npkts++;
/*
- * Remove the FIFO entry!
+ * Remove the FIFO entry and place it on the completion
+ * queue.
*/
re->m_fifo[re->m_fifo_head] = NULL;
+ TAILQ_INSERT_TAIL(&rxlist, bf, bf_list);
+ /* Bump the descriptor FIFO stats */
+ INCR(re->m_fifo_head, re->m_fifolen);
+ re->m_fifo_depth--;
+ /* XXX check it doesn't fall below 0 */
+ } while (re->m_fifo_depth > 0);
+
+ /* Append some more fresh frames to the FIFO */
+ if (dosched)
+ ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen);
+
+ ATH_RX_UNLOCK(sc);
+
+ /* Handle the completed descriptors */
+ TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) {
/*
* Skip the RX descriptor status - start at the data offset
*/
- m_adj(m, sc->sc_rx_statuslen);
+ m_adj(bf->bf_m, sc->sc_rx_statuslen);
/* Handle the frame */
- if (ath_rx_pkt(sc, rs, status, tsf, nf, qtype, bf))
+ /*
+ * Note: this may or may not free bf->bf_m and sync/unmap
+ * the frame.
+ */
+ rs = &bf->bf_status.ds_rxstat;
+ if (ath_rx_pkt(sc, rs, bf->bf_rxstatus, tsf, nf, qtype, bf))
ngood++;
+ }
+ /* Free in one set, inside the lock */
+ ATH_RX_LOCK(sc);
+ TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) {
/* Free the buffer/mbuf */
ath_edma_rxbuf_free(sc, bf);
+ }
+ ATH_RX_UNLOCK(sc);
- /* Bump the descriptor FIFO stats */
- INCR(re->m_fifo_head, re->m_fifolen);
- re->m_fifo_depth--;
- /* XXX check it doesn't fall below 0 */
- } while (re->m_fifo_depth > 0);
+ /* rx signal state monitoring */
+ ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan);
+ if (ngood)
+ sc->sc_lastrx = tsf;
+
+ CTR2(ATH_KTR_INTR, "ath edma rx proc: npkts=%d, ngood=%d",
+ npkts, ngood);
/* Handle resched and kickpcu appropriately */
ATH_PCU_LOCK(sc);
if (dosched && sc->sc_kickpcu) {
CTR0(ATH_KTR_ERR, "ath_edma_recv_proc_queue(): kickpcu");
- device_printf(sc->sc_dev, "%s: handled %d descriptors\n",
- __func__, ngood);
+ device_printf(sc->sc_dev,
+ "%s: handled npkts %d ngood %d\n",
+ __func__, npkts, ngood);
/*
* XXX TODO: what should occur here? Just re-poke and
@@ -386,10 +440,6 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
}
ATH_PCU_UNLOCK(sc);
- /* Append some more fresh frames to the FIFO */
- if (dosched)
- ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen);
-
return (ngood);
}
@@ -397,6 +447,10 @@ static void
ath_edma_recv_tasklet(void *arg, int npending)
{
struct ath_softc *sc = (struct ath_softc *) arg;
+ struct ifnet *ifp = sc->sc_ifp;
+#ifdef IEEE80211_SUPPORT_SUPERG
+ struct ieee80211com *ic = ifp->if_l2com;
+#endif
DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: called; npending=%d\n",
__func__,
@@ -409,10 +463,26 @@ ath_edma_recv_tasklet(void *arg, int npending)
ATH_PCU_UNLOCK(sc);
return;
}
+ sc->sc_rxproc_cnt++;
ATH_PCU_UNLOCK(sc);
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1);
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1);
+
+ /* XXX inside IF_LOCK ? */
+ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
+#ifdef IEEE80211_SUPPORT_SUPERG
+ ieee80211_ff_age_all(ic, 100);
+#endif
+ if (! IFQ_IS_EMPTY(&ifp->if_snd))
+ ath_tx_kick(sc);
+ }
+ if (ath_dfs_tasklet_needed(sc, sc->sc_curchan))
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
}
/*
@@ -435,6 +505,8 @@ ath_edma_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
int error;
int len;
+ ATH_RX_LOCK_ASSERT(sc);
+
// device_printf(sc->sc_dev, "%s: called; bf=%p\n", __func__, bf);
m = m_getm(NULL, sc->sc_edma_bufsize, M_DONTWAIT, MT_DATA);
@@ -498,6 +570,8 @@ ath_edma_rxbuf_alloc(struct ath_softc *sc)
struct ath_buf *bf;
int error;
+ ATH_RX_LOCK_ASSERT(sc);
+
/* Allocate buffer */
bf = TAILQ_FIRST(&sc->sc_rxbuf);
/* XXX shouldn't happen upon startup? */
@@ -526,6 +600,9 @@ static void
ath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf)
{
+ ATH_RX_LOCK_ASSERT(sc);
+
+ /* We're doing this multiple times? */
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
if (bf->bf_m) {
@@ -550,6 +627,8 @@ ath_edma_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype, int nbufs)
struct ath_buf *bf;
int i;
+ ATH_RX_LOCK_ASSERT(sc);
+
/*
* Allocate buffers until the FIFO is full or nbufs is reached.
*/
@@ -616,6 +695,8 @@ ath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype)
struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
int i;
+ ATH_RX_LOCK_ASSERT(sc);
+
for (i = 0; i < re->m_fifolen; i++) {
if (re->m_fifo[i] != NULL) {
#ifdef ATH_DEBUG
@@ -647,6 +728,8 @@ ath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype)
{
struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+ ATH_RX_LOCK_ASSERT(sc);
+
if (! ath_hal_getrxfifodepth(sc->sc_ah, qtype, &re->m_fifolen)) {
device_printf(sc->sc_dev, "%s: qtype=%d, failed\n",
__func__,
@@ -696,16 +779,18 @@ ath_edma_dma_rxsetup(struct ath_softc *sc)
{
int error;
- /* Create RX DMA tag */
- /* Create RX ath_buf array */
-
- error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
- "rx", ath_rxbuf, 1);
+ /*
+ * Create RX DMA tag and buffers.
+ */
+ error = ath_descdma_setup_rx_edma(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ "rx", ath_rxbuf, sc->sc_rx_statuslen);
if (error != 0)
return error;
+ ATH_RX_LOCK(sc);
(void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_HP);
(void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_LP);
+ ATH_RX_UNLOCK(sc);
return (0);
}
@@ -716,11 +801,13 @@ ath_edma_dma_rxteardown(struct ath_softc *sc)
device_printf(sc->sc_dev, "%s: called\n", __func__);
+ ATH_RX_LOCK(sc);
ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_HP);
ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_HP);
ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_LP);
ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_LP);
+ ATH_RX_UNLOCK(sc);
/* Free RX ath_buf */
/* Free RX DMA tag */
@@ -739,25 +826,17 @@ ath_recv_setup_edma(struct ath_softc *sc)
/* Set buffer size to 4k */
sc->sc_edma_bufsize = 4096;
- /* Configure the hardware with this */
- (void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize);
-
/* Fetch EDMA field and buffer sizes */
(void) ath_hal_getrxstatuslen(sc->sc_ah, &sc->sc_rx_statuslen);
- (void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen);
- (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen);
- (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps);
+
+ /* Configure the hardware with the RX buffer size */
+ (void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize -
+ sc->sc_rx_statuslen);
device_printf(sc->sc_dev, "RX status length: %d\n",
sc->sc_rx_statuslen);
- device_printf(sc->sc_dev, "TX descriptor length: %d\n",
- sc->sc_tx_desclen);
- device_printf(sc->sc_dev, "TX status length: %d\n",
- sc->sc_tx_statuslen);
- device_printf(sc->sc_dev, "TX/RX buffer size: %d\n",
+ device_printf(sc->sc_dev, "RX buffer size: %d\n",
sc->sc_edma_bufsize);
- device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n",
- sc->sc_tx_nmaps);
sc->sc_rx.recv_stop = ath_edma_stoprecv;
sc->sc_rx.recv_start = ath_edma_startrecv;
diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c
index ff75888..e1e9426 100644
--- a/sys/dev/ath/if_ath_sysctl.c
+++ b/sys/dev/ath/if_ath_sysctl.c
@@ -934,6 +934,8 @@ ath_sysctl_stats_attach(struct ath_softc *sc)
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_mcastq_overflow",
CTLFLAG_RD, &sc->sc_stats.ast_tx_mcastq_overflow, 0,
"Number of multicast frames exceeding maximum mcast queue depth");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_keymiss", CTLFLAG_RD,
+ &sc->sc_stats.ast_rx_keymiss, 0, "");
/* Attach the RX phy error array */
ath_sysctl_stats_attach_rxphyerr(sc, child);
diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c
index 934f9dc..699478a 100644
--- a/sys/dev/ath/if_ath_tx.c
+++ b/sys/dev/ath/if_ath_tx.c
@@ -302,6 +302,11 @@ ath_tx_chaindesclist(struct ath_softc *sc, struct ath_buf *bf)
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds, *ds0;
int i;
+ /*
+ * XXX There's txdma and txdma_mgmt; the descriptor
+ * sizes must match.
+ */
+ struct ath_descdma *dd = &sc->sc_txdma;
/*
* Fillin the remainder of the descriptor info.
@@ -310,9 +315,10 @@ ath_tx_chaindesclist(struct ath_softc *sc, struct ath_buf *bf)
for (i = 0; i < bf->bf_nseg; i++, ds++) {
ds->ds_data = bf->bf_segs[i].ds_addr;
if (i == bf->bf_nseg - 1)
- ds->ds_link = 0;
+ ath_hal_settxdesclink(ah, ds, 0);
else
- ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
+ ath_hal_settxdesclink(ah, ds,
+ bf->bf_daddr + dd->dd_descsize * (i + 1));
ath_hal_filltxdesc(ah, ds
, bf->bf_segs[i].ds_len /* segment length */
, i == 0 /* first segment */
@@ -340,6 +346,11 @@ ath_tx_chaindesclist_subframe(struct ath_softc *sc, struct ath_buf *bf)
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds, *ds0;
int i;
+ /*
+ * XXX There's txdma and txdma_mgmt; the descriptor
+ * sizes must match.
+ */
+ struct ath_descdma *dd = &sc->sc_txdma;
ds0 = ds = bf->bf_desc;
@@ -350,9 +361,10 @@ ath_tx_chaindesclist_subframe(struct ath_softc *sc, struct ath_buf *bf)
for (i = 0; i < bf->bf_nseg; i++, ds++) {
ds->ds_data = bf->bf_segs[i].ds_addr;
if (i == bf->bf_nseg - 1)
- ds->ds_link = 0;
+ ath_hal_settxdesclink(ah, ds, 0);
else
- ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
+ ath_hal_settxdesclink(ah, ds,
+ bf->bf_daddr + dd->dd_descsize * (i + 1));
/*
* This performs the setup for an aggregate frame.
@@ -382,6 +394,50 @@ ath_tx_chaindesclist_subframe(struct ath_softc *sc, struct ath_buf *bf)
}
/*
+ * Set the rate control fields in the given descriptor based on
+ * the bf_state fields and node state.
+ *
+ * The bfs fields should already be set with the relevant rate
+ * control information, including whether MRR is to be enabled.
+ *
+ * Since the FreeBSD HAL currently sets up the first TX rate
+ * in ath_hal_setuptxdesc(), this will setup the MRR
+ * conditionally for the pre-11n chips, and call ath_buf_set_rate
+ * unconditionally for 11n chips. These require the 11n rate
+ * scenario to be set if MCS rates are enabled, so it's easier
+ * to just always call it. The caller can then only set rates 2, 3
+ * and 4 if multi-rate retry is needed.
+ */
+static void
+ath_tx_set_ratectrl(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_buf *bf)
+{
+ struct ath_rc_series *rc = bf->bf_state.bfs_rc;
+
+ /* If mrr is disabled, blank tries 1, 2, 3 */
+ if (! bf->bf_state.bfs_ismrr)
+ rc[1].tries = rc[2].tries = rc[3].tries = 0;
+
+ /*
+ * Always call - that way a retried descriptor will
+ * have the MRR fields overwritten.
+ *
+ * XXX TODO: see if this is really needed - setting up
+ * the first descriptor should set the MRR fields to 0
+ * for us anyway.
+ */
+ if (ath_tx_is_11n(sc)) {
+ ath_buf_set_rate(sc, ni, bf);
+ } else {
+ ath_hal_setupxtxdesc(sc->sc_ah, bf->bf_desc
+ , rc[1].ratecode, rc[1].tries
+ , rc[2].ratecode, rc[2].tries
+ , rc[3].ratecode, rc[3].tries
+ );
+ }
+}
+
+/*
* Setup segments+descriptors for an 11n aggregate.
* bf_first is the first buffer in the aggregate.
* The descriptor list must already been linked together using
@@ -414,7 +470,8 @@ ath_tx_setds_11n(struct ath_softc *sc, struct ath_buf *bf_first)
* to the beginning descriptor of this frame.
*/
if (bf_prev != NULL)
- bf_prev->bf_lastds->ds_link = bf->bf_daddr;
+ ath_hal_settxdesclink(sc->sc_ah, bf_prev->bf_lastds,
+ bf->bf_daddr);
/* Save a copy so we can link the next descriptor in */
bf_prev = bf;
@@ -439,13 +496,6 @@ ath_tx_setds_11n(struct ath_softc *sc, struct ath_buf *bf_first)
bf_first->bf_state.bfs_ctsduration);
/*
- * Setup the last descriptor in the list.
- * bf_prev points to the last; bf is NULL here.
- */
- ath_hal_setuplasttxdesc(sc->sc_ah, bf_prev->bf_desc,
- bf_first->bf_desc);
-
- /*
* Set the first descriptor bf_lastds field to point to
* the last descriptor in the last subframe, that's where
* the status update will occur.
@@ -458,6 +508,21 @@ ath_tx_setds_11n(struct ath_softc *sc, struct ath_buf *bf_first)
*/
bf_first->bf_last = bf_prev;
+ /*
+ * setup first desc with rate and aggr info
+ */
+ ath_tx_set_ratectrl(sc, bf_first->bf_node, bf_first);
+
+ /*
+ * Setup the last descriptor in the list.
+ *
+ * bf_first->bf_lastds already points to it; the rate
+ * control information needs to be squirreled away here
+ * as well ans clearing the moreaggr/paddelim fields.
+ */
+ ath_hal_setuplasttxdesc(sc->sc_ah, bf_first->bf_lastds,
+ bf_first->bf_desc);
+
DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: end\n", __func__);
}
@@ -482,7 +547,7 @@ ath_tx_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq,
*txq->axq_link = bf->bf_daddr;
}
ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- txq->axq_link = &bf->bf_lastds->ds_link;
+ ath_hal_gettxdesclinkptr(sc->sc_ah, bf->bf_lastds, &txq->axq_link);
}
/*
@@ -616,7 +681,7 @@ ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
#endif /* IEEE80211_SUPPORT_TDMA */
if (bf->bf_state.bfs_aggr)
txq->axq_aggr_depth++;
- txq->axq_link = &bf->bf_lastds->ds_link;
+ ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
ath_hal_txstart(ah, txq->axq_qnum);
}
}
@@ -626,8 +691,8 @@ ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
*
* This must be called whether the queue is empty or not.
*/
-void
-ath_txq_restart_dma(struct ath_softc *sc, struct ath_txq *txq)
+static void
+ath_legacy_tx_dma_restart(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf, *bf_last;
@@ -645,7 +710,7 @@ ath_txq_restart_dma(struct ath_softc *sc, struct ath_txq *txq)
return;
ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- txq->axq_link = &bf_last->bf_lastds->ds_link;
+ ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
ath_hal_txstart(ah, txq->axq_qnum);
}
@@ -655,7 +720,8 @@ ath_txq_restart_dma(struct ath_softc *sc, struct ath_txq *txq)
* The relevant hardware txq should be locked.
*/
static void
-ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
+ath_legacy_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
{
ATH_TXQ_LOCK_ASSERT(txq);
@@ -988,11 +1054,12 @@ ath_tx_set_rtscts(struct ath_softc *sc, struct ath_buf *bf)
/*
* Must disable multi-rate retry when using RTS/CTS.
- * XXX TODO: only for pre-11n NICs.
*/
- bf->bf_state.bfs_ismrr = 0;
- bf->bf_state.bfs_try0 =
- bf->bf_state.bfs_rc[0].tries = ATH_TXMGTTRY; /* XXX ew */
+ if (!sc->sc_mrrprot) {
+ bf->bf_state.bfs_ismrr = 0;
+ bf->bf_state.bfs_try0 =
+ bf->bf_state.bfs_rc[0].tries = ATH_TXMGTTRY; /* XXX ew */
+ }
}
/*
@@ -1025,7 +1092,9 @@ ath_tx_setds(struct ath_softc *sc, struct ath_buf *bf)
bf->bf_lastds = ds;
bf->bf_last = bf;
- /* XXX TODO: Setup descriptor chain */
+ /* Set rate control and descriptor chain for this frame */
+ ath_tx_set_ratectrl(sc, bf->bf_node, bf);
+ ath_tx_chaindesclist(sc, bf);
}
/*
@@ -1074,50 +1143,6 @@ ath_tx_do_ratelookup(struct ath_softc *sc, struct ath_buf *bf)
}
/*
- * Set the rate control fields in the given descriptor based on
- * the bf_state fields and node state.
- *
- * The bfs fields should already be set with the relevant rate
- * control information, including whether MRR is to be enabled.
- *
- * Since the FreeBSD HAL currently sets up the first TX rate
- * in ath_hal_setuptxdesc(), this will setup the MRR
- * conditionally for the pre-11n chips, and call ath_buf_set_rate
- * unconditionally for 11n chips. These require the 11n rate
- * scenario to be set if MCS rates are enabled, so it's easier
- * to just always call it. The caller can then only set rates 2, 3
- * and 4 if multi-rate retry is needed.
- */
-static void
-ath_tx_set_ratectrl(struct ath_softc *sc, struct ieee80211_node *ni,
- struct ath_buf *bf)
-{
- struct ath_rc_series *rc = bf->bf_state.bfs_rc;
-
- /* If mrr is disabled, blank tries 1, 2, 3 */
- if (! bf->bf_state.bfs_ismrr)
- rc[1].tries = rc[2].tries = rc[3].tries = 0;
-
- /*
- * Always call - that way a retried descriptor will
- * have the MRR fields overwritten.
- *
- * XXX TODO: see if this is really needed - setting up
- * the first descriptor should set the MRR fields to 0
- * for us anyway.
- */
- if (ath_tx_is_11n(sc)) {
- ath_buf_set_rate(sc, ni, bf);
- } else {
- ath_hal_setupxtxdesc(sc->sc_ah, bf->bf_desc
- , rc[1].ratecode, rc[1].tries
- , rc[2].ratecode, rc[2].tries
- , rc[3].ratecode, rc[3].tries
- );
- }
-}
-
-/*
* Transmit the given frame to the hardware.
*
* The frame must already be setup; rate control must already have
@@ -1142,8 +1167,6 @@ ath_tx_xmit_normal(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
- ath_tx_set_ratectrl(sc, bf->bf_node, bf);
- ath_tx_chaindesclist(sc, bf);
/* Hand off to hardware */
ath_tx_handoff(sc, txq, bf);
@@ -2391,8 +2414,6 @@ ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_buf *bf)
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
- ath_tx_set_ratectrl(sc, bf->bf_node, bf);
- ath_tx_chaindesclist(sc, bf);
/* Statistics */
sc->sc_aggr_stats.aggr_low_hwq_single_pkt++;
@@ -3834,7 +3855,6 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
struct ath_buf *bf;
struct ath_txq *txq = sc->sc_ac2q[tid->ac];
struct ieee80211_tx_ampdu *tap;
- struct ieee80211_node *ni = &an->an_node;
ATH_AGGR_STATUS status;
ath_bufhead bf_q;
@@ -3882,9 +3902,7 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
- ath_tx_chaindesclist(sc, bf);
ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
- ath_tx_set_ratectrl(sc, ni, bf);
sc->sc_aggr_stats.aggr_nonbaw_pkt++;
@@ -3942,9 +3960,7 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
"%s: single-frame aggregate\n", __func__);
bf->bf_state.bfs_aggr = 0;
ath_tx_setds(sc, bf);
- ath_tx_chaindesclist(sc, bf);
ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
- ath_tx_set_ratectrl(sc, ni, bf);
if (status == ATH_AGGR_BAW_CLOSED)
sc->sc_aggr_stats.aggr_baw_closed_single_pkt++;
else
@@ -3979,10 +3995,6 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
*/
ath_tx_setds_11n(sc, bf);
- /*
- * setup first desc with rate and aggr info
- */
- ath_tx_set_ratectrl(sc, ni, bf);
}
queuepkt:
//txq = bf->bf_state.bfs_txq;
@@ -4022,7 +4034,6 @@ ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an,
{
struct ath_buf *bf;
struct ath_txq *txq = sc->sc_ac2q[tid->ac];
- struct ieee80211_node *ni = &an->an_node;
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: node %p: TID %d: called\n",
__func__, an, tid->tid);
@@ -4071,8 +4082,6 @@ ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an,
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
- ath_tx_chaindesclist(sc, bf);
- ath_tx_set_ratectrl(sc, ni, bf);
/* Track outstanding buffer count to hardware */
/* aggregates are "one" buffer */
@@ -4450,3 +4459,40 @@ ath_addba_response_timeout(struct ieee80211_node *ni,
ath_tx_tid_resume(sc, atid);
ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
}
+
+static int
+ath_legacy_dma_txsetup(struct ath_softc *sc)
+{
+
+ /* nothing new needed */
+ return (0);
+}
+
+static int
+ath_legacy_dma_txteardown(struct ath_softc *sc)
+{
+
+ /* nothing new needed */
+ return (0);
+}
+
+void
+ath_xmit_setup_legacy(struct ath_softc *sc)
+{
+ /*
+ * For now, just set the descriptor length to sizeof(ath_desc);
+ * worry about extracting the real length out of the HAL later.
+ */
+ sc->sc_tx_desclen = sizeof(struct ath_desc);
+ sc->sc_tx_statuslen = 0;
+ sc->sc_tx_nmaps = 1; /* only one buffer per TX desc */
+
+ sc->sc_tx.xmit_setup = ath_legacy_dma_txsetup;
+ sc->sc_tx.xmit_teardown = ath_legacy_dma_txteardown;
+ sc->sc_tx.xmit_attach_comp_func = ath_legacy_attach_comp_func;
+
+ sc->sc_tx.xmit_dma_restart = ath_legacy_tx_dma_restart;
+ sc->sc_tx.xmit_handoff = ath_legacy_xmit_handoff;
+ sc->sc_tx.xmit_processq = ath_legacy_tx_processq;
+ sc->sc_tx.xmit_drainq = ath_legacy_tx_draintxq;
+}
diff --git a/sys/dev/ath/if_ath_tx.h b/sys/dev/ath/if_ath_tx.h
index 958acf9..4ac4589 100644
--- a/sys/dev/ath/if_ath_tx.h
+++ b/sys/dev/ath/if_ath_tx.h
@@ -79,7 +79,6 @@
#define BAW_WITHIN(_start, _bawsz, _seqno) \
((((_seqno) - (_start)) & 4095) < (_bawsz))
-extern void ath_txq_restart_dma(struct ath_softc *sc, struct ath_txq *txq);
extern void ath_freetx(struct mbuf *m);
extern void ath_tx_node_flush(struct ath_softc *sc, struct ath_node *an);
extern void ath_tx_txq_drain(struct ath_softc *sc, struct ath_txq *txq);
@@ -124,4 +123,22 @@ extern void ath_bar_response(struct ieee80211_node *ni,
extern void ath_addba_response_timeout(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap);
+/*
+ * Setup path
+ */
+#define ath_txdma_setup(_sc) \
+ (_sc)->sc_tx.xmit_setup(_sc)
+#define ath_txdma_teardown(_sc) \
+ (_sc)->sc_tx.xmit_teardown(_sc)
+#define ath_txq_restart_dma(_sc, _txq) \
+ (_sc)->sc_tx.xmit_dma_restart((_sc), (_txq))
+#define ath_tx_handoff(_sc, _txq, _bf) \
+ (_sc)->sc_tx.xmit_handoff((_sc), (_txq), (_bf))
+#define ath_tx_draintxq(_sc, _txq) \
+ (_sc)->sc_tx.xmit_drainq((_sc), (_txq))
+#define ath_tx_processq(_sc, _txq, _dosched) \
+ (_sc)->sc_tx.xmit_processq((_sc), (_txq), (_dosched))
+
+extern void ath_xmit_setup_legacy(struct ath_softc *sc);
+
#endif
diff --git a/sys/dev/ath/if_ath_tx_edma.c b/sys/dev/ath/if_ath_tx_edma.c
new file mode 100644
index 0000000..5991d1c
--- /dev/null
+++ b/sys/dev/ath/if_ath_tx_edma.c
@@ -0,0 +1,311 @@
+/*-
+ * Copyright (c) 2012 Adrian Chadd <adrian@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h> /* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tsf.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_sysctl.h>
+#include <dev/ath/if_ath_led.h>
+#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_beacon.h>
+#include <dev/ath/if_athdfs.h>
+
+#ifdef ATH_TX99_DIAG
+#include <dev/ath/ath_tx99/ath_tx99.h>
+#endif
+
+#include <dev/ath/if_ath_tx_edma.h>
+
+/*
+ * some general macros
+ */
+#define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1)
+#define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1)
+
+/*
+ * XXX doesn't belong here, and should be tunable
+ */
+#define ATH_TXSTATUS_RING_SIZE 512
+
+MALLOC_DECLARE(M_ATHDEV);
+
+/*
+ * Re-initialise the DMA FIFO with the current contents of
+ * said FIFO.
+ *
+ * This should only be called as part of the chip reset path, as it
+ * assumes the FIFO is currently empty.
+ *
+ * TODO: verify that a cold/warm reset does clear the TX FIFO, so
+ * writing in a partially-filled FIFO will not cause double-entries
+ * to appear.
+ */
+static void
+ath_edma_dma_restart(struct ath_softc *sc, struct ath_txq *txq)
+{
+
+ device_printf(sc->sc_dev, "%s: called: txq=%p, qnum=%d\n",
+ __func__,
+ txq,
+ txq->axq_qnum);
+}
+
+/*
+ * Handoff this frame to the hardware.
+ *
+ * For the multicast queue, this will treat it as a software queue
+ * and append it to the list, after updating the MORE_DATA flag
+ * in the previous frame. The cabq processing code will ensure
+ * that the queue contents gets transferred over.
+ *
+ * For the hardware queues, this will queue a frame to the queue
+ * like before, then populate the FIFO from that. Since the
+ * EDMA hardware has 8 FIFO slots per TXQ, this ensures that
+ * frames such as management frames don't get prematurely dropped.
+ *
+ * This does imply that a similar flush-hwq-to-fifoq method will
+ * need to be called from the processq function, before the
+ * per-node software scheduler is called.
+ */
+static void
+ath_edma_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+
+ device_printf(sc->sc_dev, "%s: called; bf=%p, txq=%p, qnum=%d\n",
+ __func__,
+ bf,
+ txq,
+ txq->axq_qnum);
+
+ /*
+ * XXX For now this is a placeholder; free the buffer
+ * and inform the stack that the TX failed.
+ */
+ ath_tx_default_comp(sc, bf, 1);
+}
+
+static int
+ath_edma_setup_txfifo(struct ath_softc *sc, int qnum)
+{
+ struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum];
+
+ te->m_fifo = malloc(sizeof(struct ath_buf *) * HAL_TXFIFO_DEPTH,
+ M_ATHDEV,
+ M_NOWAIT | M_ZERO);
+ if (te->m_fifo == NULL) {
+ device_printf(sc->sc_dev, "%s: malloc failed\n",
+ __func__);
+ return (-ENOMEM);
+ }
+
+ /*
+ * Set initial "empty" state.
+ */
+ te->m_fifo_head = te->m_fifo_tail = te->m_fifo_depth = 0;
+
+ return (0);
+}
+
+static int
+ath_edma_free_txfifo(struct ath_softc *sc, int qnum)
+{
+ struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum];
+
+ /* XXX TODO: actually deref the ath_buf entries? */
+ free(te->m_fifo, M_ATHDEV);
+ return (0);
+}
+
+static int
+ath_edma_dma_txsetup(struct ath_softc *sc)
+{
+ int error;
+ int i;
+
+ error = ath_descdma_alloc_desc(sc, &sc->sc_txsdma,
+ NULL, "txcomp", sc->sc_tx_statuslen, ATH_TXSTATUS_RING_SIZE);
+ if (error != 0)
+ return (error);
+
+ ath_hal_setuptxstatusring(sc->sc_ah,
+ (void *) sc->sc_txsdma.dd_desc,
+ sc->sc_txsdma.dd_desc_paddr,
+ ATH_TXSTATUS_RING_SIZE);
+
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ ath_edma_setup_txfifo(sc, i);
+ }
+
+
+ return (0);
+}
+
+static int
+ath_edma_dma_txteardown(struct ath_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ ath_edma_free_txfifo(sc, i);
+ }
+
+ ath_descdma_cleanup(sc, &sc->sc_txsdma, NULL);
+ return (0);
+}
+
+static int
+ath_edma_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
+{
+
+ return (0);
+}
+
+static void
+ath_edma_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+{
+
+}
+
+static void
+ath_edma_tx_proc(void *arg, int npending)
+{
+ struct ath_softc *sc = (struct ath_softc *) arg;
+
+ device_printf(sc->sc_dev, "%s: called, npending=%d\n",
+ __func__, npending);
+}
+
+static void
+ath_edma_attach_comp_func(struct ath_softc *sc)
+{
+
+ TASK_INIT(&sc->sc_txtask, 0, ath_edma_tx_proc, sc);
+}
+
+void
+ath_xmit_setup_edma(struct ath_softc *sc)
+{
+
+ /* Fetch EDMA field and buffer sizes */
+ (void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen);
+ (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen);
+ (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps);
+
+ device_printf(sc->sc_dev, "TX descriptor length: %d\n",
+ sc->sc_tx_desclen);
+ device_printf(sc->sc_dev, "TX status length: %d\n",
+ sc->sc_tx_statuslen);
+ device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n",
+ sc->sc_tx_nmaps);
+
+ sc->sc_tx.xmit_setup = ath_edma_dma_txsetup;
+ sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown;
+ sc->sc_tx.xmit_attach_comp_func = ath_edma_attach_comp_func;
+
+ sc->sc_tx.xmit_dma_restart = ath_edma_dma_restart;
+ sc->sc_tx.xmit_handoff = ath_edma_xmit_handoff;
+ sc->sc_tx.xmit_processq = ath_edma_tx_processq;
+ sc->sc_tx.xmit_drainq = ath_edma_tx_draintxq;
+}
diff --git a/sys/dev/ath/if_ath_tx_edma.h b/sys/dev/ath/if_ath_tx_edma.h
new file mode 100644
index 0000000..d4975a6
--- /dev/null
+++ b/sys/dev/ath/if_ath_tx_edma.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2012 Adrian Chadd <adrian@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+#ifndef __IF_ATH_TX_EDMA_H__
+#define __IF_ATH_TX_EDMA_H__
+
+extern void ath_xmit_setup_edma(struct ath_softc *sc);
+
+#endif
diff --git a/sys/dev/ath/if_ath_tx_ht.c b/sys/dev/ath/if_ath_tx_ht.c
index e9ec632..6495a04 100644
--- a/sys/dev/ath/if_ath_tx_ht.c
+++ b/sys/dev/ath/if_ath_tx_ht.c
@@ -511,6 +511,8 @@ ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
series[i].RateFlags |= HAL_RATESERIES_HALFGI;
series[i].Rate = rt->info[rc[i].rix].rateCode;
+ series[i].RateIndex = rc[i].rix;
+ series[i].tx_power_cap = 0x3f; /* XXX for now */
/*
* PktDuration doesn't include slot, ACK, RTS, etc timing -
@@ -558,14 +560,12 @@ ath_rateseries_print(struct ath_softc *sc, HAL_11N_RATE_SERIES *series)
* This isn't useful for sending beacon frames, which has different needs
* wrt what's passed into the rate scenario function.
*/
-
void
ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni,
struct ath_buf *bf)
{
HAL_11N_RATE_SERIES series[4];
struct ath_desc *ds = bf->bf_desc;
- struct ath_desc *lastds = NULL;
struct ath_hal *ah = sc->sc_ah;
int is_pspoll = (bf->bf_state.bfs_atype == HAL_PKT_TYPE_PSPOLL);
int ctsrate = bf->bf_state.bfs_ctsrate;
@@ -576,13 +576,6 @@ ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni,
ath_rateseries_setup(sc, ni, bf, series);
- /* Enforce AR5416 aggregate limit - can't do RTS w/ an agg frame > 8k */
-
- /* Enforce RTS and CTS are mutually exclusive */
-
- /* Get a pointer to the last tx descriptor in the list */
- lastds = bf->bf_lastds;
-
#if 0
printf("pktlen: %d; flags 0x%x\n", pktlen, flags);
ath_rateseries_print(sc, series);
@@ -600,21 +593,6 @@ ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni,
4, /* number of series */
flags);
- /* Setup the last descriptor in the chain */
- /*
- * XXX Why is this done here, and not in the upper layer?
- * The rate control code stores a copy of the RC info in
- * the last descriptor as well as the first, then uses
- * the shadow copy in the last descriptor to see what the RC
- * decisions were. I'm not sure why; perhaps earlier hardware
- * overwrote the first descriptor contents.
- *
- * In the 802.11n case, it also clears the moreaggr/delim
- * fields. Again, this should be done by the caller of
- * ath_buf_set_rate().
- */
- ath_hal_setuplasttxdesc(ah, lastds, ds);
-
/* Set burst duration */
/*
* This is only required when doing 11n burst, not aggregation
diff --git a/sys/dev/ath/if_athioctl.h b/sys/dev/ath/if_athioctl.h
index 71813ae..514e5a7 100644
--- a/sys/dev/ath/if_athioctl.h
+++ b/sys/dev/ath/if_athioctl.h
@@ -161,7 +161,9 @@ struct ath_stats {
u_int32_t ast_tx_aggr_ok; /* aggregate TX ok */
u_int32_t ast_tx_aggr_fail; /* aggregate TX failed */
u_int32_t ast_tx_mcastq_overflow; /* multicast queue overflow */
- u_int32_t ast_pad[1];
+ u_int32_t ast_rx_keymiss;
+
+ u_int32_t ast_pad[16];
};
#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)
@@ -184,6 +186,53 @@ struct ath_diag {
#define SIOCGATHDIAG _IOWR('i', 138, struct ath_diag)
#define SIOCGATHPHYERR _IOWR('i', 140, struct ath_diag)
+
+/*
+ * The rate control ioctl has to support multiple potential rate
+ * control classes. For now, instead of trying to support an
+ * abstraction for this in the API, let's just use a TLV
+ * representation for the payload and let userspace sort it out.
+ */
+struct ath_rateioctl_tlv {
+ uint16_t tlv_id;
+ uint16_t tlv_len; /* length excluding TLV header */
+};
+
+/*
+ * This is purely the six byte MAC address.
+ */
+#define ATH_RATE_TLV_MACADDR 0xaab0
+
+/*
+ * The rate control modules may decide to push a mapping table
+ * of rix -> net80211 ratecode as part of the update.
+ */
+#define ATH_RATE_TLV_RATETABLE_NENTRIES 64
+struct ath_rateioctl_rt {
+ uint16_t nentries;
+ uint16_t pad[1];
+ uint8_t ratecode[ATH_RATE_TLV_RATETABLE_NENTRIES];
+};
+#define ATH_RATE_TLV_RATETABLE 0xaab1
+
+/*
+ * This is the sample node statistics structure.
+ * More in ath_rate/sample/sample.h.
+ */
+#define ATH_RATE_TLV_SAMPLENODE 0xaab2
+
+struct ath_rateioctl {
+ char if_name[IFNAMSIZ]; /* if name */
+ union {
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
+ uint64_t pad;
+ } is_u;
+ uint32_t len;
+ caddr_t buf;
+};
+#define SIOCGATHNODERATESTATS _IOWR('i', 149, struct ath_rateioctl)
+#define SIOCGATHRATESTATS _IOWR('i', 150, struct ath_rateioctl)
+
/*
* Radio capture format.
*/
diff --git a/sys/dev/ath/if_athrate.h b/sys/dev/ath/if_athrate.h
index 10f6040..d07c9ca 100644
--- a/sys/dev/ath/if_athrate.h
+++ b/sys/dev/ath/if_athrate.h
@@ -150,4 +150,16 @@ struct ath_buf;
void ath_rate_tx_complete(struct ath_softc *, struct ath_node *,
const struct ath_rc_series *, const struct ath_tx_status *,
int pktlen, int nframes, int nbad);
+
+/*
+ * Fetch the global rate control statistics.
+ */
+int ath_rate_fetch_stats(struct ath_softc *sc, struct ath_rateioctl *rs);
+
+/*
+ * Fetch the per-node statistics.
+ */
+int ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *rs);
+
#endif /* _ATH_RATECTRL_H_ */
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index 7370e01..94097ad 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -189,6 +189,7 @@ struct ath_buf {
TAILQ_ENTRY(ath_buf) bf_list;
struct ath_buf * bf_next; /* next buffer in the aggregate */
int bf_nseg;
+ HAL_STATUS bf_rxstatus;
uint16_t bf_flags; /* status flags (below) */
struct ath_desc *bf_desc; /* virtual addr of desc */
struct ath_desc_status bf_status; /* tx/rx status */
@@ -276,6 +277,7 @@ typedef TAILQ_HEAD(ath_bufhead_s, ath_buf) ath_bufhead;
struct ath_descdma {
const char* dd_name;
struct ath_desc *dd_desc; /* descriptors */
+ int dd_descsize; /* size of single descriptor */
bus_addr_t dd_desc_paddr; /* physical addr of dd_desc */
bus_size_t dd_desc_len; /* size of dd_desc */
bus_dma_segment_t dd_dseg;
@@ -395,6 +397,30 @@ struct ath_rx_edma {
struct mbuf *m_rxpending;
};
+struct ath_tx_edma_fifo {
+ struct ath_buf **m_fifo;
+ int m_fifolen;
+ int m_fifo_head;
+ int m_fifo_tail;
+ int m_fifo_depth;
+};
+
+struct ath_tx_methods {
+ int (*xmit_setup)(struct ath_softc *sc);
+ int (*xmit_teardown)(struct ath_softc *sc);
+ void (*xmit_attach_comp_func)(struct ath_softc *sc);
+
+ void (*xmit_dma_restart)(struct ath_softc *sc,
+ struct ath_txq *txq);
+ void (*xmit_handoff)(struct ath_softc *sc,
+ struct ath_txq *txq, struct ath_buf *bf);
+
+ void (*xmit_drainq)(struct ath_softc *sc,
+ struct ath_txq *txq);
+ int (*xmit_processq)(struct ath_softc *sc,
+ struct ath_txq *txq, int dosched);
+};
+
struct ath_softc {
struct ifnet *sc_ifp; /* interface common */
struct ath_stats sc_stats; /* interface statistics */
@@ -409,7 +435,10 @@ struct ath_softc {
uint32_t sc_bssidmask; /* bssid mask */
struct ath_rx_methods sc_rx;
- struct ath_rx_edma sc_rxedma[2]; /* HP/LP queues */
+ struct ath_rx_edma sc_rxedma[HAL_NUM_RX_QUEUES]; /* HP/LP queues */
+ struct ath_tx_methods sc_tx;
+ struct ath_tx_edma_fifo sc_txedma[HAL_NUM_TX_QUEUES];
+
int sc_rx_statuslen;
int sc_tx_desclen;
int sc_tx_statuslen;
@@ -425,6 +454,8 @@ struct ath_softc {
struct mtx sc_mtx; /* master lock (recursive) */
struct mtx sc_pcu_mtx; /* PCU access mutex */
char sc_pcu_mtx_name[32];
+ struct mtx sc_rx_mtx; /* RX access mutex */
+ char sc_rx_mtx_name[32];
struct taskqueue *sc_tq; /* private task queue */
struct ath_hal *sc_ah; /* Atheros HAL */
struct ath_ratectrl *sc_rc; /* tx rate control support */
@@ -432,6 +463,7 @@ struct ath_softc {
void (*sc_setdefantenna)(struct ath_softc *, u_int);
unsigned int sc_invalid : 1,/* disable hardware accesses */
sc_mrretry : 1,/* multi-rate retry support */
+ sc_mrrprot : 1,/* MRR + protection support */
sc_softled : 1,/* enable LED gpio status */
sc_hardled : 1,/* enable MAC LED status */
sc_splitmic : 1,/* split TKIP MIC keys */
@@ -546,6 +578,7 @@ struct ath_softc {
int sc_txbuf_cnt; /* how many buffers avail */
struct ath_descdma sc_txdma_mgmt; /* mgmt TX descriptors */
ath_bufhead sc_txbuf_mgmt; /* mgmt transmit buffer */
+ struct ath_descdma sc_txsdma; /* EDMA TX status desc's */
struct mtx sc_txbuflock; /* txbuf lock */
char sc_txname[12]; /* e.g. "ath0_buf" */
u_int sc_txqsetup; /* h/w queues setup */
@@ -554,6 +587,11 @@ struct ath_softc {
struct ath_txq *sc_ac2q[5]; /* WME AC -> h/w q map */
struct task sc_txtask; /* tx int processing */
struct task sc_txqtask; /* tx proc processing */
+
+ struct ath_descdma sc_txcompdma; /* TX EDMA completion */
+ struct mtx sc_txcomplock; /* TX EDMA completion lock */
+ char sc_txcompname[12]; /* eg ath0_txcomp */
+
int sc_wd_timer; /* count down for wd timer */
struct callout sc_wd_ch; /* tx watchdog timer */
struct ath_tx_radiotap_header sc_tx_th;
@@ -696,6 +734,28 @@ struct ath_softc {
#define ATH_PCU_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_pcu_mtx, \
MA_NOTOWNED)
+/*
+ * The RX lock is primarily a(nother) workaround to ensure that the
+ * RX FIFO/list isn't modified by various execution paths.
+ * Even though RX occurs in a single context (the ath taskqueue), the
+ * RX path can be executed via various reset/channel change paths.
+ */
+#define ATH_RX_LOCK_INIT(_sc) do {\
+ snprintf((_sc)->sc_rx_mtx_name, \
+ sizeof((_sc)->sc_rx_mtx_name), \
+ "%s RX lock", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_rx_mtx, (_sc)->sc_rx_mtx_name, \
+ NULL, MTX_DEF); \
+ } while (0)
+#define ATH_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_rx_mtx)
+#define ATH_RX_LOCK(_sc) mtx_lock(&(_sc)->sc_rx_mtx)
+#define ATH_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_rx_mtx)
+#define ATH_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_rx_mtx, \
+ MA_OWNED)
+#define ATH_RX_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_rx_mtx, \
+ MA_NOTOWNED)
+
#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i))
#define ATH_TXBUF_LOCK_INIT(_sc) do { \
@@ -709,6 +769,19 @@ struct ath_softc {
#define ATH_TXBUF_LOCK_ASSERT(_sc) \
mtx_assert(&(_sc)->sc_txbuflock, MA_OWNED)
+#define ATH_TXSTATUS_LOCK_INIT(_sc) do { \
+ snprintf((_sc)->sc_txcompname, sizeof((_sc)->sc_txcompname), \
+ "%s_buf", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_txcomplock, (_sc)->sc_txcompname, NULL, \
+ MTX_DEF); \
+} while (0)
+#define ATH_TXSTATUS_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_txcomplock)
+#define ATH_TXSTATUS_LOCK(_sc) mtx_lock(&(_sc)->sc_txcomplock)
+#define ATH_TXSTATUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_txcomplock)
+#define ATH_TXSTATUS_LOCK_ASSERT(_sc) \
+ mtx_assert(&(_sc)->sc_txcomplock, MA_OWNED)
+
int ath_attach(u_int16_t, struct ath_softc *);
int ath_detach(struct ath_softc *);
void ath_resume(struct ath_softc *);
@@ -1042,6 +1115,15 @@ void ath_intr(void *);
((*(_ah)->ah_getTxIntrQueue)((_ah), (_txqs)))
#define ath_hal_gettxcompletionrates(_ah, _ds, _rates, _tries) \
((*(_ah)->ah_getTxCompletionRates)((_ah), (_ds), (_rates), (_tries)))
+#define ath_hal_settxdesclink(_ah, _ds, _link) \
+ ((*(_ah)->ah_setTxDescLink)((_ah), (_ds), (_link)))
+#define ath_hal_gettxdesclink(_ah, _ds, _link) \
+ ((*(_ah)->ah_getTxDescLink)((_ah), (_ds), (_link)))
+#define ath_hal_gettxdesclinkptr(_ah, _ds, _linkptr) \
+ ((*(_ah)->ah_getTxDescLinkPtr)((_ah), (_ds), (_linkptr)))
+#define ath_hal_setuptxstatusring(_ah, _tsstart, _tspstart, _size) \
+ ((*(_ah)->ah_setupTxStatusRing)((_ah), (_tsstart), (_tspstart), \
+ (_size)))
#define ath_hal_setupfirsttxdesc(_ah, _ds, _aggrlen, _flags, _txpower, \
_txr0, _txtr0, _antm, _rcr, _rcd) \
@@ -1060,7 +1142,7 @@ void ath_intr(void *);
(_series), (_ns), (_flags)))
#define ath_hal_set11n_aggr_first(_ah, _ds, _len, _num) \
- ((*(_ah)->ah_set11nAggrFirst)((_ah), (_ds), (_len), (_num)))
+ ((*(_ah)->ah_set11nAggrFirst)((_ah), (_ds), (_len)))
#define ath_hal_set11naggrmiddle(_ah, _ds, _num) \
((*(_ah)->ah_set11nAggrMiddle)((_ah), (_ds), (_num)))
#define ath_hal_set11n_aggr_last(_ah, _ds) \
OpenPOWER on IntegriCloud