Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / mwl8k.c
index 091d9a64080aa520879261a276d1e08e529f111f..956c1084ebf13ade0959fff0ad894a4910b60108 100644 (file)
@@ -232,6 +232,7 @@ struct mwl8k_priv {
        u16 num_mcaddrs;
        u8 hw_rev;
        u32 fw_rev;
+       u32 caps;
 
        /*
         * Running count of TX packets in flight, to avoid
@@ -284,6 +285,7 @@ struct mwl8k_priv {
        unsigned fw_state;
        char *fw_pref;
        char *fw_alt;
+       bool is_8764;
        struct completion firmware_loading_complete;
 
        /* bitmap of running BSSes */
@@ -600,13 +602,18 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
        loops = 1000;
        do {
                u32 int_code;
-
-               int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
-               if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
-                       iowrite32(0, regs + MWL8K_HIU_INT_CODE);
-                       break;
+               if (priv->is_8764) {
+                       int_code = ioread32(regs +
+                                           MWL8K_HIU_H2A_INTERRUPT_STATUS);
+                       if (int_code == 0)
+                               break;
+               } else {
+                       int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
+                       if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
+                               iowrite32(0, regs + MWL8K_HIU_INT_CODE);
+                               break;
+                       }
                }
-
                cond_resched();
                udelay(1);
        } while (--loops);
@@ -724,7 +731,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
        int rc;
        int loops;
 
