From e2bb52def5cd5ac268c33cedc32891431362e260 Mon Sep 17 00:00:00 2001 From: Jason Mei Date: Mon, 17 Jun 2024 09:43:08 +0800 Subject: [PATCH] PCI: EPF: tvnet: disable the edma interrupt 1. Disable the corresponding PCIe EP controller EDMA interrupt. 2. Disable IP checksum to improve performance since the PCIe link is reliable. 3. DMA unmap matches the map size. 4. Adjust the SKB buffer link list handle. Bug 4704944 Signed-off-by: Jason Mei Change-Id: I05f76fa60e3533c2dd01e53ed17664d6898fcffd Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3158126 Reviewed-by: svcacv Reviewed-by: Nagarjuna Kristam GVS: buildbot_gerritrpt Reviewed-by: Bibek Basu --- drivers/net/ethernet/nvidia/pcie/tegra_vnet.c | 11 ++++-- .../endpoint/functions/pci-epf-tegra-vnet.c | 34 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c b/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c index 4748b8bd..18373a33 100644 --- a/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c +++ b/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c @@ -183,6 +183,11 @@ static void tvnet_host_alloc_empty_buffers(struct tvnet_priv *tvnet) break; } + /* The PCIe link is stable and dependable, + * so it's not necessary to perform a software checksum. + */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + ep2h_empty_ptr = kmalloc(sizeof(*ep2h_empty_ptr), GFP_ATOMIC); if (!ep2h_empty_ptr) { dma_unmap_single(d, iova, len, DMA_FROM_DEVICE); @@ -651,16 +656,18 @@ static int tvnet_host_process_ep2h_msg(struct tvnet_priv *tvnet) list_for_each_entry(ep2h_empty_ptr, &tvnet->ep2h_empty_list, list) { if (ep2h_empty_ptr->iova == pcie_address) { + list_del(&ep2h_empty_ptr->list); found = 1; break; } } - WARN_ON(!found); - list_del(&ep2h_empty_ptr->list); spin_unlock_irqrestore(&tvnet->ep2h_empty_lock, flags); /* Advance H2EP full buffer after search in local list */ tvnet_ivc_advance_rd(&tvnet->ep2h_full); + if (WARN_ON(!found)) + continue; + /* If EP2H network queue is stopped due to lack of EP2H_FULL * queue, raising ctrl irq will help. */ diff --git a/drivers/pci/endpoint/functions/pci-epf-tegra-vnet.c b/drivers/pci/endpoint/functions/pci-epf-tegra-vnet.c index 02e3917c..d85bad5b 100644 --- a/drivers/pci/endpoint/functions/pci-epf-tegra-vnet.c +++ b/drivers/pci/endpoint/functions/pci-epf-tegra-vnet.c @@ -30,6 +30,8 @@ #endif #define BAR0_SIZE SZ_4M +#define APPL_INTR_EN_L1_8_0 0x44 +#define APPL_INTR_EN_L1_8_EDMA_INT_EN BIT(6) enum bar0_amap_type { META_DATA, @@ -146,6 +148,8 @@ struct pci_epf_tvnet { /* IOVA alloc abstraction.*/ struct iova_domain *iovad; struct iova *iova; + struct resource *appl_res; + void __iomem *appl_base; #endif }; @@ -304,6 +308,10 @@ static void tvnet_ep_alloc_empty_buffers(struct pci_epf_tvnet *tvnet) break; } + /* The PCIe link is stable and dependable, + * so it's not necessary to perform a software checksum. + */ + skb->ip_summed = CHECKSUM_UNNECESSARY; #else iova = tvnet_ivoa_alloc(tvnet); if (iova == DMA_ERROR_CODE) { @@ -849,18 +857,19 @@ static int tvnet_ep_process_h2ep_msg(struct pci_epf_tvnet *tvnet) list_for_each_entry(h2ep_empty_ptr, &tvnet->h2ep_empty_list, list) { if (h2ep_empty_ptr->iova == pcie_address) { + list_del(&h2ep_empty_ptr->list); found = 1; break; } } - WARN_ON(!found); - list_del(&h2ep_empty_ptr->list); spin_unlock_irqrestore(&tvnet->h2ep_empty_lock, flags); /* Advance H2EP full buffer after search in local list */ tvnet_ivc_advance_rd(&tvnet->h2ep_full); + if (WARN_ON(!found)) + continue; #if ENABLE_DMA - dma_unmap_single(cdev, pcie_address, ndev->mtu, + dma_unmap_single(cdev, pcie_address, ndev->mtu + ETH_HLEN, DMA_FROM_DEVICE); skb = h2ep_empty_ptr->skb; skb_put(skb, len); @@ -1597,7 +1606,7 @@ static void tvnet_ep_pci_epf_linkup(struct pci_epf *epf) #endif { struct pci_epf_tvnet *tvnet = epf_get_drvdata(epf); - + u32 val; #if ENABLE_DMA tvnet_ep_setup_dma(tvnet); #endif @@ -1611,6 +1620,11 @@ static void tvnet_ep_pci_epf_linkup(struct pci_epf *epf) tvnet->pcie_link_status = true; #if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 14, 0)) + val = readl(tvnet->appl_base + APPL_INTR_EN_L1_8_0); + if (val & APPL_INTR_EN_L1_8_EDMA_INT_EN) + writel(val & ~APPL_INTR_EN_L1_8_EDMA_INT_EN, + tvnet->appl_base + APPL_INTR_EN_L1_8_0); + return 0; #endif } @@ -1714,6 +1728,18 @@ static int tvnet_ep_pci_epf_bind(struct pci_epf *epf) goto fail; } + tvnet->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "appl"); + if (!tvnet->appl_res) { + dev_err(fdev, "Failed to find \"appl\" region\n"); + goto fail; + } + + tvnet->appl_base = devm_ioremap(fdev, tvnet->appl_res->start, + PAGE_SIZE); + if (IS_ERR(tvnet->appl_base)) + goto fail; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 14, 0)) tvnet->iovad = (struct iova_domain *)&domain->iova_cookie->iovad;