From c48e2d095d50c9aea409c3171ed1f183fe906ea6 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 28 Sep 2010 19:46:10 +0200 Subject: [PATCH] carl9170 firmware: implement software rx filter Signed-off-by: Christian Lamparter --- carlfw/include/carl9170.h | 1 + carlfw/include/cmd.h | 1 + carlfw/src/cmd.c | 5 +++ carlfw/src/fw.c | 4 +- carlfw/src/wlan.c | 93 +++++++++++++++++++++++++++++---------- include/shared/fwcmd.h | 16 +++++++ include/shared/fwdesc.h | 4 ++ tools/src/fwinfo.c | 3 ++ 8 files changed, 102 insertions(+), 25 deletions(-) diff --git a/carlfw/include/carl9170.h b/carlfw/include/carl9170.h index 2b890fb..0878473 100644 --- a/carlfw/include/carl9170.h +++ b/carlfw/include/carl9170.h @@ -97,6 +97,7 @@ struct firmware_context_struct { /* Hardware DMA queue unstuck/fix detection */ unsigned int last_tx_desc_num[__AR9170_NUM_TX_QUEUES]; struct dma_desc *last_tx_desc[__AR9170_NUM_TX_QUEUES]; + unsigned int rx_filter; unsigned int rx_total; unsigned int rx_overruns; unsigned int mac_reset; diff --git a/carlfw/include/cmd.h b/carlfw/include/cmd.h index f99aded..94f8cf5 100644 --- a/carlfw/include/cmd.h +++ b/carlfw/include/cmd.h @@ -46,6 +46,7 @@ static inline void __check(void) BUILD_BUG_ON(sizeof(struct carl9170_tx_status) != CARL9170_TX_STATUS_SIZE); BUILD_BUG_ON(sizeof(struct _carl9170_tx_status) != CARL9170_TX_STATUS_SIZE); BUILD_BUG_ON(sizeof(struct carl9170_gpio) != CARL9170_GPIO_SIZE); + BUILD_BUG_ON(sizeof(struct carl9170_rx_filter_cmd) != CARL9170_RX_FILTER_CMD_SIZE); } void handle_cmd(struct carl9170_rsp *resp); diff --git a/carlfw/src/cmd.c b/carlfw/src/cmd.c index b63f926..5887891 100644 --- a/carlfw/src/cmd.c +++ b/carlfw/src/cmd.c @@ -81,6 +81,11 @@ void handle_cmd(struct carl9170_rsp *resp) read_tsf((uint32_t *)resp->tsf.tsf); break; + case CARL9170_CMD_RX_FILTER: + resp->hdr.len = 0; + fw.wlan.rx_filter = cmd->rx_filter.rx_filter; + break; + #ifdef CONFIG_CARL9170FW_CAB_QUEUE case CARL9170_CMD_BCN_CTRL: resp->hdr.len = 0; diff --git a/carlfw/src/fw.c b/carlfw/src/fw.c index 6cd62ae..9ec963b 100644 --- a/carlfw/src/fw.c +++ b/carlfw/src/fw.c @@ -64,7 +64,8 @@ const struct carl9170_firmware_descriptor __section(fwdsc) carl9170fw_desc = { #endif /* CONFIG_CARL9170FW_GPIO_INTERRUPT */ #ifdef CONFIG_CARL9170FW_PSM BIT(CARL9170FW_PSM) | -#endif +#endif /* CONFIG_CARL9170FW_PSM */ + BIT(CARL9170FW_RX_FILTER) | (0)), .miniboot_size = cpu_to_le16(0), @@ -92,6 +93,7 @@ const struct carl9170_firmware_descriptor __section(fwdsc) carl9170fw_desc = { .counter_addr = cpu_to_le32(&fw.counter), .rx_total_addr = cpu_to_le32(&fw.wlan.rx_total), .rx_overrun_addr = cpu_to_le32(&fw.wlan.rx_overruns), + .rx_filter = cpu_to_le32(&fw.wlan.rx_filter), ), FILL(last, LAST), diff --git a/carlfw/src/wlan.c b/carlfw/src/wlan.c index b6c0e34..61976b0 100644 --- a/carlfw/src/wlan.c +++ b/carlfw/src/wlan.c @@ -522,19 +522,13 @@ static struct carl9170_bar_ctx *wlan_get_bar_cache_buffer(void) return tmp; } -static void handle_bar(struct dma_desc *desc) +static void handle_bar(struct dma_desc *desc, struct ieee80211_hdr *hdr, + unsigned int len, unsigned int mac_err) { - struct ieee80211_hdr *hdr; struct ieee80211_bar *bar; struct carl9170_bar_ctx *ctx; - hdr = ar9170_get_rx_i3e(desc); - - /* check if this is a BAR for us */ - if (likely(!ieee80211_is_back_req(hdr->frame_control))) - return ; - - if (unlikely(ar9170_get_rx_macstatus_error(desc))) { + if (unlikely(mac_err)) { /* * This check does a number of things: * 1. checks if the frame is in good nick @@ -543,8 +537,7 @@ static void handle_bar(struct dma_desc *desc) return ; } - if (unlikely(ar9170_get_rx_mpdu_len(desc) < - sizeof(struct ieee80211_bar))) { + if (unlikely(len < (sizeof(struct ieee80211_bar) + FCS_LEN))) { /* * Sneaky, corrupted BARs... but not with us! */ @@ -598,26 +591,78 @@ static void wlan_check_rx_overrun(void) } } -static void handle_rx(void) +static unsigned int wlan_rx_filter(struct dma_desc *desc) { - struct dma_desc *desc; + struct ieee80211_hdr *hdr; + unsigned int data_len; + unsigned int rx_filter; + unsigned int mac_err; - for_each_desc_not_bits(desc, &fw.wlan.rx_queue, AR9170_OWN_BITS_HW) { - if (unlikely(desc->totalLen < 26 || - desc->totalLen > CONFIG_CARL9170FW_RX_FRAME_LEN)) { - /* - * This frame is too damaged to do anything - * useful with it. - */ - dma_reclaim(&fw.wlan.rx_queue, desc); - _wlan_trigger(AR9170_DMA_TRIGGER_RXQ); - } else { + data_len = ar9170_get_rx_mpdu_len(desc); + mac_err = ar9170_get_rx_macstatus_error(desc); + +#define AR9170_RX_ERROR_BAD (AR9170_RX_ERROR_FCS | AR9170_RX_ERROR_PLCP | \ + AR9170_RX_ERROR_FATAL) + + if (unlikely(data_len < (4 + 6 + FCS_LEN) || + desc->totalLen > CONFIG_CARL9170FW_RX_FRAME_LEN) || + mac_err & AR9170_RX_ERROR_BAD) { + + /* + * This frame is too damaged to do anything + * useful with it. + */ + + return CARL9170_RX_FILTER_BAD; + } + + rx_filter = 0; + if (mac_err & AR9170_RX_ERROR_WRONG_RA) + rx_filter |= CARL9170_RX_FILTER_OTHER_RA; + + if (mac_err & AR9170_RX_ERROR_DECRYPT) + rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL; + + hdr = ar9170_get_rx_i3e(desc); + if (likely(ieee80211_is_data(hdr->frame_control))) { + rx_filter |= CARL9170_RX_FILTER_DATA; + } else if (ieee80211_is_ctl(hdr->frame_control)) { + switch (le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BACK_REQ: #ifdef CONFIG_CARL9170FW_HANDLE_BACK_REQ - handle_bar(desc); + handle_bar(desc, hdr, data_len, mac_err); #endif /* CONFIG_CARL9170FW_HANDLE_BACK_REQ */ + /* fallthrough */ + rx_filter |= CARL9170_RX_FILTER_CTL_BACKR; + break; + case IEEE80211_STYPE_PSPOLL: + rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL; + break; + default: + rx_filter |= CARL9170_RX_FILTER_CTL_OTHER; + break; + } + } else { + /* ieee80211_is_mgmt */ + rx_filter |= CARL9170_RX_FILTER_MGMT; + } +#undef AR9170_RX_ERROR_BAD + + return rx_filter; +} + +static void handle_rx(void) +{ + struct dma_desc *desc; + + for_each_desc_not_bits(desc, &fw.wlan.rx_queue, AR9170_OWN_BITS_HW) { + if (!(wlan_rx_filter(desc) & fw.wlan.rx_filter)) { dma_put(&fw.pta.up_queue, desc); up_trigger(); + } else { + dma_reclaim(&fw.wlan.rx_queue, desc); + _wlan_trigger(AR9170_DMA_TRIGGER_RXQ); } } } diff --git a/include/shared/fwcmd.h b/include/shared/fwcmd.h index d4a4e1d..d552166 100644 --- a/include/shared/fwcmd.h +++ b/include/shared/fwcmd.h @@ -53,6 +53,7 @@ enum carl9170_cmd_oids { CARL9170_CMD_REBOOT = 0x04, CARL9170_CMD_BCN_CTRL = 0x05, CARL9170_CMD_READ_TSF = 0x06, + CARL9170_CMD_RX_FILTER = 0x07, /* CAM */ CARL9170_CMD_EKEY = 0x10, @@ -153,6 +154,20 @@ struct carl9170_psm { } __packed; #define CARL9170_PSM_SIZE 4 +struct carl9170_rx_filter_cmd { + __le32 rx_filter; +} __packed; +#define CARL9170_RX_FILTER_CMD_SIZE 4 + +#define CARL9170_RX_FILTER_BAD 0x01 +#define CARL9170_RX_FILTER_OTHER_RA 0x02 +#define CARL9170_RX_FILTER_DECRY_FAIL 0x04 +#define CARL9170_RX_FILTER_CTL_OTHER 0x08 +#define CARL9170_RX_FILTER_CTL_PSPOLL 0x10 +#define CARL9170_RX_FILTER_CTL_BACKR 0x20 +#define CARL9170_RX_FILTER_MGMT 0x40 +#define CARL9170_RX_FILTER_DATA 0x80 + struct carl9170_bcn_ctrl_cmd { __le32 vif_id; __le32 mode; @@ -188,6 +203,7 @@ struct carl9170_cmd { struct carl9170_rf_init rf_init; struct carl9170_psm psm; struct carl9170_bcn_ctrl_cmd bcn_ctrl; + struct carl9170_rx_filter_cmd rx_filter; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; } __packed; } __packed; diff --git a/include/shared/fwdesc.h b/include/shared/fwdesc.h index 7cd8117..67e4581 100644 --- a/include/shared/fwdesc.h +++ b/include/shared/fwdesc.h @@ -66,6 +66,9 @@ enum carl9170fw_feature_list { /* Firmware PSM support | CARL9170_CMD_PSM */ CARL9170FW_PSM, + /* Firmware RX filter | CARL9170_CMD_RX_FILTER */ + CARL9170FW_RX_FILTER, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; @@ -150,6 +153,7 @@ struct carl9170fw_dbg_desc { __le32 counter_addr; __le32 rx_total_addr; __le32 rx_overrun_addr; + __le32 rx_filter; /* Put your debugging definitions here */ } __packed; diff --git a/tools/src/fwinfo.c b/tools/src/fwinfo.c index d446359..f0b63a8 100644 --- a/tools/src/fwinfo.c +++ b/tools/src/fwinfo.c @@ -63,6 +63,7 @@ static const struct feature_list known_otus_features_v1[] = { CHECK_FOR_FEATURE(CARL9170FW_HANDLE_BACK_REQ), CHECK_FOR_FEATURE(CARL9170FW_GPIO_INTERRUPT), CHECK_FOR_FEATURE(CARL9170FW_PSM), + CHECK_FOR_FEATURE(CARL9170FW_RX_FILTER), }; static void check_feature_list(const struct carl9170fw_desc_head *head, @@ -158,6 +159,8 @@ static void show_dbg_desc(const struct carl9170fw_desc_head *head, le32_to_cpu(dbg->rx_total_addr)); fprintf(stdout, "\t\trx overrun = 0x%.8x\n", le32_to_cpu(dbg->rx_overrun_addr)); + fprintf(stdout, "\t\trx filter = 0x%.8x\n", + le32_to_cpu(dbg->rx_filter)); /* Nothing interesting here */ } -- 2.31.1