-       if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
+       if (!memcmp(fw->data, "\x01\x00\x00\x00", 4) && !priv->is_8764) {
                const struct firmware *helper = priv->fw_helper;
 
                if (helper == NULL) {
@@ -743,7 +750,10 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 
                rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
        } else {
-               rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
+               if (priv->is_8764)
+                       rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
+               else
+                       rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
        }
 
        if (rc) {
@@ -908,9 +918,9 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv,
 }
 
 /*
- * Packet reception for 88w8366 AP firmware.
+ * Packet reception for 88w8366/88w8764 AP firmware.
  */
-struct mwl8k_rxd_8366_ap {
+struct mwl8k_rxd_ap {
        __le16 pkt_len;
        __u8 sq2;
        __u8 rate;
@@ -928,30 +938,30 @@ struct mwl8k_rxd_8366_ap {
        __u8 rx_ctrl;
 } __packed;
 
-#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT     0x80
-#define MWL8K_8366_AP_RATE_INFO_40MHZ          0x40
-#define MWL8K_8366_AP_RATE_INFO_RATEID(x)      ((x) & 0x3f)
+#define MWL8K_AP_RATE_INFO_MCS_FORMAT          0x80
+#define MWL8K_AP_RATE_INFO_40MHZ               0x40
+#define MWL8K_AP_RATE_INFO_RATEID(x)           ((x) & 0x3f)
 
-#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST    0x80
+#define MWL8K_AP_RX_CTRL_OWNED_BY_HOST         0x80
 
-/* 8366 AP rx_status bits */
-#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK          0x80
-#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR       0xFF
-#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR      0x02
-#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR       0x04
-#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR      0x08
+/* 8366/8764 AP rx_status bits */
+#define MWL8K_AP_RXSTAT_DECRYPT_ERR_MASK               0x80
+#define MWL8K_AP_RXSTAT_GENERAL_DECRYPT_ERR            0xFF
+#define MWL8K_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR           0x02
+#define MWL8K_AP_RXSTAT_WEP_DECRYPT_ICV_ERR            0x04
+#define MWL8K_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR           0x08
 
-static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_ap_init(void *_rxd, dma_addr_t next_dma_addr)
 {
-       struct mwl8k_rxd_8366_ap *rxd = _rxd;
+       struct mwl8k_rxd_ap *rxd = _rxd;
 
        rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
-       rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST;
+       rxd->rx_ctrl = MWL8K_AP_RX_CTRL_OWNED_BY_HOST;
 }
 
-static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_ap_refill(void *_rxd, dma_addr_t addr, int len)
 {
-       struct mwl8k_rxd_8366_ap *rxd = _rxd;
+       struct mwl8k_rxd_ap *rxd = _rxd;
 
        rxd->pkt_len = cpu_to_le16(len);
        rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -960,12 +970,12 @@ static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
 }
 
 static int
-mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
-                         __le16 *qos, s8 *noise)
+mwl8k_rxd_ap_process(void *_rxd, struct ieee80211_rx_status *status,
+                    __le16 *qos, s8 *noise)
 {
-       struct mwl8k_rxd_8366_ap *rxd = _rxd;
+       struct mwl8k_rxd_ap *rxd = _rxd;
 
-       if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST))
+       if (!(rxd->rx_ctrl & MWL8K_AP_RX_CTRL_OWNED_BY_HOST))
                return -1;
        rmb();
 
@@ -974,11 +984,11 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
        status->signal = -rxd->rssi;
        *noise = -rxd->noise_floor;
 
-       if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
+       if (rxd->rate & MWL8K_AP_RATE_INFO_MCS_FORMAT) {
                status->flag |= RX_FLAG_HT;
-               if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ)
+               if (rxd->rate & MWL8K_AP_RATE_INFO_40MHZ)
                        status->flag |= RX_FLAG_40MHZ;
-               status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate);
+               status->rate_idx = MWL8K_AP_RATE_INFO_RATEID(rxd->rate);
        } else {
                int i;
 
@@ -1002,19 +1012,19 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
 
        *qos = rxd->qos_control;
 
-       if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
-           (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) &&
-           (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
+       if ((rxd->rx_status != MWL8K_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
+           (rxd->rx_status & MWL8K_AP_RXSTAT_DECRYPT_ERR_MASK) &&
+           (rxd->rx_status & MWL8K_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
                status->flag |= RX_FLAG_MMIC_ERROR;
 
        return le16_to_cpu(rxd->pkt_len);
 }
 
-static struct rxd_ops rxd_8366_ap_ops = {
-       .rxd_size       = sizeof(struct mwl8k_rxd_8366_ap),
-       .rxd_init       = mwl8k_rxd_8366_ap_init,
-       .rxd_refill     = mwl8k_rxd_8366_ap_refill,
-       .rxd_process    = mwl8k_rxd_8366_ap_process,
+static struct rxd_ops rxd_ap_ops = {
+       .rxd_size       = sizeof(struct mwl8k_rxd_ap),
+       .rxd_init       = mwl8k_rxd_ap_init,
+       .rxd_refill     = mwl8k_rxd_ap_refill,
+       .rxd_process    = mwl8k_rxd_ap_process,
 };
 
 /*
@@ -2401,6 +2411,9 @@ mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
 {
        struct mwl8k_priv *priv = hw->priv;
 
+       if (priv->caps)
+               return;
+
        if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) {
                mwl8k_setup_2ghz_band(hw);
                if (caps & MWL8K_CAP_MIMO)
@@ -2412,6 +2425,8 @@ mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
                if (caps & MWL8K_CAP_MIMO)
                        mwl8k_set_ht_caps(hw, &priv->band_50, caps);
        }
+
+       priv->caps = caps;
 }
 
 static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
@@ -4792,16 +4807,14 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
        struct mwl8k_priv *priv = hw->priv;
        int rc;
 
-       if (conf->flags & IEEE80211_CONF_IDLE) {
-               mwl8k_cmd_radio_disable(hw);
-               return 0;
-       }
-
        rc = mwl8k_fw_lock(hw);
        if (rc)
                return rc;
 
-       rc = mwl8k_cmd_radio_enable(hw);
+       if (conf->flags & IEEE80211_CONF_IDLE)
+               rc = mwl8k_cmd_radio_disable(hw);
+       else
+               rc = mwl8k_cmd_radio_enable(hw);
        if (rc)
                goto out;
 
@@ -5429,12 +5442,17 @@ enum {
        MWL8363 = 0,
        MWL8687,
        MWL8366,
+       MWL8764,
 };
 
 #define MWL8K_8366_AP_FW_API 3
 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
 #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
 
+#define MWL8K_8764_AP_FW_API 1
+#define _MWL8K_8764_AP_FW(api) "mwl8k/fmimage_8764_ap-" #api ".fw"
+#define MWL8K_8764_AP_FW(api) _MWL8K_8764_AP_FW(api)
+
 static struct mwl8k_device_info mwl8k_info_tbl[] = {
        [MWL8363] = {
                .part_name      = "88w8363",
@@ -5452,7 +5470,13 @@ static struct mwl8k_device_info mwl8k_info_tbl[] = {
                .fw_image_sta   = "mwl8k/fmimage_8366.fw",
                .fw_image_ap    = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API),
                .fw_api_ap      = MWL8K_8366_AP_FW_API,
-               .ap_rxd_ops     = &rxd_8366_ap_ops,
+               .ap_rxd_ops     = &rxd_ap_ops,
+       },
+       [MWL8764] = {
+               .part_name      = "88w8764",
+               .fw_image_ap    = MWL8K_8764_AP_FW(MWL8K_8764_AP_FW_API),
+               .fw_api_ap      = MWL8K_8764_AP_FW_API,
+               .ap_rxd_ops     = &rxd_ap_ops,
        },
 };
 
@@ -5474,6 +5498,7 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
        { PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, },
        { PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, },
        { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
+       { PCI_VDEVICE(MARVELL, 0x2b36), .driver_data = MWL8764, },
        { },
 };
 MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
@@ -5995,6 +6020,8 @@ static int mwl8k_probe(struct pci_dev *pdev,
        priv->pdev = pdev;
        priv->device_info = &mwl8k_info_tbl[id->driver_data];
 
+       if (id->driver_data == MWL8764)
+               priv->is_8764 = true;
 
        priv->sram = pci_iomap(pdev, 0, 0x10000);
        if (priv->sram == NULL) {