Commit 1d5e3b90 authored by Sergey Matyukevich's avatar Sergey Matyukevich Committed by Kalle Valo

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: default avatarSergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent dcdd54c2
...@@ -478,10 +478,11 @@ static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment