qtnfmac: fix releasing Tx/Rx data buffers

Add missing PCI unmap for Tx buffers and release all buffers explicitly.
Managed release using devm_add_action is not suitable for qtnfmac Tx/Rx
data buffers. The reason is in ordering and dependencies: buffers
should be released after transmission is stopped but before PCI
device resources and DMA allocations are released.

Signed-off-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Sergey Matyukevich 2018-02-10 17:04:17 +03:00 committed by Kalle Valo
parent dcdd54c2bc
commit 1d5e3b90ab
1 changed files with 18 additions and 12 deletions

View File

@ -478,10 +478,11 @@ static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv)
} }
/* all rx/tx activity should have ceased before calling this function */ /* all rx/tx activity should have ceased before calling this function */
static void free_xfer_buffers(void *data) static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv)
{ {
struct qtnf_pcie_bus_priv *priv = (struct qtnf_pcie_bus_priv *)data; struct qtnf_tx_bd *txbd;
struct qtnf_rx_bd *rxbd; struct qtnf_rx_bd *rxbd;
struct sk_buff *skb;
dma_addr_t paddr; dma_addr_t paddr;
int i; int i;
@ -489,19 +490,26 @@ static void free_xfer_buffers(void *data)
for (i = 0; i < priv->rx_bd_num; i++) { for (i = 0; i < priv->rx_bd_num; i++) {
if (priv->rx_skb && priv->rx_skb[i]) { if (priv->rx_skb && priv->rx_skb[i]) {
rxbd = &priv->rx_bd_vbase[i]; rxbd = &priv->rx_bd_vbase[i];
skb = priv->rx_skb[i];
paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h),
le32_to_cpu(rxbd->addr)); le32_to_cpu(rxbd->addr));
pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
dev_kfree_skb_any(priv->rx_skb[i]); priv->rx_skb[i] = NULL;
} }
} }
/* free tx buffers */ /* free tx buffers */
for (i = 0; i < priv->tx_bd_num; i++) { for (i = 0; i < priv->tx_bd_num; i++) {
if (priv->tx_skb && priv->tx_skb[i]) { if (priv->tx_skb && priv->tx_skb[i]) {
dev_kfree_skb_any(priv->tx_skb[i]); txbd = &priv->tx_bd_vbase[i];
skb = priv->tx_skb[i];
paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h),
le32_to_cpu(txbd->addr));
pci_unmap_single(priv->pdev, paddr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
priv->tx_skb[i] = NULL; priv->tx_skb[i] = NULL;
} }
} }
@ -1321,12 +1329,6 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_base; goto err_base;
} }
ret = devm_add_action(&pdev->dev, free_xfer_buffers, (void *)pcie_priv);
if (ret) {
pr_err("custom release callback init failed\n");
goto err_base;
}
ret = qtnf_pcie_init_xfer(pcie_priv); ret = qtnf_pcie_init_xfer(pcie_priv);
if (ret) { if (ret) {
pr_err("PCIE xfer init failed\n"); pr_err("PCIE xfer init failed\n");
@ -1343,7 +1345,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
"qtnf_pcie_irq", (void *)bus); "qtnf_pcie_irq", (void *)bus);
if (ret) { if (ret) {
pr_err("failed to request pcie irq %d\n", pdev->irq); pr_err("failed to request pcie irq %d\n", pdev->irq);
goto err_base; goto err_xfer;
} }
tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn,
@ -1387,6 +1389,9 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_bringup_fw: err_bringup_fw:
netif_napi_del(&bus->mux_napi); netif_napi_del(&bus->mux_napi);
err_xfer:
qtnf_free_xfer_buffers(pcie_priv);
err_base: err_base:
flush_workqueue(pcie_priv->workqueue); flush_workqueue(pcie_priv->workqueue);
destroy_workqueue(pcie_priv->workqueue); destroy_workqueue(pcie_priv->workqueue);
@ -1416,6 +1421,7 @@ static void qtnf_pcie_remove(struct pci_dev *pdev)
destroy_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue);
tasklet_kill(&priv->reclaim_tq); tasklet_kill(&priv->reclaim_tq);
qtnf_free_xfer_buffers(priv);
qtnf_debugfs_remove(bus); qtnf_debugfs_remove(bus);
qtnf_pcie_free_shm_ipc(priv); qtnf_pcie_free_shm_ipc(priv);