diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 121 |
1 files changed, 74 insertions, 47 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 091d9a6..956c108 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -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) { |