From 19e4d682fca010ef72e0a304335910f670c2268a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 22 Jan 2011 20:52:56 +0100 Subject: [PATCH] carl9170 firmware: per-vif tx sequence counter mac80211 will properly assign sequence numbers to QoS-data frames but cannot do so correctly for non-QoS-data and management frames because beacons need them from that counter as well and mac80211 cannot guarantee proper sequencing. Signed-off-by: Christian Lamparter --- carlfw/include/carl9170.h | 3 +++ carlfw/include/fwdsc.h | 1 + carlfw/include/wl.h | 6 +++--- carlfw/src/cmd.c | 2 +- carlfw/src/fw.c | 4 ++++ carlfw/src/wlan.c | 26 +++++++++++++++++++++++--- include/shared/fwdesc.h | 11 +++++++++++ include/shared/version.h | 2 +- include/shared/wlan.h | 3 ++- tools/src/fwinfo.c | 10 ++++++++++ 10 files changed, 59 insertions(+), 9 deletions(-) diff --git a/carlfw/include/carl9170.h b/carlfw/include/carl9170.h index b57993d..29e1e29 100644 --- a/carlfw/include/carl9170.h +++ b/carlfw/include/carl9170.h @@ -114,6 +114,9 @@ struct firmware_context_struct { unsigned int rx_total; unsigned int rx_overruns; + /* tx sequence control counters */ + unsigned int sequence[CARL9170_INTF_NUM]; + #ifdef CONFIG_CARL9170FW_TX_AMPDU /* tx aggregate scheduling */ struct carl9170_tx_superframe *ampdu_prev[__AR9170_NUM_TX_QUEUES]; diff --git a/carlfw/include/fwdsc.h b/carlfw/include/fwdsc.h index efab7fc..d702795 100644 --- a/carlfw/include/fwdsc.h +++ b/carlfw/include/fwdsc.h @@ -30,6 +30,7 @@ struct carl9170_firmware_descriptor { struct carl9170fw_otus_desc otus; + struct carl9170fw_txsq_desc txsq; struct carl9170fw_motd_desc motd; struct carl9170fw_dbg_desc dbg; struct carl9170fw_last_desc last; diff --git a/carlfw/include/wl.h b/carlfw/include/wl.h index 8c06f6a..577fd05 100644 --- a/carlfw/include/wl.h +++ b/carlfw/include/wl.h @@ -261,9 +261,9 @@ void wlan_timer(void); void handle_wlan(void); void wlan_cab_flush_queue(const unsigned int vif); -void wlan_cab_modify_dtim_beacon(const unsigned int vif, - const unsigned int bcn_addr, - const unsigned int bcn_len); +void wlan_modify_beacon(const unsigned int vif, + const unsigned int bcn_addr, + const unsigned int bcn_len); static inline void wlan_prepare_wol(void) { diff --git a/carlfw/src/cmd.c b/carlfw/src/cmd.c index 5887891..a222c6c 100644 --- a/carlfw/src/cmd.c +++ b/carlfw/src/cmd.c @@ -91,7 +91,7 @@ void handle_cmd(struct carl9170_rsp *resp) resp->hdr.len = 0; if (cmd->bcn_ctrl.mode & CARL9170_BCN_CTRL_CAB_TRIGGER) { - wlan_cab_modify_dtim_beacon(cmd->bcn_ctrl.vif_id, + wlan_modify_beacon(cmd->bcn_ctrl.vif_id, cmd->bcn_ctrl.bcn_addr, cmd->bcn_ctrl.bcn_len); set(AR9170_MAC_REG_BCN_ADDR, cmd->bcn_ctrl.bcn_addr); set(AR9170_MAC_REG_BCN_LENGTH, cmd->bcn_ctrl.bcn_len); diff --git a/carlfw/src/fw.c b/carlfw/src/fw.c index e71425f..1af4d90 100644 --- a/carlfw/src/fw.c +++ b/carlfw/src/fw.c @@ -83,6 +83,10 @@ const struct carl9170_firmware_descriptor __section(fwdsc) carl9170fw_desc = { .api_ver = CONFIG_CARL9170FW_RELEASE_VERSION, ), + FILL(txsq, TXSQ, + .seq_table_addr = cpu_to_le32(&fw.wlan.sequence), + ), + FILL(motd, MOTD, .fw_year_month_day = cpu_to_le32( CARL9170FW_SET_DAY(CARL9170FW_VERSION_DAY) + diff --git a/carlfw/src/wlan.c b/carlfw/src/wlan.c index 9eb336a..c4cf0b3 100644 --- a/carlfw/src/wlan.c +++ b/carlfw/src/wlan.c @@ -296,11 +296,24 @@ static void __wlan_tx(struct dma_desc *desc) #endif /* CONFIG_CARL9170FW_LOOPBACK */ } +static void wlan_assign_seq(struct ieee80211_hdr *hdr, unsigned int vif) +{ + hdr->seq_ctrl &= cpu_to_le16(~IEEE80211_SCTL_SEQ); + hdr->seq_ctrl |= cpu_to_le16(fw.wlan.sequence[vif]); + + if (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG))) + fw.wlan.sequence[vif] += 0x10; +} + /* prepares frame for the first transmission */ static void _wlan_tx(struct dma_desc *desc) { struct carl9170_tx_superframe *super = get_super(desc); + if (unlikely(super->s.assign_seq)) { + wlan_assign_seq(&super->f.data.i3e, super->s.vif_id); + } + if (unlikely(super->s.ampdu_commit_density)) { set(AR9170_MAC_REG_AMPDU_DENSITY, MOD_VAL(AR9170_MAC_AMPDU_DENSITY, @@ -842,7 +855,7 @@ static uint8_t *beacon_find_ie(uint8_t ie, void *addr, return NULL; } -void wlan_cab_modify_dtim_beacon(const unsigned int vif, +void wlan_modify_beacon(const unsigned int vif, const unsigned int addr, const unsigned int len) { uint8_t *_ie; @@ -867,6 +880,15 @@ void wlan_cab_modify_dtim_beacon(const unsigned int vif, ie->bitmap_ctrl |= 0x1; } } + + /* + * Ideally, the sequence number should be assigned by the TX arbiter + * hardware. But AFAIK that's not possible, so we have to go for the + * next best thing and write it into the beacon fifo during the open + * beacon update window. + */ + + wlan_assign_seq((struct ieee80211_hdr *)addr, vif); } #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ @@ -877,8 +899,6 @@ static void handle_beacon_config(void) bcn_count = get(AR9170_MAC_REG_BCN_COUNT); send_cmd_to_host(4, CARL9170_RSP_BEACON_CONFIG, 0x00, (uint8_t *) &bcn_count); - - set(AR9170_MAC_REG_BCN_CTRL, AR9170_BCN_CTRL_READY); } static void handle_pretbtt(void) diff --git a/include/shared/fwdesc.h b/include/shared/fwdesc.h index 59c7213..9210668 100644 --- a/include/shared/fwdesc.h +++ b/include/shared/fwdesc.h @@ -81,6 +81,7 @@ enum carl9170fw_feature_list { #define FIX_MAGIC "FIX\0" #define DBG_MAGIC "DBG\0" #define CHK_MAGIC "CHK\0" +#define TXSQ_MAGIC "TXSQ" #define LAST_MAGIC "LAST" #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31) @@ -175,6 +176,16 @@ struct carl9170fw_chk_desc { #define CARL9170FW_CHK_DESC_SIZE \ (sizeof(struct carl9170fw_chk_desc)) +#define CARL9170FW_TXSQ_DESC_MIN_VER 1 +#define CARL9170FW_TXSQ_DESC_CUR_VER 1 +struct carl9170fw_txsq_desc { + struct carl9170fw_desc_head head; + + __le32 seq_table_addr; +} __packed; +#define CARL9170FW_TXSQ_DESC_SIZE \ + (sizeof(struct carl9170fw_txsq_desc)) + #define CARL9170FW_LAST_DESC_MIN_VER 1 #define CARL9170FW_LAST_DESC_CUR_VER 2 struct carl9170fw_last_desc { diff --git a/include/shared/version.h b/include/shared/version.h index 043454a..15095c0 100644 --- a/include/shared/version.h +++ b/include/shared/version.h @@ -2,6 +2,6 @@ #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 11 #define CARL9170FW_VERSION_MONTH 1 -#define CARL9170FW_VERSION_DAY 15 +#define CARL9170FW_VERSION_DAY 22 #define CARL9170FW_VERSION_GIT "1.9.2" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/include/shared/wlan.h b/include/shared/wlan.h index ff3b917..9e1324b 100644 --- a/include/shared/wlan.h +++ b/include/shared/wlan.h @@ -251,7 +251,7 @@ struct carl9170_tx_superdesc { u8 ampdu_commit_factor:1; u8 ampdu_unused_bit:1; u8 queue:2; - u8 reserved:1; + u8 assign_seq:1; u8 vif_id:3; u8 fill_in_tsf:1; u8 cab:1; @@ -299,6 +299,7 @@ struct _ar9170_tx_hwdesc { #define CARL9170_TX_SUPER_MISC_QUEUE 0x3 #define CARL9170_TX_SUPER_MISC_QUEUE_S 0 +#define CARL9170_TX_SUPER_MISC_ASSIGN_SEQ 0x4 #define CARL9170_TX_SUPER_MISC_VIF_ID 0x38 #define CARL9170_TX_SUPER_MISC_VIF_ID_S 3 #define CARL9170_TX_SUPER_MISC_FILL_IN_TSF 0x40 diff --git a/tools/src/fwinfo.c b/tools/src/fwinfo.c index 18ca8be..c54ff81 100644 --- a/tools/src/fwinfo.c +++ b/tools/src/fwinfo.c @@ -165,6 +165,15 @@ static void show_dbg_desc(const struct carl9170fw_desc_head *head, DBG_ADDR("rx filer ", rx_filter); } +static void show_txsq_desc(const struct carl9170fw_desc_head *head, + struct carlfw *fw __unused) +{ + const struct carl9170fw_txsq_desc *txsq = (const void *) head; + + fprintf(stdout, "\t\ttx-seq table addr: 0x%x\n", + le32_to_cpu(txsq->seq_table_addr)); +} + static void show_chk_desc(const struct carl9170fw_desc_head *head, struct carlfw *fw __unused) { @@ -200,6 +209,7 @@ static const struct { uint16_t size; } known_magics[] = { ADD_HANDLER(OTUS, show_otus_desc), + ADD_HANDLER(TXSQ, show_txsq_desc), ADD_HANDLER(MOTD, show_motd_desc), ADD_HANDLER(DBG, show_dbg_desc), ADD_HANDLER(FIX, show_fix_desc), -- 2.31.1