From: Rafał Miłecki Date: Tue, 26 May 2015 12:14:34 +0000 (+0000) Subject: mac80211: backport today's brcmfmac changes X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=565eac46b6389f3bd83c92e7a67b2a2e1482636c;p=openwrt%2Fstaging%2Fldir.git mac80211: backport today's brcmfmac changes It should improve msgbuf throughput (PCIe devices like BCM43602). Signed-off-by: Rafał Miłecki SVN-Revision: 45767 --- diff --git a/package/kernel/mac80211/patches/364-brcmfmac-cleanup-a-sizeof.patch b/package/kernel/mac80211/patches/364-brcmfmac-cleanup-a-sizeof.patch new file mode 100644 index 0000000000..d26e118d77 --- /dev/null +++ b/package/kernel/mac80211/patches/364-brcmfmac-cleanup-a-sizeof.patch @@ -0,0 +1,23 @@ +From: Dan Carpenter +Date: Thu, 7 May 2015 12:59:19 +0300 +Subject: [PATCH] brcmfmac: cleanup a sizeof() + +"flowrings" and "*flowrings" are both pointers so this always returns +sizeof(void *) and the current code works fine. But "*flowrings" is +intended here and static checkers complain, so lets change it. + +Signed-off-by: Dan Carpenter +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -1617,7 +1617,7 @@ static void brcmf_pcie_setup(struct devi + bus->msgbuf->commonrings[i] = + &devinfo->shared.commonrings[i]->commonring; + +- flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(flowrings), ++ flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*flowrings), + GFP_KERNEL); + if (!flowrings) + goto fail; diff --git a/package/kernel/mac80211/patches/365-brcmfmac-check-result-of-USB-firmware-request.patch b/package/kernel/mac80211/patches/365-brcmfmac-check-result-of-USB-firmware-request.patch new file mode 100644 index 0000000000..9b2880d8fc --- /dev/null +++ b/package/kernel/mac80211/patches/365-brcmfmac-check-result-of-USB-firmware-request.patch @@ -0,0 +1,33 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 7 May 2015 14:13:03 +0200 +Subject: [PATCH] brcmfmac: check result of USB firmware request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This prevents silence failures with driver waiting (infinitely) for a +callback. + +Signed-off-by: Rafał Miłecki +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c +@@ -1270,8 +1270,13 @@ static int brcmf_usb_probe_cb(struct brc + bus->chiprev = bus_pub->chiprev; + + /* request firmware here */ +- brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL, +- brcmf_usb_probe_phase2); ++ ret = brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), ++ NULL, brcmf_usb_probe_phase2); ++ if (ret) { ++ brcmf_err("firmware request failed: %d\n", ret); ++ goto fail; ++ } ++ + return 0; + + fail: diff --git a/package/kernel/mac80211/patches/366-brcmfmac-prohibit-ACPI-power-management-for-brcmfmac.patch b/package/kernel/mac80211/patches/366-brcmfmac-prohibit-ACPI-power-management-for-brcmfmac.patch new file mode 100644 index 0000000000..d46b300daa --- /dev/null +++ b/package/kernel/mac80211/patches/366-brcmfmac-prohibit-ACPI-power-management-for-brcmfmac.patch @@ -0,0 +1,47 @@ +From: "Fu, Zhonghui" +Date: Mon, 11 May 2015 10:41:32 +0800 +Subject: [PATCH] brcmfmac: prohibit ACPI power management for brcmfmac driver + +ACPI will manage WiFi chip's power state during suspend/resume +process on some tablet platforms(such as ASUS T100TA). This is +not supported by brcmfmac driver now, and the context of WiFi +chip will be damaged after resume. This patch informs ACPI not +to manage WiFi chip's power state. + +Signed-off-by: Zhonghui Fu +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1122,6 +1123,8 @@ static int brcmf_ops_sdio_probe(struct s + int err; + struct brcmf_sdio_dev *sdiodev; + struct brcmf_bus *bus_if; ++ struct device *dev; ++ struct acpi_device *adev; + + brcmf_dbg(SDIO, "Enter\n"); + brcmf_dbg(SDIO, "Class=%x\n", func->class); +@@ -1129,6 +1132,12 @@ static int brcmf_ops_sdio_probe(struct s + brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); + brcmf_dbg(SDIO, "Function#: %d\n", func->num); + ++ /* prohibit ACPI power management for this device */ ++ dev = &func->dev; ++ adev = ACPI_COMPANION(dev); ++ if (adev) ++ adev->flags.power_manageable = 0; ++ + /* Consume func num 1 but dont do anything with it. */ + if (func->num == 1) + return 0; diff --git a/package/kernel/mac80211/patches/367-brcmfmac-avoid-gcc-5.1-warning.patch b/package/kernel/mac80211/patches/367-brcmfmac-avoid-gcc-5.1-warning.patch new file mode 100644 index 0000000000..9b4609fb75 --- /dev/null +++ b/package/kernel/mac80211/patches/367-brcmfmac-avoid-gcc-5.1-warning.patch @@ -0,0 +1,30 @@ +From: Arnd Bergmann +Date: Tue, 12 May 2015 23:54:25 +0200 +Subject: [PATCH] brcmfmac: avoid gcc-5.1 warning + +gcc-5.0 gained a new warning in the fwsignal portion of the brcmfmac +driver: + +drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c: In function 'brcmf_fws_txs_process': +drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c:1478:8: warning: 'skb' may be used uninitialized in this function [-Wmaybe-uninitialized] + +This is a false positive, and marking the brcmf_fws_hanger_poppkt function +as 'static inline' makes the warning go away. I have checked the object +file output and while a little code gets moved around, the size of +the binary remains identical. + +Signed-off-by: Arnd Bergmann +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -635,7 +635,7 @@ static int brcmf_fws_hanger_pushpkt(stru + return 0; + } + +-static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h, ++static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h, + u32 slot_id, struct sk_buff **pktout, + bool remove_item) + { diff --git a/package/kernel/mac80211/patches/368-brcmfmac-allow-device-tree-node-without-interrupts-p.patch b/package/kernel/mac80211/patches/368-brcmfmac-allow-device-tree-node-without-interrupts-p.patch new file mode 100644 index 0000000000..b16782d593 --- /dev/null +++ b/package/kernel/mac80211/patches/368-brcmfmac-allow-device-tree-node-without-interrupts-p.patch @@ -0,0 +1,45 @@ +From: Arend van Spriel +Date: Wed, 20 May 2015 14:09:47 +0200 +Subject: [PATCH] brcmfmac: allow device tree node without 'interrupts' + property + +As described in the device tree bindings for 'brcm,bcm4329-fmac' +nodes, the interrupts property is optional. So adding a check +for the presence of this property before attempting to parse +and map the interrupt. If not present or parsing fails return +and fallback to in-band sdio interrupt. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c +@@ -39,10 +39,16 @@ void brcmf_of_probe(struct brcmf_sdio_de + if (!sdiodev->pdata) + return; + ++ if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) ++ sdiodev->pdata->drive_strength = val; ++ ++ /* make sure there are interrupts defined in the node */ ++ if (!of_find_property(np, "interrupts", NULL)) ++ return; ++ + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + brcmf_err("interrupt could not be mapped\n"); +- devm_kfree(dev, sdiodev->pdata); + return; + } + irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); +@@ -50,7 +56,4 @@ void brcmf_of_probe(struct brcmf_sdio_de + sdiodev->pdata->oob_irq_supported = true; + sdiodev->pdata->oob_irq_nr = irq; + sdiodev->pdata->oob_irq_flags = irqf; +- +- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) +- sdiodev->pdata->drive_strength = val; + } diff --git a/package/kernel/mac80211/patches/369-brcmfmac-Improve-throughput-by-scheduling-msbug-flow.patch b/package/kernel/mac80211/patches/369-brcmfmac-Improve-throughput-by-scheduling-msbug-flow.patch new file mode 100644 index 0000000000..f81250ee4c --- /dev/null +++ b/package/kernel/mac80211/patches/369-brcmfmac-Improve-throughput-by-scheduling-msbug-flow.patch @@ -0,0 +1,87 @@ +From: Hante Meuleman +Date: Wed, 20 May 2015 14:09:48 +0200 +Subject: [PATCH] brcmfmac: Improve throughput by scheduling msbug flow worker. + +The tx flow worker in msgbuf gets scheduled at tx till a certain +threshold has been reached. Then the tx completes will take over +the scheduling. When amsdu and ampdu is used the frames are +transferred wireless in a very bulky fashion, in combination +with this scheduling algorithm and buffer limiters in the stack +this can result in limited throughput. This change causes the +flow worker to be scheduled more frequently from tx. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Daniel (Deognyoun) Kim +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +@@ -249,8 +249,8 @@ void brcmf_flowring_delete(struct brcmf_ + } + + +-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, +- struct sk_buff *skb) ++u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, ++ struct sk_buff *skb) + { + struct brcmf_flowring_ring *ring; + +@@ -271,6 +271,7 @@ void brcmf_flowring_enqueue(struct brcmf + if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW) + brcmf_flowring_block(flow, flowid, false); + } ++ return skb_queue_len(&ring->skblist); + } + + +--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h +@@ -64,8 +64,8 @@ u32 brcmf_flowring_create(struct brcmf_f + void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid); + void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid); + u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid); +-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, +- struct sk_buff *skb); ++u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, ++ struct sk_buff *skb); + struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid); + void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, + struct sk_buff *skb); +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -73,7 +73,7 @@ + #define BRCMF_MSGBUF_TX_FLUSH_CNT1 32 + #define BRCMF_MSGBUF_TX_FLUSH_CNT2 96 + +-#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64 ++#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 96 + #define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32 + + struct msgbuf_common_hdr { +@@ -797,6 +797,8 @@ static int brcmf_msgbuf_txdata(struct br + struct brcmf_flowring *flow = msgbuf->flow; + struct ethhdr *eh = (struct ethhdr *)(skb->data); + u32 flowid; ++ u32 queue_count; ++ bool force; + + flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx); + if (flowid == BRCMF_FLOWRING_INVALID_ID) { +@@ -804,8 +806,9 @@ static int brcmf_msgbuf_txdata(struct br + if (flowid == BRCMF_FLOWRING_INVALID_ID) + return -ENOMEM; + } +- brcmf_flowring_enqueue(flow, flowid, skb); +- brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false); ++ queue_count = brcmf_flowring_enqueue(flow, flowid, skb); ++ force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0); ++ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, force); + + return 0; + } diff --git a/package/kernel/mac80211/patches/370-brcmfmac-remove-pci-shared-structure-rev4-support.patch b/package/kernel/mac80211/patches/370-brcmfmac-remove-pci-shared-structure-rev4-support.patch new file mode 100644 index 0000000000..61153c4a98 --- /dev/null +++ b/package/kernel/mac80211/patches/370-brcmfmac-remove-pci-shared-structure-rev4-support.patch @@ -0,0 +1,41 @@ +From: Franky Lin +Date: Wed, 20 May 2015 14:09:49 +0200 +Subject: [PATCH] brcmfmac: remove pci shared structure rev4 support + +All pcie full dongle chips supported by fmac are using rev 5+ shared +structure. This patch removes the rev4 related code. + +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Hante Meuleman +Reviewed-by: Arend Van Spriel +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -112,10 +112,9 @@ enum brcmf_pcie_state { + BRCMF_PCIE_MB_INT_D2H3_DB0 | \ + BRCMF_PCIE_MB_INT_D2H3_DB1) + +-#define BRCMF_PCIE_MIN_SHARED_VERSION 4 ++#define BRCMF_PCIE_MIN_SHARED_VERSION 5 + #define BRCMF_PCIE_MAX_SHARED_VERSION 5 + #define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF +-#define BRCMF_PCIE_SHARED_TXPUSH_SUPPORT 0x4000 + + #define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000 + #define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000 +@@ -1280,11 +1279,6 @@ brcmf_pcie_init_share_ram_info(struct br + brcmf_err("Unsupported PCIE version %d\n", version); + return -EINVAL; + } +- if (shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT) { +- brcmf_err("Unsupported legacy TX mode 0x%x\n", +- shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT); +- return -EINVAL; +- } + + addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET; + shared->max_rxbufpost = brcmf_pcie_read_tcm16(devinfo, addr); diff --git a/package/kernel/mac80211/patches/371-brcmfmac-remove-dummy-cache-flush-invalidate-functio.patch b/package/kernel/mac80211/patches/371-brcmfmac-remove-dummy-cache-flush-invalidate-functio.patch new file mode 100644 index 0000000000..8c8eebe44f --- /dev/null +++ b/package/kernel/mac80211/patches/371-brcmfmac-remove-dummy-cache-flush-invalidate-functio.patch @@ -0,0 +1,120 @@ +From: Franky Lin +Date: Wed, 20 May 2015 14:09:50 +0200 +Subject: [PATCH] brcmfmac: remove dummy cache flush/invalidate function + +brcmf_dma_flush and brcmf_dma_invalidate_cache are not necessary and +have never been implemented. + +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Hante Meuleman +Reviewed-by: Arend Van Spriel +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c +@@ -22,17 +22,6 @@ + #include "core.h" + #include "commonring.h" + +- +-/* dma flushing needs implementation for mips and arm platforms. Should +- * be put in util. Note, this is not real flushing. It is virtual non +- * cached memory. Only write buffers should have to be drained. Though +- * this may be different depending on platform...... +- * SEE ALSO msgbuf.c +- */ +-#define brcmf_dma_flush(addr, len) +-#define brcmf_dma_invalidate_cache(addr, len) +- +- + void brcmf_commonring_register_cb(struct brcmf_commonring *commonring, + int (*cr_ring_bell)(void *ctx), + int (*cr_update_rptr)(void *ctx), +@@ -206,14 +195,9 @@ int brcmf_commonring_write_complete(stru + address = commonring->buf_addr; + address += (commonring->f_ptr * commonring->item_len); + if (commonring->f_ptr > commonring->w_ptr) { +- brcmf_dma_flush(address, +- (commonring->depth - commonring->f_ptr) * +- commonring->item_len); + address = commonring->buf_addr; + commonring->f_ptr = 0; + } +- brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) * +- commonring->item_len); + + commonring->f_ptr = commonring->w_ptr; + +@@ -258,8 +242,6 @@ void *brcmf_commonring_get_read_ptr(stru + if (commonring->r_ptr == commonring->depth) + commonring->r_ptr = 0; + +- brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len); +- + return ret_addr; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -278,16 +278,6 @@ struct brcmf_msgbuf_pktids { + struct brcmf_msgbuf_pktid *array; + }; + +- +-/* dma flushing needs implementation for mips and arm platforms. Should +- * be put in util. Note, this is not real flushing. It is virtual non +- * cached memory. Only write buffers should have to be drained. Though +- * this may be different depending on platform...... +- */ +-#define brcmf_dma_flush(addr, len) +-#define brcmf_dma_invalidate_cache(addr, len) +- +- + static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf); + + +@@ -462,7 +452,6 @@ static int brcmf_msgbuf_tx_ioctl(struct + memcpy(msgbuf->ioctbuf, buf, buf_len); + else + memset(msgbuf->ioctbuf, 0, buf_len); +- brcmf_dma_flush(ioctl_buf, buf_len); + + err = brcmf_commonring_write_complete(commonring); + brcmf_commonring_unlock(commonring); +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -276,15 +276,6 @@ static const u32 brcmf_ring_itemsize[BRC + }; + + +-/* dma flushing needs implementation for mips and arm platforms. Should +- * be put in util. Note, this is not real flushing. It is virtual non +- * cached memory. Only write buffers should have to be drained. Though +- * this may be different depending on platform...... +- */ +-#define brcmf_dma_flush(addr, len) +-#define brcmf_dma_invalidate_cache(addr, len) +- +- + static u32 + brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset) + { +@@ -1174,7 +1165,6 @@ static int brcmf_pcie_init_scratchbuffer + goto fail; + + memset(devinfo->shared.scratch, 0, BRCMF_DMA_D2H_SCRATCH_BUF_LEN); +- brcmf_dma_flush(devinfo->shared.scratch, BRCMF_DMA_D2H_SCRATCH_BUF_LEN); + + addr = devinfo->shared.tcm_base_address + + BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET; +@@ -1192,7 +1182,6 @@ static int brcmf_pcie_init_scratchbuffer + goto fail; + + memset(devinfo->shared.ringupd, 0, BRCMF_DMA_D2H_RINGUPD_BUF_LEN); +- brcmf_dma_flush(devinfo->shared.ringupd, BRCMF_DMA_D2H_RINGUPD_BUF_LEN); + + addr = devinfo->shared.tcm_base_address + + BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET; diff --git a/package/kernel/mac80211/patches/372-brcmfmac-add-support-for-dma-indices-feature.patch b/package/kernel/mac80211/patches/372-brcmfmac-add-support-for-dma-indices-feature.patch new file mode 100644 index 0000000000..2f50abd0e1 --- /dev/null +++ b/package/kernel/mac80211/patches/372-brcmfmac-add-support-for-dma-indices-feature.patch @@ -0,0 +1,270 @@ +From: Franky Lin +Date: Wed, 20 May 2015 14:09:51 +0200 +Subject: [PATCH] brcmfmac: add support for dma indices feature + +PCIe full dongle firmware can support a dma indices feature with which +firmware can update/fetch the read/write indices of message buffer +rings on both host to dongle and dongle to host directions. The support is +announced by firmware through shared flags. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -115,6 +115,8 @@ enum brcmf_pcie_state { + #define BRCMF_PCIE_MIN_SHARED_VERSION 5 + #define BRCMF_PCIE_MAX_SHARED_VERSION 5 + #define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF ++#define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000 ++#define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000 + + #define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000 + #define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000 +@@ -146,6 +148,10 @@ enum brcmf_pcie_state { + #define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8 + #define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12 + #define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16 ++#define BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET 20 ++#define BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET 28 ++#define BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET 36 ++#define BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET 44 + #define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0 + #define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52 + +@@ -247,6 +253,13 @@ struct brcmf_pciedev_info { + bool mbdata_completed; + bool irq_allocated; + bool wowl_enabled; ++ u8 dma_idx_sz; ++ void *idxbuf; ++ u32 idxbuf_sz; ++ dma_addr_t idxbuf_dmahandle; ++ u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset); ++ void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset, ++ u16 value); + }; + + struct brcmf_pcie_ringbuf { +@@ -323,6 +336,25 @@ brcmf_pcie_write_tcm16(struct brcmf_pcie + } + + ++static u16 ++brcmf_pcie_read_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset) ++{ ++ u16 *address = devinfo->idxbuf + mem_offset; ++ ++ return (*(address)); ++} ++ ++ ++static void ++brcmf_pcie_write_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset, ++ u16 value) ++{ ++ u16 *address = devinfo->idxbuf + mem_offset; ++ ++ *(address) = value; ++} ++ ++ + static u32 + brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) + { +@@ -868,7 +900,7 @@ static int brcmf_pcie_ring_mb_write_rptr + brcmf_dbg(PCIE, "W r_ptr %d (%d), ring %d\n", commonring->r_ptr, + commonring->w_ptr, ring->id); + +- brcmf_pcie_write_tcm16(devinfo, ring->r_idx_addr, commonring->r_ptr); ++ devinfo->write_ptr(devinfo, ring->r_idx_addr, commonring->r_ptr); + + return 0; + } +@@ -886,7 +918,7 @@ static int brcmf_pcie_ring_mb_write_wptr + brcmf_dbg(PCIE, "W w_ptr %d (%d), ring %d\n", commonring->w_ptr, + commonring->r_ptr, ring->id); + +- brcmf_pcie_write_tcm16(devinfo, ring->w_idx_addr, commonring->w_ptr); ++ devinfo->write_ptr(devinfo, ring->w_idx_addr, commonring->w_ptr); + + return 0; + } +@@ -915,7 +947,7 @@ static int brcmf_pcie_ring_mb_update_rpt + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + +- commonring->r_ptr = brcmf_pcie_read_tcm16(devinfo, ring->r_idx_addr); ++ commonring->r_ptr = devinfo->read_ptr(devinfo, ring->r_idx_addr); + + brcmf_dbg(PCIE, "R r_ptr %d (%d), ring %d\n", commonring->r_ptr, + commonring->w_ptr, ring->id); +@@ -933,7 +965,7 @@ static int brcmf_pcie_ring_mb_update_wpt + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + +- commonring->w_ptr = brcmf_pcie_read_tcm16(devinfo, ring->w_idx_addr); ++ commonring->w_ptr = devinfo->read_ptr(devinfo, ring->w_idx_addr); + + brcmf_dbg(PCIE, "R w_ptr %d (%d), ring %d\n", commonring->w_ptr, + commonring->r_ptr, ring->id); +@@ -1038,6 +1070,13 @@ static void brcmf_pcie_release_ringbuffe + } + kfree(devinfo->shared.flowrings); + devinfo->shared.flowrings = NULL; ++ if (devinfo->idxbuf) { ++ dma_free_coherent(&devinfo->pdev->dev, ++ devinfo->idxbuf_sz, ++ devinfo->idxbuf, ++ devinfo->idxbuf_dmahandle); ++ devinfo->idxbuf = NULL; ++ } + } + + +@@ -1053,19 +1092,72 @@ static int brcmf_pcie_init_ringbuffers(s + u32 addr; + u32 ring_mem_ptr; + u32 i; ++ u64 address; ++ u32 bufsz; + u16 max_sub_queues; ++ u8 idx_offset; + + ring_addr = devinfo->shared.ring_info_addr; + brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr); ++ addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES; ++ max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr); + +- addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET; +- d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); +- addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET; +- d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); +- addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET; +- h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); +- addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET; +- h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); ++ if (devinfo->dma_idx_sz != 0) { ++ bufsz = (BRCMF_NROF_D2H_COMMON_MSGRINGS + max_sub_queues) * ++ devinfo->dma_idx_sz * 2; ++ devinfo->idxbuf = dma_alloc_coherent(&devinfo->pdev->dev, bufsz, ++ &devinfo->idxbuf_dmahandle, ++ GFP_KERNEL); ++ if (!devinfo->idxbuf) ++ devinfo->dma_idx_sz = 0; ++ } ++ ++ if (devinfo->dma_idx_sz == 0) { ++ addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET; ++ d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); ++ addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET; ++ d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); ++ addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET; ++ h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); ++ addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET; ++ h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); ++ idx_offset = sizeof(u32); ++ devinfo->write_ptr = brcmf_pcie_write_tcm16; ++ devinfo->read_ptr = brcmf_pcie_read_tcm16; ++ brcmf_dbg(PCIE, "Using TCM indices\n"); ++ } else { ++ memset(devinfo->idxbuf, 0, bufsz); ++ devinfo->idxbuf_sz = bufsz; ++ idx_offset = devinfo->dma_idx_sz; ++ devinfo->write_ptr = brcmf_pcie_write_idx; ++ devinfo->read_ptr = brcmf_pcie_read_idx; ++ ++ h2d_w_idx_ptr = 0; ++ addr = ring_addr + BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET; ++ address = (u64)devinfo->idxbuf_dmahandle; ++ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); ++ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); ++ ++ h2d_r_idx_ptr = h2d_w_idx_ptr + max_sub_queues * idx_offset; ++ addr = ring_addr + BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET; ++ address += max_sub_queues * idx_offset; ++ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); ++ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); ++ ++ d2h_w_idx_ptr = h2d_r_idx_ptr + max_sub_queues * idx_offset; ++ addr = ring_addr + BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET; ++ address += max_sub_queues * idx_offset; ++ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); ++ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); ++ ++ d2h_r_idx_ptr = d2h_w_idx_ptr + ++ BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset; ++ addr = ring_addr + BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET; ++ address += BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset; ++ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); ++ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); ++ brcmf_dbg(PCIE, "Using host memory indices\n"); ++ } + + addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET; + ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr); +@@ -1079,8 +1171,8 @@ static int brcmf_pcie_init_ringbuffers(s + ring->id = i; + devinfo->shared.commonrings[i] = ring; + +- h2d_w_idx_ptr += sizeof(u32); +- h2d_r_idx_ptr += sizeof(u32); ++ h2d_w_idx_ptr += idx_offset; ++ h2d_r_idx_ptr += idx_offset; + ring_mem_ptr += BRCMF_RING_MEM_SZ; + } + +@@ -1094,13 +1186,11 @@ static int brcmf_pcie_init_ringbuffers(s + ring->id = i; + devinfo->shared.commonrings[i] = ring; + +- d2h_w_idx_ptr += sizeof(u32); +- d2h_r_idx_ptr += sizeof(u32); ++ d2h_w_idx_ptr += idx_offset; ++ d2h_r_idx_ptr += idx_offset; + ring_mem_ptr += BRCMF_RING_MEM_SZ; + } + +- addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES; +- max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr); + devinfo->shared.nrof_flowrings = + max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS; + rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring), +@@ -1124,15 +1214,15 @@ static int brcmf_pcie_init_ringbuffers(s + ring); + ring->w_idx_addr = h2d_w_idx_ptr; + ring->r_idx_addr = h2d_r_idx_ptr; +- h2d_w_idx_ptr += sizeof(u32); +- h2d_r_idx_ptr += sizeof(u32); ++ h2d_w_idx_ptr += idx_offset; ++ h2d_r_idx_ptr += idx_offset; + } + devinfo->shared.flowrings = rings; + + return 0; + + fail: +- brcmf_err("Allocating commonring buffers failed\n"); ++ brcmf_err("Allocating ring buffers failed\n"); + brcmf_pcie_release_ringbuffers(devinfo); + return -ENOMEM; + } +@@ -1269,6 +1359,14 @@ brcmf_pcie_init_share_ram_info(struct br + return -EINVAL; + } + ++ /* check firmware support dma indicies */ ++ if (shared->flags & BRCMF_PCIE_SHARED_DMA_INDEX) { ++ if (shared->flags & BRCMF_PCIE_SHARED_DMA_2B_IDX) ++ devinfo->dma_idx_sz = sizeof(u16); ++ else ++ devinfo->dma_idx_sz = sizeof(u32); ++ } ++ + addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET; + shared->max_rxbufpost = brcmf_pcie_read_tcm16(devinfo, addr); + if (shared->max_rxbufpost == 0)