carl9170 firmware: implement software rx filter
authorChristian Lamparter <chunkeey@googlemail.com>
Tue, 28 Sep 2010 17:46:10 +0000 (19:46 +0200)
committerChristian Lamparter <chunkeey@googlemail.com>
Tue, 28 Sep 2010 17:46:10 +0000 (19:46 +0200)
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
carlfw/include/carl9170.h
carlfw/include/cmd.h
carlfw/src/cmd.c
carlfw/src/fw.c
carlfw/src/wlan.c
include/shared/fwcmd.h
include/shared/fwdesc.h
tools/src/fwinfo.c

index 2b890fbe2343f1bdddc0bc8ceda4d396fdc3da1d..08784733988d924a3f77c7804cb7e41ade63dbb6 100644 (file)
@@ -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];
                /* 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;
                unsigned int rx_total;
                unsigned int rx_overruns;
                unsigned int mac_reset;
index f99adedef27c791e4fee45483736772f3e7dbe6e..94f8cf5a9aa1c0665264937a05b3b3a658eff0b4 100644 (file)
@@ -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_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);
 }
 
 void handle_cmd(struct carl9170_rsp *resp);
index b63f9262012aae3afbf3f4e8fa97f8780b7b86db..5887891aa7abdb880c1e020c2acf92581af2bec8 100644 (file)
@@ -81,6 +81,11 @@ void handle_cmd(struct carl9170_rsp *resp)
                read_tsf((uint32_t *)resp->tsf.tsf);
                break;
 
                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;
 #ifdef CONFIG_CARL9170FW_CAB_QUEUE
        case CARL9170_CMD_BCN_CTRL:
                resp->hdr.len = 0;
index 6cd62ae9151d71f994b7a4d87073b54972242303..9ec963b508727f05ae484e9800fc75a589b34a6a 100644 (file)
@@ -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 /* 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),
                                           (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),
             .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),
        ),
 
        FILL(last, LAST),
index b6c0e34958c51eed0ad2f84e4bd1f9cc3ae0f075..61976b05d6b3311ca96d905907f55eedbc52406e 100644 (file)
@@ -522,19 +522,13 @@ static struct carl9170_bar_ctx *wlan_get_bar_cache_buffer(void)
        return tmp;
 }
 
        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;
 
        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
                /*
                 * 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 ;
        }
 
                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!
                 */
                /*
                 * 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
 #ifdef CONFIG_CARL9170FW_HANDLE_BACK_REQ
-                       handle_bar(desc);
+                       handle_bar(desc, hdr, data_len, mac_err);
 #endif /* CONFIG_CARL9170FW_HANDLE_BACK_REQ */
 #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();
                        dma_put(&fw.pta.up_queue, desc);
                        up_trigger();
+               } else {
+                       dma_reclaim(&fw.wlan.rx_queue, desc);
+                       _wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
                }
        }
 }
                }
        }
 }
index d4a4e1dbef0695d1d9c3acd72a9df29485d42f1b..d552166db5059149cd8e653fb2e1154dfba85173 100644 (file)
@@ -53,6 +53,7 @@ enum carl9170_cmd_oids {
        CARL9170_CMD_REBOOT             = 0x04,
        CARL9170_CMD_BCN_CTRL           = 0x05,
        CARL9170_CMD_READ_TSF           = 0x06,
        CARL9170_CMD_REBOOT             = 0x04,
        CARL9170_CMD_BCN_CTRL           = 0x05,
        CARL9170_CMD_READ_TSF           = 0x06,
+       CARL9170_CMD_RX_FILTER          = 0x07,
 
        /* CAM */
        CARL9170_CMD_EKEY               = 0x10,
 
        /* CAM */
        CARL9170_CMD_EKEY               = 0x10,
@@ -153,6 +154,20 @@ struct carl9170_psm {
 } __packed;
 #define CARL9170_PSM_SIZE              4
 
 } __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;
 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_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;
                u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
        } __packed;
 } __packed;
index 7cd811708fe5b18d9911aa35d126f787edd52a37..67e4581b9ddb2bebf16a32ee38f4e30a97d20fc1 100644 (file)
@@ -66,6 +66,9 @@ enum carl9170fw_feature_list {
        /* Firmware PSM support | CARL9170_CMD_PSM */
        CARL9170FW_PSM,
 
        /* Firmware PSM support | CARL9170_CMD_PSM */
        CARL9170FW_PSM,
 
+       /* Firmware RX filter | CARL9170_CMD_RX_FILTER */
+       CARL9170FW_RX_FILTER,
+
        /* KEEP LAST */
        __CARL9170FW_FEATURE_NUM
 };
        /* 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 counter_addr;
        __le32 rx_total_addr;
        __le32 rx_overrun_addr;
+       __le32 rx_filter;
 
        /* Put your debugging definitions here */
 } __packed;
 
        /* Put your debugging definitions here */
 } __packed;
index d446359090d9e84918627232bc1a7c509e52ee63..f0b63a85983b5fb08feb850a7e3745cd2bcad07d 100644 (file)
@@ -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_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,
 };
 
 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));
                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 */
 }
 
        /* Nothing interesting here */
 }