18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2017 Cadence 38c2ecf20Sopenharmony_ci// Cadence PCIe endpoint controller driver. 48c2ecf20Sopenharmony_ci// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/delay.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/of.h> 98c2ecf20Sopenharmony_ci#include <linux/pci-epc.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/sizes.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "pcie-cadence.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */ 168c2ecf20Sopenharmony_ci#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1 178c2ecf20Sopenharmony_ci#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x3 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, 208c2ecf20Sopenharmony_ci struct pci_epf_header *hdr) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 238c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid); 268c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid); 278c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code); 288c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE, 298c2ecf20Sopenharmony_ci hdr->subclass_code | hdr->baseclass_code << 8); 308c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE, 318c2ecf20Sopenharmony_ci hdr->cache_line_size); 328c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id); 338c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* 368c2ecf20Sopenharmony_ci * Vendor ID can only be modified from function 0, all other functions 378c2ecf20Sopenharmony_ci * use the same vendor ID as function 0. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci if (fn == 0) { 408c2ecf20Sopenharmony_ci /* Update the vendor IDs. */ 418c2ecf20Sopenharmony_ci u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) | 428c2ecf20Sopenharmony_ci CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, 518c2ecf20Sopenharmony_ci struct pci_epf_bar *epf_bar) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 548c2ecf20Sopenharmony_ci struct cdns_pcie_epf *epf = &ep->epf[fn]; 558c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 568c2ecf20Sopenharmony_ci dma_addr_t bar_phys = epf_bar->phys_addr; 578c2ecf20Sopenharmony_ci enum pci_barno bar = epf_bar->barno; 588c2ecf20Sopenharmony_ci int flags = epf_bar->flags; 598c2ecf20Sopenharmony_ci u32 addr0, addr1, reg, cfg, b, aperture, ctrl; 608c2ecf20Sopenharmony_ci u64 sz; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* BAR size is 2^(aperture + 7) */ 638c2ecf20Sopenharmony_ci sz = max_t(size_t, epf_bar->size, CDNS_PCIE_EP_MIN_APERTURE); 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * roundup_pow_of_two() returns an unsigned long, which is not suited 668c2ecf20Sopenharmony_ci * for 64bit values. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci sz = 1ULL << fls64(sz - 1); 698c2ecf20Sopenharmony_ci aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { 728c2ecf20Sopenharmony_ci ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS; 738c2ecf20Sopenharmony_ci } else { 748c2ecf20Sopenharmony_ci bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH); 758c2ecf20Sopenharmony_ci bool is_64bits = sz > SZ_2G; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (is_64bits && (bar & 1)) 788c2ecf20Sopenharmony_ci return -EINVAL; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) 818c2ecf20Sopenharmony_ci epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (is_64bits && is_prefetch) 848c2ecf20Sopenharmony_ci ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS; 858c2ecf20Sopenharmony_ci else if (is_prefetch) 868c2ecf20Sopenharmony_ci ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS; 878c2ecf20Sopenharmony_ci else if (is_64bits) 888c2ecf20Sopenharmony_ci ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS; 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci addr0 = lower_32_bits(bar_phys); 948c2ecf20Sopenharmony_ci addr1 = upper_32_bits(bar_phys); 958c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 968c2ecf20Sopenharmony_ci addr0); 978c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 988c2ecf20Sopenharmony_ci addr1); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (bar < BAR_4) { 1018c2ecf20Sopenharmony_ci reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn); 1028c2ecf20Sopenharmony_ci b = bar; 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn); 1058c2ecf20Sopenharmony_ci b = bar - BAR_4; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci cfg = cdns_pcie_readl(pcie, reg); 1098c2ecf20Sopenharmony_ci cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | 1108c2ecf20Sopenharmony_ci CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); 1118c2ecf20Sopenharmony_ci cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) | 1128c2ecf20Sopenharmony_ci CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl)); 1138c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, reg, cfg); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci epf->epf_bar[bar] = epf_bar; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, 1218c2ecf20Sopenharmony_ci struct pci_epf_bar *epf_bar) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 1248c2ecf20Sopenharmony_ci struct cdns_pcie_epf *epf = &ep->epf[fn]; 1258c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 1268c2ecf20Sopenharmony_ci enum pci_barno bar = epf_bar->barno; 1278c2ecf20Sopenharmony_ci u32 reg, cfg, b, ctrl; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (bar < BAR_4) { 1308c2ecf20Sopenharmony_ci reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn); 1318c2ecf20Sopenharmony_ci b = bar; 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn); 1348c2ecf20Sopenharmony_ci b = bar - BAR_4; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; 1388c2ecf20Sopenharmony_ci cfg = cdns_pcie_readl(pcie, reg); 1398c2ecf20Sopenharmony_ci cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | 1408c2ecf20Sopenharmony_ci CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); 1418c2ecf20Sopenharmony_ci cfg |= CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl); 1428c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, reg, cfg); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0); 1458c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci epf->epf_bar[bar] = NULL; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr, 1518c2ecf20Sopenharmony_ci u64 pci_addr, size_t size) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 1548c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 1558c2ecf20Sopenharmony_ci u32 r; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG); 1588c2ecf20Sopenharmony_ci if (r >= ep->max_regions - 1) { 1598c2ecf20Sopenharmony_ci dev_err(&epc->dev, "no free outbound region\n"); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci cdns_pcie_set_outbound_region(pcie, 0, fn, r, false, addr, pci_addr, size); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci set_bit(r, &ep->ob_region_map); 1668c2ecf20Sopenharmony_ci ep->ob_addr[r] = addr; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, 1728c2ecf20Sopenharmony_ci phys_addr_t addr) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 1758c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 1768c2ecf20Sopenharmony_ci u32 r; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for (r = 0; r < ep->max_regions - 1; r++) 1798c2ecf20Sopenharmony_ci if (ep->ob_addr[r] == addr) 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (r == ep->max_regions - 1) 1838c2ecf20Sopenharmony_ci return; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci cdns_pcie_reset_outbound_region(pcie, r); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ep->ob_addr[r] = 0; 1888c2ecf20Sopenharmony_ci clear_bit(r, &ep->ob_region_map); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 mmc) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 1948c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 1958c2ecf20Sopenharmony_ci u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; 1968c2ecf20Sopenharmony_ci u16 flags; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * Set the Multiple Message Capable bitfield into the Message Control 2008c2ecf20Sopenharmony_ci * register. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); 2038c2ecf20Sopenharmony_ci flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1); 2048c2ecf20Sopenharmony_ci flags |= PCI_MSI_FLAGS_64BIT; 2058c2ecf20Sopenharmony_ci flags &= ~PCI_MSI_FLAGS_MASKBIT; 2068c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 2148c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 2158c2ecf20Sopenharmony_ci u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; 2168c2ecf20Sopenharmony_ci u16 flags, mme; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Validate that the MSI feature is actually enabled. */ 2198c2ecf20Sopenharmony_ci flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); 2208c2ecf20Sopenharmony_ci if (!(flags & PCI_MSI_FLAGS_ENABLE)) 2218c2ecf20Sopenharmony_ci return -EINVAL; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * Get the Multiple Message Enable bitfield from the Message Control 2258c2ecf20Sopenharmony_ci * register. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return mme; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 2358c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 2368c2ecf20Sopenharmony_ci u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; 2378c2ecf20Sopenharmony_ci u32 val, reg; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci reg = cap + PCI_MSIX_FLAGS; 2408c2ecf20Sopenharmony_ci val = cdns_pcie_ep_fn_readw(pcie, func_no, reg); 2418c2ecf20Sopenharmony_ci if (!(val & PCI_MSIX_FLAGS_ENABLE)) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci val &= PCI_MSIX_FLAGS_QSIZE; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return val; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts, 2508c2ecf20Sopenharmony_ci enum pci_barno bir, u32 offset) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 2538c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 2548c2ecf20Sopenharmony_ci u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; 2558c2ecf20Sopenharmony_ci u32 val, reg; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci reg = cap + PCI_MSIX_FLAGS; 2588c2ecf20Sopenharmony_ci val = cdns_pcie_ep_fn_readw(pcie, fn, reg); 2598c2ecf20Sopenharmony_ci val &= ~PCI_MSIX_FLAGS_QSIZE; 2608c2ecf20Sopenharmony_ci val |= interrupts; 2618c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writew(pcie, fn, reg, val); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Set MSIX BAR and offset */ 2648c2ecf20Sopenharmony_ci reg = cap + PCI_MSIX_TABLE; 2658c2ecf20Sopenharmony_ci val = offset | bir; 2668c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writel(pcie, fn, reg, val); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Set PBA BAR and offset. BAR must match MSIX BAR */ 2698c2ecf20Sopenharmony_ci reg = cap + PCI_MSIX_PBA; 2708c2ecf20Sopenharmony_ci val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; 2718c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writel(pcie, fn, reg, val); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, 2778c2ecf20Sopenharmony_ci u8 intx, bool is_asserted) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 2808c2ecf20Sopenharmony_ci unsigned long flags; 2818c2ecf20Sopenharmony_ci u32 offset; 2828c2ecf20Sopenharmony_ci u16 status; 2838c2ecf20Sopenharmony_ci u8 msg_code; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci intx &= 3; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Set the outbound region if needed. */ 2888c2ecf20Sopenharmony_ci if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY || 2898c2ecf20Sopenharmony_ci ep->irq_pci_fn != fn)) { 2908c2ecf20Sopenharmony_ci /* First region was reserved for IRQ writes. */ 2918c2ecf20Sopenharmony_ci cdns_pcie_set_outbound_region_for_normal_msg(pcie, 0, fn, 0, 2928c2ecf20Sopenharmony_ci ep->irq_phys_addr); 2938c2ecf20Sopenharmony_ci ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY; 2948c2ecf20Sopenharmony_ci ep->irq_pci_fn = fn; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (is_asserted) { 2988c2ecf20Sopenharmony_ci ep->irq_pending |= BIT(intx); 2998c2ecf20Sopenharmony_ci msg_code = MSG_CODE_ASSERT_INTA + intx; 3008c2ecf20Sopenharmony_ci } else { 3018c2ecf20Sopenharmony_ci ep->irq_pending &= ~BIT(intx); 3028c2ecf20Sopenharmony_ci msg_code = MSG_CODE_DEASSERT_INTA + intx; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 3068c2ecf20Sopenharmony_ci status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS); 3078c2ecf20Sopenharmony_ci if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) { 3088c2ecf20Sopenharmony_ci status ^= PCI_STATUS_INTERRUPT; 3098c2ecf20Sopenharmony_ci cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) | 3148c2ecf20Sopenharmony_ci CDNS_PCIE_NORMAL_MSG_CODE(msg_code) | 3158c2ecf20Sopenharmony_ci CDNS_PCIE_MSG_NO_DATA; 3168c2ecf20Sopenharmony_ci writel(0, ep->irq_cpu_addr + offset); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci u16 cmd; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND); 3248c2ecf20Sopenharmony_ci if (cmd & PCI_COMMAND_INTX_DISABLE) 3258c2ecf20Sopenharmony_ci return -EINVAL; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci cdns_pcie_ep_assert_intx(ep, fn, intx, true); 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq() 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci mdelay(1); 3328c2ecf20Sopenharmony_ci cdns_pcie_ep_assert_intx(ep, fn, intx, false); 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, 3378c2ecf20Sopenharmony_ci u8 interrupt_num) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 3408c2ecf20Sopenharmony_ci u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; 3418c2ecf20Sopenharmony_ci u16 flags, mme, data, data_mask; 3428c2ecf20Sopenharmony_ci u8 msi_count; 3438c2ecf20Sopenharmony_ci u64 pci_addr, pci_addr_mask = 0xff; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* Check whether the MSI feature has been enabled by the PCI host. */ 3468c2ecf20Sopenharmony_ci flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); 3478c2ecf20Sopenharmony_ci if (!(flags & PCI_MSI_FLAGS_ENABLE)) 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Get the number of enabled MSIs */ 3518c2ecf20Sopenharmony_ci mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4; 3528c2ecf20Sopenharmony_ci msi_count = 1 << mme; 3538c2ecf20Sopenharmony_ci if (!interrupt_num || interrupt_num > msi_count) 3548c2ecf20Sopenharmony_ci return -EINVAL; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Compute the data value to be written. */ 3578c2ecf20Sopenharmony_ci data_mask = msi_count - 1; 3588c2ecf20Sopenharmony_ci data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64); 3598c2ecf20Sopenharmony_ci data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Get the PCI address where to write the data into. */ 3628c2ecf20Sopenharmony_ci pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI); 3638c2ecf20Sopenharmony_ci pci_addr <<= 32; 3648c2ecf20Sopenharmony_ci pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO); 3658c2ecf20Sopenharmony_ci pci_addr &= GENMASK_ULL(63, 2); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Set the outbound region if needed. */ 3688c2ecf20Sopenharmony_ci if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) || 3698c2ecf20Sopenharmony_ci ep->irq_pci_fn != fn)) { 3708c2ecf20Sopenharmony_ci /* First region was reserved for IRQ writes. */ 3718c2ecf20Sopenharmony_ci cdns_pcie_set_outbound_region(pcie, 0, fn, 0, 3728c2ecf20Sopenharmony_ci false, 3738c2ecf20Sopenharmony_ci ep->irq_phys_addr, 3748c2ecf20Sopenharmony_ci pci_addr & ~pci_addr_mask, 3758c2ecf20Sopenharmony_ci pci_addr_mask + 1); 3768c2ecf20Sopenharmony_ci ep->irq_pci_addr = (pci_addr & ~pci_addr_mask); 3778c2ecf20Sopenharmony_ci ep->irq_pci_fn = fn; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask)); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, 3858c2ecf20Sopenharmony_ci u16 interrupt_num) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; 3888c2ecf20Sopenharmony_ci u32 tbl_offset, msg_data, reg; 3898c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 3908c2ecf20Sopenharmony_ci struct pci_epf_msix_tbl *msix_tbl; 3918c2ecf20Sopenharmony_ci struct cdns_pcie_epf *epf; 3928c2ecf20Sopenharmony_ci u64 pci_addr_mask = 0xff; 3938c2ecf20Sopenharmony_ci u64 msg_addr; 3948c2ecf20Sopenharmony_ci u16 flags; 3958c2ecf20Sopenharmony_ci u8 bir; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Check whether the MSI-X feature has been enabled by the PCI host. */ 3988c2ecf20Sopenharmony_ci flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS); 3998c2ecf20Sopenharmony_ci if (!(flags & PCI_MSIX_FLAGS_ENABLE)) 4008c2ecf20Sopenharmony_ci return -EINVAL; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci reg = cap + PCI_MSIX_TABLE; 4038c2ecf20Sopenharmony_ci tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg); 4048c2ecf20Sopenharmony_ci bir = tbl_offset & PCI_MSIX_TABLE_BIR; 4058c2ecf20Sopenharmony_ci tbl_offset &= PCI_MSIX_TABLE_OFFSET; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci epf = &ep->epf[fn]; 4088c2ecf20Sopenharmony_ci msix_tbl = epf->epf_bar[bir]->addr + tbl_offset; 4098c2ecf20Sopenharmony_ci msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr; 4108c2ecf20Sopenharmony_ci msg_data = msix_tbl[(interrupt_num - 1)].msg_data; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Set the outbound region if needed. */ 4138c2ecf20Sopenharmony_ci if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) || 4148c2ecf20Sopenharmony_ci ep->irq_pci_fn != fn) { 4158c2ecf20Sopenharmony_ci /* First region was reserved for IRQ writes. */ 4168c2ecf20Sopenharmony_ci cdns_pcie_set_outbound_region(pcie, 0, fn, 0, 4178c2ecf20Sopenharmony_ci false, 4188c2ecf20Sopenharmony_ci ep->irq_phys_addr, 4198c2ecf20Sopenharmony_ci msg_addr & ~pci_addr_mask, 4208c2ecf20Sopenharmony_ci pci_addr_mask + 1); 4218c2ecf20Sopenharmony_ci ep->irq_pci_addr = (msg_addr & ~pci_addr_mask); 4228c2ecf20Sopenharmony_ci ep->irq_pci_fn = fn; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask)); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, 4308c2ecf20Sopenharmony_ci enum pci_epc_irq_type type, 4318c2ecf20Sopenharmony_ci u16 interrupt_num) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci switch (type) { 4368c2ecf20Sopenharmony_ci case PCI_EPC_IRQ_LEGACY: 4378c2ecf20Sopenharmony_ci return cdns_pcie_ep_send_legacy_irq(ep, fn, 0); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci case PCI_EPC_IRQ_MSI: 4408c2ecf20Sopenharmony_ci return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci case PCI_EPC_IRQ_MSIX: 4438c2ecf20Sopenharmony_ci return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci default: 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int cdns_pcie_ep_start(struct pci_epc *epc) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 4558c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 4568c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 4578c2ecf20Sopenharmony_ci struct pci_epf *epf; 4588c2ecf20Sopenharmony_ci u32 cfg; 4598c2ecf20Sopenharmony_ci int ret; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * BIT(0) is hardwired to 1, hence function 0 is always enabled 4638c2ecf20Sopenharmony_ci * and can't be disabled anyway. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci cfg = BIT(0); 4668c2ecf20Sopenharmony_ci list_for_each_entry(epf, &epc->pci_epf, list) 4678c2ecf20Sopenharmony_ci cfg |= BIT(epf->func_no); 4688c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = cdns_pcie_start_link(pcie); 4718c2ecf20Sopenharmony_ci if (ret) { 4728c2ecf20Sopenharmony_ci dev_err(dev, "Failed to start link\n"); 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic const struct pci_epc_features cdns_pcie_epc_features = { 4808c2ecf20Sopenharmony_ci .linkup_notifier = false, 4818c2ecf20Sopenharmony_ci .msi_capable = true, 4828c2ecf20Sopenharmony_ci .msix_capable = true, 4838c2ecf20Sopenharmony_ci}; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic const struct pci_epc_features* 4868c2ecf20Sopenharmony_cicdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci return &cdns_pcie_epc_features; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic const struct pci_epc_ops cdns_pcie_epc_ops = { 4928c2ecf20Sopenharmony_ci .write_header = cdns_pcie_ep_write_header, 4938c2ecf20Sopenharmony_ci .set_bar = cdns_pcie_ep_set_bar, 4948c2ecf20Sopenharmony_ci .clear_bar = cdns_pcie_ep_clear_bar, 4958c2ecf20Sopenharmony_ci .map_addr = cdns_pcie_ep_map_addr, 4968c2ecf20Sopenharmony_ci .unmap_addr = cdns_pcie_ep_unmap_addr, 4978c2ecf20Sopenharmony_ci .set_msi = cdns_pcie_ep_set_msi, 4988c2ecf20Sopenharmony_ci .get_msi = cdns_pcie_ep_get_msi, 4998c2ecf20Sopenharmony_ci .set_msix = cdns_pcie_ep_set_msix, 5008c2ecf20Sopenharmony_ci .get_msix = cdns_pcie_ep_get_msix, 5018c2ecf20Sopenharmony_ci .raise_irq = cdns_pcie_ep_raise_irq, 5028c2ecf20Sopenharmony_ci .start = cdns_pcie_ep_start, 5038c2ecf20Sopenharmony_ci .get_features = cdns_pcie_ep_get_features, 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciint cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct device *dev = ep->pcie.dev; 5108c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 5118c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 5128c2ecf20Sopenharmony_ci struct cdns_pcie *pcie = &ep->pcie; 5138c2ecf20Sopenharmony_ci struct resource *res; 5148c2ecf20Sopenharmony_ci struct pci_epc *epc; 5158c2ecf20Sopenharmony_ci int ret; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci pcie->is_rc = false; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg"); 5208c2ecf20Sopenharmony_ci if (IS_ERR(pcie->reg_base)) { 5218c2ecf20Sopenharmony_ci dev_err(dev, "missing \"reg\"\n"); 5228c2ecf20Sopenharmony_ci return PTR_ERR(pcie->reg_base); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); 5268c2ecf20Sopenharmony_ci if (!res) { 5278c2ecf20Sopenharmony_ci dev_err(dev, "missing \"mem\"\n"); 5288c2ecf20Sopenharmony_ci return -EINVAL; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci pcie->mem_res = res; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "cdns,max-outbound-regions", 5338c2ecf20Sopenharmony_ci &ep->max_regions); 5348c2ecf20Sopenharmony_ci if (ret < 0) { 5358c2ecf20Sopenharmony_ci dev_err(dev, "missing \"cdns,max-outbound-regions\"\n"); 5368c2ecf20Sopenharmony_ci return ret; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci ep->ob_addr = devm_kcalloc(dev, 5398c2ecf20Sopenharmony_ci ep->max_regions, sizeof(*ep->ob_addr), 5408c2ecf20Sopenharmony_ci GFP_KERNEL); 5418c2ecf20Sopenharmony_ci if (!ep->ob_addr) 5428c2ecf20Sopenharmony_ci return -ENOMEM; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Disable all but function 0 (anyway BIT(0) is hardwired to 1). */ 5458c2ecf20Sopenharmony_ci cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0)); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops); 5488c2ecf20Sopenharmony_ci if (IS_ERR(epc)) { 5498c2ecf20Sopenharmony_ci dev_err(dev, "failed to create epc device\n"); 5508c2ecf20Sopenharmony_ci return PTR_ERR(epc); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci epc_set_drvdata(epc, ep); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0) 5568c2ecf20Sopenharmony_ci epc->max_functions = 1; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf), 5598c2ecf20Sopenharmony_ci GFP_KERNEL); 5608c2ecf20Sopenharmony_ci if (!ep->epf) 5618c2ecf20Sopenharmony_ci return -ENOMEM; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ret = pci_epc_mem_init(epc, pcie->mem_res->start, 5648c2ecf20Sopenharmony_ci resource_size(pcie->mem_res), PAGE_SIZE); 5658c2ecf20Sopenharmony_ci if (ret < 0) { 5668c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize the memory space\n"); 5678c2ecf20Sopenharmony_ci return ret; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr, 5718c2ecf20Sopenharmony_ci SZ_128K); 5728c2ecf20Sopenharmony_ci if (!ep->irq_cpu_addr) { 5738c2ecf20Sopenharmony_ci dev_err(dev, "failed to reserve memory space for MSI\n"); 5748c2ecf20Sopenharmony_ci ret = -ENOMEM; 5758c2ecf20Sopenharmony_ci goto free_epc_mem; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE; 5788c2ecf20Sopenharmony_ci /* Reserve region 0 for IRQs */ 5798c2ecf20Sopenharmony_ci set_bit(0, &ep->ob_region_map); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (ep->quirk_detect_quiet_flag) 5828c2ecf20Sopenharmony_ci cdns_pcie_detect_quiet_min_delay_set(&ep->pcie); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci spin_lock_init(&ep->lock); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci free_epc_mem: 5898c2ecf20Sopenharmony_ci pci_epc_mem_exit(epc); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return ret; 5928c2ecf20Sopenharmony_ci} 593