diff options
Diffstat (limited to 'drivers/net/wireless/marvell/mwifiex/pcie.c')
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/pcie.c | 185 |
1 files changed, 173 insertions, 12 deletions
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 106717dd8..453ab6ad4 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -190,7 +190,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, if (ent->driver_data) { struct mwifiex_pcie_device *data = (void *)ent->driver_data; - card->pcie.firmware = data->firmware; card->pcie.reg = data->reg; card->pcie.blksz_fw_dl = data->blksz_fw_dl; card->pcie.tx_buf_size = data->tx_buf_size; @@ -203,7 +202,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, MWIFIEX_PCIE)) { pr_err("%s failed\n", __func__); - kfree(card); return -1; } @@ -269,6 +267,11 @@ static const struct pci_device_id mwifiex_ids[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, .driver_data = (unsigned long)&mwifiex_pcie8997, }, + { + PCIE_VENDOR_ID_V2_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + .driver_data = (unsigned long)&mwifiex_pcie8997, + }, {}, }; @@ -436,6 +439,11 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter) return 0; } +static void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter) +{ + WARN_ON(mwifiex_pcie_disable_host_int(adapter)); +} + /* * This function enables the host interrupt. * @@ -503,7 +511,7 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { /* Allocate skb here so that firmware can DMA data from it */ skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, - GFP_KERNEL | GFP_DMA); + GFP_KERNEL); if (!skb) { mwifiex_dbg(adapter, ERROR, "Unable to allocate skb for RX ring.\n"); @@ -1315,7 +1323,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) } skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, - GFP_KERNEL | GFP_DMA); + GFP_KERNEL); if (!skb_tmp) { mwifiex_dbg(adapter, ERROR, "Unable to allocate skb.\n"); @@ -1608,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) pkt_len = *((__le16 *)skb->data); rx_len = le16_to_cpu(pkt_len); + skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); skb_trim(skb, rx_len); skb_pull(skb, INTF_HEADER_LEN); @@ -2082,6 +2091,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter, unsigned long flags; struct pcie_service_card *card = adapter->card; + if (card->msi_enable) { + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status = 1; + spin_unlock_irqrestore(&adapter->int_lock, flags); + return; + } + if (!mwifiex_pcie_ok_to_access_hw(adapter)) return; @@ -2183,15 +2199,44 @@ exit: static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) { int ret; - u32 pcie_ireg; + u32 pcie_ireg = 0; unsigned long flags; + struct pcie_service_card *card = adapter->card; spin_lock_irqsave(&adapter->int_lock, flags); - /* Clear out unused interrupts */ - pcie_ireg = adapter->int_status; + if (!card->msi_enable) { + /* Clear out unused interrupts */ + pcie_ireg = adapter->int_status; + } adapter->int_status = 0; spin_unlock_irqrestore(&adapter->int_lock, flags); + if (card->msi_enable) { + if (mwifiex_pcie_ok_to_access_hw(adapter)) { + if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, + &pcie_ireg)) { + mwifiex_dbg(adapter, ERROR, + "Read register failed\n"); + return -1; + } + + if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) { + if (mwifiex_write_reg(adapter, + PCIE_HOST_INT_STATUS, + ~pcie_ireg)) { + mwifiex_dbg(adapter, ERROR, + "Write register failed\n"); + return -1; + } + if (!adapter->pps_uapsd_mode && + adapter->ps_state == PS_STATE_SLEEP) { + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_fw_try = false; + del_timer(&adapter->wakeup_timer); + } + } + } + } while (pcie_ireg & HOST_INTR_MASK) { if (pcie_ireg & HOST_INTR_DNLD_DONE) { pcie_ireg &= ~HOST_INTR_DNLD_DONE; @@ -2231,6 +2276,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) return ret; } + if (card->msi_enable) { + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } + if (mwifiex_pcie_ok_to_access_hw(adapter)) { if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) { @@ -2250,11 +2301,17 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) } } + if (!card->msi_enable) { + spin_lock_irqsave(&adapter->int_lock, flags); + pcie_ireg |= adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } } mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n", adapter->cmd_sent, adapter->data_sent); - if (adapter->ps_state != PS_STATE_SLEEP) + if (!card->msi_enable && adapter->ps_state != PS_STATE_SLEEP) mwifiex_pcie_enable_host_int(adapter); return 0; @@ -2351,6 +2408,47 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type, return 0; } +/* Function to dump PCIE scratch registers in case of FW crash + */ +static int +mwifiex_pcie_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) +{ + char *p = drv_buf; + char buf[256], *ptr; + int i; + u32 value; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int pcie_scratch_reg[] = {PCIE_SCRATCH_12_REG, + PCIE_SCRATCH_13_REG, + PCIE_SCRATCH_14_REG}; + + if (!p) + return 0; + + mwifiex_dbg(adapter, MSG, "PCIE register dump start\n"); + + if (mwifiex_read_reg(adapter, reg->fw_status, &value)) { + mwifiex_dbg(adapter, ERROR, "failed to read firmware status"); + return 0; + } + + ptr = buf; + mwifiex_dbg(adapter, MSG, "pcie scratch register:"); + for (i = 0; i < ARRAY_SIZE(pcie_scratch_reg); i++) { + mwifiex_read_reg(adapter, pcie_scratch_reg[i], &value); + ptr += sprintf(ptr, "reg:0x%x, value=0x%x\n", + pcie_scratch_reg[i], value); + } + + mwifiex_dbg(adapter, MSG, "%s\n", buf); + p += sprintf(p, "%s\n", buf); + + mwifiex_dbg(adapter, MSG, "PCIE register dump end\n"); + + return p - drv_buf; +} + /* This function read/write firmware */ static enum rdwr_status mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag) @@ -2751,7 +2849,6 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) "MRVL_PCIE", &card->share_irq_ctx); if (ret) { pr_err("request_irq failed: ret=%d\n", ret); - adapter->card = NULL; return -1; } @@ -2759,6 +2856,68 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) } /* + * This function gets the firmware name for downloading by revision id + * + * Read revision id register to get revision id + */ +static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter) +{ + int revision_id = 0; + int version; + struct pcie_service_card *card = adapter->card; + + switch (card->dev->device) { + case PCIE_DEVICE_ID_MARVELL_88W8766P: + strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME); + break; + case PCIE_DEVICE_ID_MARVELL_88W8897: + mwifiex_write_reg(adapter, 0x0c58, 0x80c00000); + mwifiex_read_reg(adapter, 0x0c58, &revision_id); + revision_id &= 0xff00; + switch (revision_id) { + case PCIE8897_A0: + strcpy(adapter->fw_name, PCIE8897_A0_FW_NAME); + break; + case PCIE8897_B0: + strcpy(adapter->fw_name, PCIE8897_B0_FW_NAME); + break; + default: + strcpy(adapter->fw_name, PCIE8897_DEFAULT_FW_NAME); + + break; + } + break; + case PCIE_DEVICE_ID_MARVELL_88W8997: + mwifiex_read_reg(adapter, 0x0c48, &revision_id); + mwifiex_read_reg(adapter, 0x0cd0, &version); + version &= 0x7; + switch (revision_id) { + case PCIE8997_V2: + if (version == CHIP_VER_PCIEUART) + strcpy(adapter->fw_name, + PCIEUART8997_FW_NAME_V2); + else + strcpy(adapter->fw_name, + PCIEUSB8997_FW_NAME_V2); + break; + case PCIE8997_Z: + if (version == CHIP_VER_PCIEUART) + strcpy(adapter->fw_name, + PCIEUART8997_FW_NAME_Z); + else + strcpy(adapter->fw_name, + PCIEUSB8997_FW_NAME_Z); + break; + default: + strcpy(adapter->fw_name, PCIE8997_DEFAULT_FW_NAME); + break; + } + default: + break; + } +} + +/* * This function registers the PCIE device. * * PCIE IRQ is claimed, block size is set and driver data is initialized. @@ -2778,8 +2937,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->tx_buf_size = card->pcie.tx_buf_size; adapter->mem_type_mapping_tbl = card->pcie.mem_type_mapping_tbl; adapter->num_mem_types = card->pcie.num_mem_types; - strcpy(adapter->fw_name, card->pcie.firmware); adapter->ext_scan = card->pcie.can_ext_scan; + mwifiex_pcie_get_fw_name(adapter); return 0; } @@ -2794,10 +2953,11 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg; - struct pci_dev *pdev = card->dev; + struct pci_dev *pdev; int i; if (card) { + pdev = card->dev; if (card->msix_enable) { for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) synchronize_irq(card->msix_entries[i].vector); @@ -2838,6 +2998,7 @@ static struct mwifiex_if_ops pcie_ops = { .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, .enable_int = mwifiex_pcie_enable_host_int, + .disable_int = mwifiex_pcie_disable_host_int_noerr, .process_int_status = mwifiex_process_int_status, .host_to_card = mwifiex_pcie_host_to_card, .wakeup = mwifiex_pm_wakeup_card, @@ -2850,6 +3011,7 @@ static struct mwifiex_if_ops pcie_ops = { .cleanup_mpa_buf = NULL, .init_fw_port = mwifiex_pcie_init_fw_port, .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, + .reg_dump = mwifiex_pcie_reg_dump, .device_dump = mwifiex_pcie_device_dump, }; @@ -2907,4 +3069,3 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION); MODULE_VERSION(PCIE_VERSION); MODULE_LICENSE("GPL v2"); -/*(DEBLOBBED)*/ |