Merge branch 'pci/endpoint'

- Free all previously requested IRQs in epf_ntb_db_bar_init_msi_doorbell()
  error path (Koichiro Den)

- Free doorbell IRQ in pci-epf-test only if it has actually been requested
  (Koichiro Den)

- Discard pointer to doorbell message array after freeing it in
  pci_epf_alloc_doorbell() error path (Koichiro Den)

- Advertise dynamic inbound mapping support in pci-epf-test and update host
  pci_endpoint_test to skip doorbell testing if not advertised by endpoint
  (Koichiro Den)

- Constify configfs item and group operations (Christophe JAILLET)

- Use array_index_nospec() on configfs MW show/store attributes (Koichiro
  Den)

- Return -ERANGE (not -EINVAL) for configfs out-of-range MW index (Koichiro
  Den)

- Return 0, not remaining timeout, when MHI eDMA ops complete so
  mhi_ep_ring_add_element() doesn't interpret non-zero as failure (Daniel
  Hodges)

- Remove vntb and ntb duplicate resource teardown that leads to oops when
  .allow_link() fails or .drop_link() is called (Koichiro Den)

- Disable vntb delayed work before clearing BAR mappings and doorbells to
  avoid oops caused by doing the work after resources have been torn down
  (Koichiro Den)

- Fix pci_epf_add_vepf() kernel-doc typo (Alok Tiwari)

- Propagate pci_epf_create() errors to pci_epf_make() callers (Alok Tiwari)

- Remove redundant BAR_RESERVED annotation for the high order part of a
  64-bit BAR (Niklas Cassel)

- Add a way to describe reserved subregions within BARs, e.g.,
  platform-owned fixed register windows, and use it for the RK3588 BAR4 DMA
  ctrl window (Koichiro Den)

- Add BAR_DISABLED for BARs that will never be available to an EPF driver,
  and change some BAR_RESERVED annotations to BAR_DISABLED (Niklas Cassel)

- Disable BARs in common code instead of in each glue driver (Niklas
  Cassel)

- Advertise reserved BARs in Capabilities so host-side drivers can skip
  them (Niklas Cassel)

- Skip reserved BARs in selftests (Niklas Cassel)

- Improve error messages and include device name when available (Manivannan
  Sadhasivam)

- Add NTB .get_dma_dev() callback for cases where DMA API requires a
  different device, e.g., vNTB devices (Koichiro Den)

- Return -EINVAL, not -ENOSPC, if endpoint test determines the subrange
  size is too small (Koichiro Den)

- Add reserved region types for MSI-X Table and PBA so Endpoint controllers
  can them as describe hardware-owned regions in a BAR_RESERVED BAR
  (Manikanta Maddireddy)

- Make Tegra194/234 BAR0 programmable and remove 1MB size limit (Manikanta
  Maddireddy)

- Expose Tegra BAR2 (MSI-X) and BAR4 (DMA) as 64-bit BAR_RESERVED
  (Manikanta Maddireddy)

- Add Tegra194 and Tegra234 device table entries to pci_endpoint_test
  (Manikanta Maddireddy)

- Skip the BAR subrange selftest if there are not enough inbound window
  resources to run the test (Christian Bruel)

* pci/endpoint:
  selftests: pci_endpoint: Skip BAR subrange test on -ENOSPC
  misc: pci_endpoint_test: Add Tegra194 and Tegra234 device table entries
  PCI: tegra194: Expose BAR2 (MSI-X) and BAR4 (DMA) as 64-bit BAR_RESERVED
  PCI: tegra194: Make BAR0 programmable and remove 1MB size limit
  PCI: endpoint: Add reserved region type for MSI-X Table and PBA
  misc: pci_endpoint_test: Use -EINVAL for small subrange size
  PCI: endpoint: pci-epf-vntb: Implement .get_dma_dev()
  NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers
  NTB: core: Add .get_dma_dev() callback to ntb_dev_ops
  PCI: endpoint: Improve error messages
  PCI: endpoint: Print the EPF name in the error log of pci_epf_make()
  selftests: pci_endpoint: Skip reserved BARs
  misc: pci_endpoint_test: Give reserved BARs a distinct error code
  PCI: endpoint: pci-epf-test: Advertise reserved BARs
  PCI: dwc: Disable BARs in common code instead of in each glue driver
  PCI: dwc: Replace certain BAR_RESERVED with BAR_DISABLED in glue drivers
  PCI: endpoint: Introduce pci_epc_bar_type BAR_DISABLED
  PCI: dw-rockchip: Describe RK3588 BAR4 DMA ctrl window
  PCI: endpoint: Describe reserved subregions within BARs
  PCI: endpoint: Allow only_64bit on BAR_RESERVED
  PCI: endpoint: Do not mark the BAR succeeding a 64-bit BAR as BAR_RESERVED
  PCI: endpoint: Propagate error from pci_epf_create()
  PCI: endpoint: Fix typo in pci_epf_add_vepf() kernel-doc
  PCI: endpoint: pci-epf-vntb: Stop cmd_handler work in epf_ntb_epc_cleanup
  PCI: endpoint: pci-epf-ntb: Remove duplicate resource teardown
  PCI: endpoint: pci-epf-vntb: Remove duplicate resource teardown
  PCI: epf-mhi: Return 0, not remaining timeout, when eDMA ops complete
  PCI: endpoint: pci-epf-vntb: Return -ERANGE for out-of-range MW index
  PCI: endpoint: pci-epf-vntb: Use array_index_nospec() on mws_size[] access
  PCI: endpoint: Constify struct configfs_item_operations and configfs_group_operations
  selftests: pci_endpoint: Skip doorbell test when unsupported
  misc: pci_endpoint_test: Gate doorbell test on dynamic inbound mapping
  PCI: endpoint: pci-epf-test: Advertise dynamic inbound mapping support
  PCI: endpoint: pci-ep-msi: Fix error unwind and prevent double alloc
  PCI: endpoint: pci-epf-test: Don't free doorbell IRQ unless requested
  PCI: endpoint: pci-epf-vntb: Fix MSI doorbell IRQ unwind
This commit is contained in:
Bjorn Helgaas 2026-04-13 12:50:07 -05:00
commit 8153aaf6b9
28 changed files with 313 additions and 250 deletions

View file

@ -61,6 +61,7 @@
#define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
#define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
#define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
#define STATUS_NO_RESOURCE BIT(18)
#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
@ -84,6 +85,13 @@
#define CAP_MSIX BIT(2)
#define CAP_INTX BIT(3)
#define CAP_SUBRANGE_MAPPING BIT(4)
#define CAP_DYNAMIC_INBOUND_MAPPING BIT(5)
#define CAP_BAR0_RESERVED BIT(6)
#define CAP_BAR1_RESERVED BIT(7)
#define CAP_BAR2_RESERVED BIT(8)
#define CAP_BAR3_RESERVED BIT(9)
#define CAP_BAR4_RESERVED BIT(10)
#define CAP_BAR5_RESERVED BIT(11)
#define PCI_ENDPOINT_TEST_DB_BAR 0x34
#define PCI_ENDPOINT_TEST_DB_OFFSET 0x38
@ -107,6 +115,9 @@
#define PCI_DEVICE_ID_ROCKCHIP_RK3588 0x3588
#define PCI_DEVICE_ID_NVIDIA_TEGRA194_EP 0x1ad4
#define PCI_DEVICE_ID_NVIDIA_TEGRA234_EP 0x229b
#define PCI_ENDPOINT_TEST_BAR_SUBRANGE_NSUB 2
static DEFINE_IDA(pci_endpoint_test_ida);
@ -275,6 +286,11 @@ fail:
return ret;
}
static bool bar_is_reserved(struct pci_endpoint_test *test, enum pci_barno bar)
{
return test->ep_caps & BIT(bar + __fls(CAP_BAR0_RESERVED));
}
static const u32 bar_test_pattern[] = {
0xA0A0A0A0,
0xA1A1A1A1,
@ -403,7 +419,7 @@ static int pci_endpoint_test_bars(struct pci_endpoint_test *test)
/* Write all BARs in order (without reading). */
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
if (test->bar[bar])
if (test->bar[bar] && !bar_is_reserved(test, bar))
pci_endpoint_test_bars_write_bar(test, bar);
/*
@ -413,7 +429,7 @@ static int pci_endpoint_test_bars(struct pci_endpoint_test *test)
* (Reading back the BAR directly after writing can not detect this.)
*/
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
if (test->bar[bar]) {
if (test->bar[bar] && !bar_is_reserved(test, bar)) {
ret = pci_endpoint_test_bars_read_bar(test, bar);
if (ret)
return ret;
@ -465,7 +481,7 @@ static int pci_endpoint_test_bar_subrange_cmd(struct pci_endpoint_test *test,
status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
if (status & fail_bit)
return -EIO;
return (status & STATUS_NO_RESOURCE) ? -ENOSPC : -EIO;
if (!(status & ok_bit))
return -EIO;
@ -535,7 +551,7 @@ static int pci_endpoint_test_bar_subrange(struct pci_endpoint_test *test,
sub_size = bar_size / nsub;
if (sub_size < sizeof(u32)) {
ret = -ENOSPC;
ret = -EINVAL;
goto out_clear;
}
@ -1060,6 +1076,9 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test)
u32 addr;
int left;
if (!(test->ep_caps & CAP_DYNAMIC_INBOUND_MAPPING))
return -EOPNOTSUPP;
if (irq_type < PCITEST_IRQ_TYPE_INTX ||
irq_type > PCITEST_IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type\n");
@ -1139,6 +1158,11 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
if (is_am654_pci_dev(pdev) && bar == BAR_0)
goto ret;
if (bar_is_reserved(test, bar)) {
ret = -ENOBUFS;
goto ret;
}
if (cmd == PCITEST_BAR)
ret = pci_endpoint_test_bar(test, bar);
else
@ -1418,6 +1442,8 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ROCKCHIP, PCI_DEVICE_ID_ROCKCHIP_RK3588),
.driver_data = (kernel_ulong_t)&rk3588_data,
},
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TEGRA194_EP),},
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TEGRA234_EP),},
{ }
};
MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);

View file

@ -759,13 +759,13 @@ static void ntb_transport_msi_desc_changed(void *data)
static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
{
struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
struct pci_dev *pdev = nt->ndev->pdev;
struct device *dma_dev = ntb_get_dma_dev(nt->ndev);
if (!mw->virt_addr)
return;
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(&pdev->dev, mw->alloc_size,
dma_free_coherent(dma_dev, mw->alloc_size,
mw->alloc_addr, mw->dma_addr);
mw->xlat_size = 0;
mw->buff_size = 0;
@ -835,7 +835,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
resource_size_t size)
{
struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
struct pci_dev *pdev = nt->ndev->pdev;
struct device *dma_dev = ntb_get_dma_dev(nt->ndev);
size_t xlat_size, buff_size;
resource_size_t xlat_align;
resource_size_t xlat_align_size;
@ -864,12 +864,12 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
mw->buff_size = buff_size;
mw->alloc_size = buff_size;
rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
rc = ntb_alloc_mw_buffer(mw, dma_dev, xlat_align);
if (rc) {
mw->alloc_size *= 2;
rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
rc = ntb_alloc_mw_buffer(mw, dma_dev, xlat_align);
if (rc) {
dev_err(&pdev->dev,
dev_err(dma_dev,
"Unable to alloc aligned MW buff\n");
mw->xlat_size = 0;
mw->buff_size = 0;
@ -882,7 +882,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
mw->xlat_size);
if (rc) {
dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
dev_err(dma_dev, "Unable to set mw%d translation", num_mw);
ntb_free_mw(nt, num_mw);
return -EIO;
}

View file

@ -378,10 +378,6 @@ static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
enum pci_barno bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
dra7xx_pcie_enable_wrapper_interrupts(dra7xx);
}

View file

@ -1401,15 +1401,6 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.stop_link = imx_pcie_stop_link,
};
static void imx_pcie_ep_init(struct dw_pcie_ep *ep)
{
enum pci_barno bar;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
for (bar = BAR_0; bar <= BAR_5; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static int imx_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
unsigned int type, u16 interrupt_num)
{
@ -1433,19 +1424,19 @@ static int imx_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
static const struct pci_epc_features imx8m_pcie_epc_features = {
DWC_EPC_COMMON_FEATURES,
.msi_capable = true,
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_1] = { .type = BAR_DISABLED, },
.bar[BAR_3] = { .type = BAR_DISABLED, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = SZ_256, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_DISABLED, },
.align = SZ_64K,
};
static const struct pci_epc_features imx8q_pcie_epc_features = {
DWC_EPC_COMMON_FEATURES,
.msi_capable = true,
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.bar[BAR_1] = { .type = BAR_DISABLED, },
.bar[BAR_3] = { .type = BAR_DISABLED, },
.bar[BAR_5] = { .type = BAR_DISABLED, },
.align = SZ_64K,
};
@ -1478,7 +1469,6 @@ imx_pcie_ep_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
.init = imx_pcie_ep_init,
.raise_irq = imx_pcie_ep_raise_irq,
.get_features = imx_pcie_ep_get_features,
};

View file

@ -933,6 +933,18 @@ static const struct pci_epc_features ks_pcie_am654_epc_features = {
DWC_EPC_COMMON_FEATURES,
.msi_capable = true,
.msix_capable = true,
/*
* TODO: This driver is the only DWC glue driver that had BAR_RESERVED
* BARs, but did not call dw_pcie_ep_reset_bar() for the reserved BARs.
*
* To not change the existing behavior, these BARs were not migrated to
* BAR_DISABLED. If this driver wants the BAR_RESERVED BARs to be
* disabled, it should migrate them to BAR_DISABLED.
*
* If they actually should be enabled, then the driver must also define
* what is behind these reserved BARs, see the definition of struct
* pci_epc_bar_rsvd_region.
*/
.bar[BAR_0] = { .type = BAR_RESERVED, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_RESIZABLE, },

View file

@ -152,15 +152,11 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
struct dw_pcie_ep_func *ep_func;
enum pci_barno bar;
ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
if (!ep_func)
return;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
}
@ -251,9 +247,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
pci->ops = pcie->drvdata->dw_pcie_ops;
ls_epc->bar[BAR_2].only_64bit = true;
ls_epc->bar[BAR_3].type = BAR_RESERVED;
ls_epc->bar[BAR_4].only_64bit = true;
ls_epc->bar[BAR_5].type = BAR_RESERVED;
ls_epc->linkup_notifier = true;
pcie->pci = pci;

View file

@ -340,15 +340,11 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
enum pci_barno bar;
artpec6_pcie_assert_core_reset(artpec6_pcie);
artpec6_pcie_init_phy(artpec6_pcie);
artpec6_pcie_deassert_core_reset(artpec6_pcie);
artpec6_pcie_wait_for_phy(artpec6_pcie);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,

View file

@ -1114,6 +1114,28 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
dw_pcie_dbi_ro_wr_dis(pci);
}
static void dw_pcie_ep_disable_bars(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_epc_bar_type bar_type;
enum pci_barno bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
bar_type = dw_pcie_ep_get_bar_type(ep, bar);
/*
* Reserved BARs should not get disabled by default. All other
* BAR types are disabled by default.
*
* This is in line with the current EPC core design, where all
* BARs are disabled by default, and then the EPF driver enables
* the BARs it wishes to use.
*/
if (bar_type != BAR_RESERVED)
dw_pcie_ep_reset_bar(pci, bar);
}
}
/**
* dw_pcie_ep_init_registers - Initialize DWC EP specific registers
* @ep: DWC EP device
@ -1196,6 +1218,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
if (ep->ops->init)
ep->ops->init(ep);
dw_pcie_ep_disable_bars(ep);
/*
* PCIe r6.0, section 7.9.15 states that for endpoints that support
* PTM, this capability structure is required in exactly one

View file

@ -32,15 +32,6 @@ struct dw_plat_pcie_of_data {
static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
};
static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
unsigned int type, u16 interrupt_num)
{
@ -73,7 +64,6 @@ dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
.init = dw_plat_pcie_ep_init,
.raise_irq = dw_plat_pcie_ep_raise_irq,
.get_features = dw_plat_pcie_get_features,
};

View file

@ -361,13 +361,9 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep)
static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
rockchip_pcie_enable_l0s(pci);
rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
};
static int rockchip_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
@ -403,12 +399,19 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = {
.bar[BAR_5] = { .type = BAR_RESIZABLE, },
};
static const struct pci_epc_bar_rsvd_region rk3588_bar4_rsvd[] = {
{
/* DMA_CAP (BAR4: DMA Port Logic Structure) */
.type = PCI_EPC_BAR_RSVD_DMA_CTRL_MMIO,
.offset = 0x0,
.size = 0x2000,
},
};
/*
* BAR4 on rk3588 exposes the ATU Port Logic Structure to the host regardless of
* iATU settings for BAR4. This means that BAR4 cannot be used by an EPF driver,
* so mark it as RESERVED. (rockchip_pcie_ep_init() will disable all BARs by
* default.) If the host could write to BAR4, the iATU settings (for all other
* BARs) would be overwritten, resulting in (all other BARs) no longer working.
* so mark it as RESERVED.
*/
static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = {
DWC_EPC_COMMON_FEATURES,
@ -420,7 +423,11 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = {
.bar[BAR_1] = { .type = BAR_RESIZABLE, },
.bar[BAR_2] = { .type = BAR_RESIZABLE, },
.bar[BAR_3] = { .type = BAR_RESIZABLE, },
.bar[BAR_4] = { .type = BAR_RESERVED, },
.bar[BAR_4] = {
.type = BAR_RESERVED,
.nr_rsvd_regions = ARRAY_SIZE(rk3588_bar4_rsvd),
.rsvd_regions = rk3588_bar4_rsvd,
},
.bar[BAR_5] = { .type = BAR_RESIZABLE, },
};

View file

@ -313,11 +313,8 @@ static const struct pci_epc_features keembay_pcie_epc_features = {
.msi_capable = true,
.msix_capable = true,
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .only_64bit = true, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.align = SZ_16K,
};

View file

@ -850,9 +850,7 @@ static const struct pci_epc_features qcom_pcie_epc_features = {
.msi_capable = true,
.align = SZ_4K,
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
};
static const struct pci_epc_features *
@ -861,17 +859,7 @@ qcom_pcie_epc_get_features(struct dw_pcie_ep *pci_ep)
return &qcom_pcie_epc_features;
}
static void qcom_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = BAR_0; bar <= BAR_5; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static const struct dw_pcie_ep_ops pci_ep_ops = {
.init = qcom_pcie_ep_init,
.raise_irq = qcom_pcie_ep_raise_irq,
.get_features = qcom_pcie_epc_get_features,
};

View file

@ -386,15 +386,6 @@ static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep)
writel(PCIEDMAINTSTSEN_INIT, rcar->base + PCIEDMAINTSTSEN);
}
static void rcar_gen4_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static void rcar_gen4_pcie_ep_deinit(struct rcar_gen4_pcie *rcar)
{
writel(0, rcar->base + PCIEDMAINTSTSEN);
@ -422,10 +413,10 @@ static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
DWC_EPC_COMMON_FEATURES,
.msi_capable = true,
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_1] = { .type = BAR_DISABLED, },
.bar[BAR_3] = { .type = BAR_DISABLED, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_DISABLED, },
.align = SZ_1M,
};
@ -449,7 +440,6 @@ static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
static const struct dw_pcie_ep_ops pcie_ep_ops = {
.pre_init = rcar_gen4_pcie_ep_pre_init,
.init = rcar_gen4_pcie_ep_init,
.raise_irq = rcar_gen4_pcie_ep_raise_irq,
.get_features = rcar_gen4_pcie_ep_get_features,
.get_dbi_offset = rcar_gen4_pcie_ep_get_dbi_offset,

View file

@ -28,15 +28,6 @@ struct stm32_pcie {
unsigned int perst_irq;
};
static void stm32_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static int stm32_pcie_start_link(struct dw_pcie *pci)
{
struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
@ -82,7 +73,6 @@ stm32_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops stm32_pcie_ep_ops = {
.init = stm32_pcie_ep_init,
.raise_irq = stm32_pcie_raise_irq,
.get_features = stm32_pcie_get_features,
};

View file

@ -1923,15 +1923,6 @@ static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg)
return IRQ_HANDLED;
}
static void tegra_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
dw_pcie_ep_reset_bar(pci, bar);
};
static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
{
/* Tegra194 supports only INTA */
@ -1987,17 +1978,48 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
return 0;
}
static const struct pci_epc_bar_rsvd_region tegra194_bar2_rsvd[] = {
{
/* MSI-X table structure */
.type = PCI_EPC_BAR_RSVD_MSIX_TBL_RAM,
.offset = 0x0,
.size = SZ_64K,
},
{
/* MSI-X PBA structure */
.type = PCI_EPC_BAR_RSVD_MSIX_PBA_RAM,
.offset = 0x10000,
.size = SZ_64K,
},
};
static const struct pci_epc_bar_rsvd_region tegra194_bar4_rsvd[] = {
{
/* DMA_CAP (BAR4: DMA Port Logic Structure) */
.type = PCI_EPC_BAR_RSVD_DMA_CTRL_MMIO,
.offset = 0x0,
.size = SZ_4K,
},
};
/* Tegra EP: BAR0 = 64-bit programmable BAR, BAR2 = 64-bit MSI-X table, BAR4 = 64-bit DMA regs. */
static const struct pci_epc_features tegra_pcie_epc_features = {
DWC_EPC_COMMON_FEATURES,
.linkup_notifier = true,
.msi_capable = true,
.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M,
.only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_2] = {
.type = BAR_RESERVED,
.only_64bit = true,
.nr_rsvd_regions = ARRAY_SIZE(tegra194_bar2_rsvd),
.rsvd_regions = tegra194_bar2_rsvd,
},
.bar[BAR_4] = {
.type = BAR_RESERVED,
.only_64bit = true,
.nr_rsvd_regions = ARRAY_SIZE(tegra194_bar4_rsvd),
.rsvd_regions = tegra194_bar4_rsvd,
},
.align = SZ_64K,
};
@ -2008,7 +2030,6 @@ tegra_pcie_ep_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
.init = tegra_pcie_ep_init,
.raise_irq = tegra_pcie_ep_raise_irq,
.get_features = tegra_pcie_ep_get_features,
};

View file

@ -203,15 +203,6 @@ static void uniphier_pcie_stop_link(struct dw_pcie *pci)
uniphier_pcie_ltssm_enable(priv, false);
}
static void uniphier_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = BAR_0; bar <= BAR_5; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static int uniphier_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
@ -283,7 +274,6 @@ uniphier_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
.init = uniphier_pcie_ep_init,
.raise_irq = uniphier_pcie_ep_raise_irq,
.get_features = uniphier_pcie_get_features,
};
@ -426,11 +416,9 @@ static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = {
.msix_capable = false,
.align = 1 << 16,
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_DISABLED, },
.bar[BAR_5] = { .type = BAR_DISABLED, },
},
};
@ -445,11 +433,8 @@ static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = {
.msix_capable = false,
.align = 1 << 12,
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .only_64bit = true, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
},
};

View file

@ -440,13 +440,10 @@ static const struct pci_epc_features rcar_pcie_epc_features = {
/* use 64-bit BARs so mark BAR[1,3,5] as reserved */
.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = 128,
.only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = 256,
.only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256,
.only_64bit = true, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
};
static const struct pci_epc_features*

View file

@ -367,6 +367,8 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
dev_err(dev, "DMA transfer timeout\n");
dmaengine_terminate_sync(chan);
ret = -ETIMEDOUT;
} else {
ret = 0;
}
err_unmap:
@ -438,6 +440,8 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
dev_err(dev, "DMA transfer timeout\n");
dmaengine_terminate_sync(chan);
ret = -ETIMEDOUT;
} else {
ret = 0;
}
err_unmap:

View file

@ -1494,47 +1494,6 @@ err_alloc_peer_mem:
return ret;
}
/**
* epf_ntb_epc_destroy_interface() - Cleanup NTB EPC interface
* @ntb: NTB device that facilitates communication between HOST1 and HOST2
* @type: PRIMARY interface or SECONDARY interface
*
* Unbind NTB function device from EPC and relinquish reference to pci_epc
* for each of the interface.
*/
static void epf_ntb_epc_destroy_interface(struct epf_ntb *ntb,
enum pci_epc_interface_type type)
{
struct epf_ntb_epc *ntb_epc;
struct pci_epc *epc;
struct pci_epf *epf;
if (type < 0)
return;
epf = ntb->epf;
ntb_epc = ntb->epc[type];
if (!ntb_epc)
return;
epc = ntb_epc->epc;
pci_epc_remove_epf(epc, epf, type);
pci_epc_put(epc);
}
/**
* epf_ntb_epc_destroy() - Cleanup NTB EPC interface
* @ntb: NTB device that facilitates communication between HOST1 and HOST2
*
* Wrapper for epf_ntb_epc_destroy_interface() to cleanup all the NTB interfaces
*/
static void epf_ntb_epc_destroy(struct epf_ntb *ntb)
{
enum pci_epc_interface_type type;
for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++)
epf_ntb_epc_destroy_interface(ntb, type);
}
/**
* epf_ntb_epc_create_interface() - Create and initialize NTB EPC interface
* @ntb: NTB device that facilitates communication between HOST1 and HOST2
@ -1614,15 +1573,8 @@ static int epf_ntb_epc_create(struct epf_ntb *ntb)
ret = epf_ntb_epc_create_interface(ntb, epf->sec_epc,
SECONDARY_INTERFACE);
if (ret) {
if (ret)
dev_err(dev, "SECONDARY intf: Fail to create NTB EPC\n");
goto err_epc_create;
}
return 0;
err_epc_create:
epf_ntb_epc_destroy_interface(ntb, PRIMARY_INTERFACE);
return ret;
}
@ -1887,7 +1839,7 @@ static int epf_ntb_bind(struct pci_epf *epf)
ret = epf_ntb_init_epc_bar(ntb);
if (ret) {
dev_err(dev, "Failed to create NTB EPC\n");
goto err_bar_init;
return ret;
}
ret = epf_ntb_config_spad_bar_alloc_interface(ntb);
@ -1909,9 +1861,6 @@ static int epf_ntb_bind(struct pci_epf *epf)
err_bar_alloc:
epf_ntb_config_spad_bar_free(ntb);
err_bar_init:
epf_ntb_epc_destroy(ntb);
return ret;
}
@ -1927,7 +1876,6 @@ static void epf_ntb_unbind(struct pci_epf *epf)
epf_ntb_epc_cleanup(ntb);
epf_ntb_config_spad_bar_free(ntb);
epf_ntb_epc_destroy(ntb);
}
#define EPF_NTB_R(_name) \

View file

@ -54,6 +54,7 @@
#define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
#define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
#define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
#define STATUS_NO_RESOURCE BIT(18)
#define FLAG_USE_DMA BIT(0)
@ -64,6 +65,13 @@
#define CAP_MSIX BIT(2)
#define CAP_INTX BIT(3)
#define CAP_SUBRANGE_MAPPING BIT(4)
#define CAP_DYNAMIC_INBOUND_MAPPING BIT(5)
#define CAP_BAR0_RESERVED BIT(6)
#define CAP_BAR1_RESERVED BIT(7)
#define CAP_BAR2_RESERVED BIT(8)
#define CAP_BAR3_RESERVED BIT(9)
#define CAP_BAR4_RESERVED BIT(10)
#define CAP_BAR5_RESERVED BIT(11)
#define PCI_EPF_TEST_BAR_SUBRANGE_NSUB 2
@ -715,7 +723,6 @@ static void pci_epf_test_doorbell_cleanup(struct pci_epf_test *epf_test)
struct pci_epf_test_reg *reg = epf_test->reg[epf_test->test_reg_bar];
struct pci_epf *epf = epf_test->epf;
free_irq(epf->db_msg[0].virq, epf_test);
reg->doorbell_bar = cpu_to_le32(NO_BAR);
pci_epf_free_doorbell(epf);
@ -759,7 +766,7 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
&epf_test->db_bar.phys_addr, &offset);
if (ret)
goto err_doorbell_cleanup;
goto err_free_irq;
reg->doorbell_offset = cpu_to_le32(offset);
@ -769,12 +776,14 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar);
if (ret)
goto err_doorbell_cleanup;
goto err_free_irq;
status |= STATUS_DOORBELL_ENABLE_SUCCESS;
reg->status = cpu_to_le32(status);
return;
err_free_irq:
free_irq(epf->db_msg[0].virq, epf_test);
err_doorbell_cleanup:
pci_epf_test_doorbell_cleanup(epf_test);
set_status_err:
@ -794,6 +803,7 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test,
if (bar < BAR_0)
goto set_status_err;
free_irq(epf->db_msg[0].virq, epf_test);
pci_epf_test_doorbell_cleanup(epf_test);
/*
@ -892,6 +902,8 @@ static void pci_epf_test_bar_subrange_setup(struct pci_epf_test *epf_test,
ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar);
if (ret) {
dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret);
if (ret == -ENOSPC)
status |= STATUS_NO_RESOURCE;
bar->submap = old_submap;
bar->num_submap = old_nsub;
kfree(submap);
@ -1102,10 +1114,31 @@ static void pci_epf_test_set_capabilities(struct pci_epf *epf)
if (epf_test->epc_features->intx_capable)
caps |= CAP_INTX;
if (epf_test->epc_features->dynamic_inbound_mapping)
caps |= CAP_DYNAMIC_INBOUND_MAPPING;
if (epf_test->epc_features->dynamic_inbound_mapping &&
epf_test->epc_features->subrange_mapping)
caps |= CAP_SUBRANGE_MAPPING;
if (epf_test->epc_features->bar[BAR_0].type == BAR_RESERVED)
caps |= CAP_BAR0_RESERVED;
if (epf_test->epc_features->bar[BAR_1].type == BAR_RESERVED)
caps |= CAP_BAR1_RESERVED;
if (epf_test->epc_features->bar[BAR_2].type == BAR_RESERVED)
caps |= CAP_BAR2_RESERVED;
if (epf_test->epc_features->bar[BAR_3].type == BAR_RESERVED)
caps |= CAP_BAR3_RESERVED;
if (epf_test->epc_features->bar[BAR_4].type == BAR_RESERVED)
caps |= CAP_BAR4_RESERVED;
if (epf_test->epc_features->bar[BAR_5].type == BAR_RESERVED)
caps |= CAP_BAR5_RESERVED;
reg->caps = cpu_to_le32(caps);
}

View file

@ -527,20 +527,20 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
struct msi_msg *msg;
size_t sz;
int ret;
int i;
int i, req;
ret = pci_epf_alloc_doorbell(epf, ntb->db_count);
if (ret)
return ret;
for (i = 0; i < ntb->db_count; i++) {
ret = request_irq(epf->db_msg[i].virq, epf_ntb_doorbell_handler,
for (req = 0; req < ntb->db_count; req++) {
ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler,
0, "pci_epf_vntb_db", ntb);
if (ret) {
dev_err(&epf->dev,
"Failed to request doorbell IRQ: %d\n",
epf->db_msg[i].virq);
epf->db_msg[req].virq);
goto err_free_irq;
}
}
@ -598,8 +598,8 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
return 0;
err_free_irq:
for (i--; i >= 0; i--)
free_irq(epf->db_msg[i].virq, ntb);
for (req--; req >= 0; req--)
free_irq(epf->db_msg[req].virq, ntb);
pci_epf_free_doorbell(ntb->epf);
return ret;
@ -763,19 +763,6 @@ static void epf_ntb_mw_bar_clear(struct epf_ntb *ntb, int num_mws)
}
}
/**
* epf_ntb_epc_destroy() - Cleanup NTB EPC interface
* @ntb: NTB device that facilitates communication between HOST and VHOST
*
* Wrapper for epf_ntb_epc_destroy_interface() to cleanup all the NTB interfaces
*/
static void epf_ntb_epc_destroy(struct epf_ntb *ntb)
{
pci_epc_remove_epf(ntb->epf->epc, ntb->epf, 0);
pci_epc_put(ntb->epf->epc);
}
/**
* epf_ntb_is_bar_used() - Check if a bar is used in the ntb configuration
* @ntb: NTB device that facilitates communication between HOST and VHOST
@ -955,6 +942,7 @@ err_config_interrupt:
*/
static void epf_ntb_epc_cleanup(struct epf_ntb *ntb)
{
disable_delayed_work_sync(&ntb->cmd_handler);
epf_ntb_mw_bar_clear(ntb, ntb->num_mws);
epf_ntb_db_bar_clear(ntb);
epf_ntb_config_sspad_bar_clear(ntb);
@ -995,17 +983,19 @@ static ssize_t epf_ntb_##_name##_show(struct config_item *item, \
struct config_group *group = to_config_group(item); \
struct epf_ntb *ntb = to_epf_ntb(group); \
struct device *dev = &ntb->epf->dev; \
int win_no; \
int win_no, idx; \
\
if (sscanf(#_name, "mw%d", &win_no) != 1) \
return -EINVAL; \
\
if (win_no <= 0 || win_no > ntb->num_mws) { \
dev_err(dev, "Invalid num_nws: %d value\n", ntb->num_mws); \
return -EINVAL; \
idx = win_no - 1; \
if (idx < 0 || idx >= ntb->num_mws) { \
dev_err(dev, "MW%d out of range (num_mws=%d)\n", \
win_no, ntb->num_mws); \
return -ERANGE; \
} \
\
return sprintf(page, "%lld\n", ntb->mws_size[win_no - 1]); \
idx = array_index_nospec(idx, ntb->num_mws); \
return sprintf(page, "%llu\n", ntb->mws_size[idx]); \
}
#define EPF_NTB_MW_W(_name) \
@ -1015,7 +1005,7 @@ static ssize_t epf_ntb_##_name##_store(struct config_item *item, \
struct config_group *group = to_config_group(item); \
struct epf_ntb *ntb = to_epf_ntb(group); \
struct device *dev = &ntb->epf->dev; \
int win_no; \
int win_no, idx; \
u64 val; \
int ret; \
\
@ -1026,12 +1016,14 @@ static ssize_t epf_ntb_##_name##_store(struct config_item *item, \
if (sscanf(#_name, "mw%d", &win_no) != 1) \
return -EINVAL; \
\
if (win_no <= 0 || win_no > ntb->num_mws) { \
dev_err(dev, "Invalid num_nws: %d value\n", ntb->num_mws); \
return -EINVAL; \
idx = win_no - 1; \
if (idx < 0 || idx >= ntb->num_mws) { \
dev_err(dev, "MW%d out of range (num_mws=%d)\n", \
win_no, ntb->num_mws); \
return -ERANGE; \
} \
\
ntb->mws_size[win_no - 1] = val; \
idx = array_index_nospec(idx, ntb->num_mws); \
ntb->mws_size[idx] = val; \
\
return len; \
}
@ -1436,6 +1428,14 @@ static int vntb_epf_link_disable(struct ntb_dev *ntb)
return 0;
}
static struct device *vntb_epf_get_dma_dev(struct ntb_dev *ndev)
{
struct epf_ntb *ntb = ntb_ndev(ndev);
struct pci_epc *epc = ntb->epf->epc;
return epc->dev.parent;
}
static const struct ntb_dev_ops vntb_epf_ops = {
.mw_count = vntb_epf_mw_count,
.spad_count = vntb_epf_spad_count,
@ -1457,6 +1457,7 @@ static const struct ntb_dev_ops vntb_epf_ops = {
.db_clear_mask = vntb_epf_db_clear_mask,
.db_clear = vntb_epf_db_clear,
.link_disable = vntb_epf_link_disable,
.get_dma_dev = vntb_epf_get_dma_dev,
};
static int pci_vntb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@ -1525,7 +1526,7 @@ static int epf_ntb_bind(struct pci_epf *epf)
ret = epf_ntb_init_epc_bar(ntb);
if (ret) {
dev_err(dev, "Failed to create NTB EPC\n");
goto err_bar_init;
return ret;
}
ret = epf_ntb_config_spad_bar_alloc(ntb);
@ -1565,9 +1566,6 @@ err_epc_cleanup:
err_bar_alloc:
epf_ntb_config_spad_bar_free(ntb);
err_bar_init:
epf_ntb_epc_destroy(ntb);
return ret;
}
@ -1583,7 +1581,6 @@ static void epf_ntb_unbind(struct pci_epf *epf)
epf_ntb_epc_cleanup(ntb);
epf_ntb_config_spad_bar_free(ntb);
epf_ntb_epc_destroy(ntb);
pci_unregister_driver(&vntb_pci_driver);
}

View file

@ -84,7 +84,7 @@ static void pci_secondary_epc_epf_unlink(struct config_item *epf_item,
pci_epc_remove_epf(epc, epf, SECONDARY_INTERFACE);
}
static struct configfs_item_operations pci_secondary_epc_item_ops = {
static const struct configfs_item_operations pci_secondary_epc_item_ops = {
.allow_link = pci_secondary_epc_epf_link,
.drop_link = pci_secondary_epc_epf_unlink,
};
@ -148,7 +148,7 @@ static void pci_primary_epc_epf_unlink(struct config_item *epf_item,
pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
}
static struct configfs_item_operations pci_primary_epc_item_ops = {
static const struct configfs_item_operations pci_primary_epc_item_ops = {
.allow_link = pci_primary_epc_epf_link,
.drop_link = pci_primary_epc_epf_unlink,
};
@ -256,7 +256,7 @@ static void pci_epc_epf_unlink(struct config_item *epc_item,
pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
}
static struct configfs_item_operations pci_epc_item_ops = {
static const struct configfs_item_operations pci_epc_item_ops = {
.allow_link = pci_epc_epf_link,
.drop_link = pci_epc_epf_unlink,
};
@ -507,7 +507,7 @@ static void pci_epf_release(struct config_item *item)
kfree(epf_group);
}
static struct configfs_item_operations pci_epf_ops = {
static const struct configfs_item_operations pci_epf_ops = {
.allow_link = pci_epf_vepf_link,
.drop_link = pci_epf_vepf_unlink,
.release = pci_epf_release,
@ -565,7 +565,8 @@ static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group)
if (IS_ERR(group)) {
dev_err(&epf_group->epf->dev,
"failed to create epf type specific attributes\n");
"failed to create epf type specific attributes: %pe\n",
group);
return;
}
@ -578,13 +579,17 @@ static void pci_epf_cfs_add_sub_groups(struct pci_epf_group *epf_group)
group = pci_ep_cfs_add_primary_group(epf_group);
if (IS_ERR(group)) {
pr_err("failed to create 'primary' EPC interface\n");
dev_err(&epf_group->epf->dev,
"failed to create 'primary' EPC interface: %pe\n",
group);
return;
}
group = pci_ep_cfs_add_secondary_group(epf_group);
if (IS_ERR(group)) {
pr_err("failed to create 'secondary' EPC interface\n");
dev_err(&epf_group->epf->dev,
"failed to create 'secondary' EPC interface: %pe\n",
group);
return;
}
@ -624,8 +629,9 @@ static struct config_group *pci_epf_make(struct config_group *group,
epf = pci_epf_create(epf_name);
if (IS_ERR(epf)) {
pr_err("failed to create endpoint function device\n");
err = -EINVAL;
err = PTR_ERR(epf);
pr_err("failed to create endpoint function device (%s): %d\n",
epf_name, err);
goto free_name;
}
@ -657,7 +663,7 @@ static void pci_epf_drop(struct config_group *group, struct config_item *item)
config_item_put(item);
}
static struct configfs_group_operations pci_epf_group_ops = {
static const struct configfs_group_operations pci_epf_group_ops = {
.make_group = &pci_epf_make,
.drop_item = &pci_epf_drop,
};
@ -674,8 +680,8 @@ struct config_group *pci_ep_cfs_add_epf_group(const char *name)
group = configfs_register_default_group(functions_group, name,
&pci_epf_group_type);
if (IS_ERR(group))
pr_err("failed to register configfs group for %s function\n",
name);
pr_err("failed to register configfs group for %s function: %pe\n",
name, group);
return group;
}

View file

@ -50,6 +50,9 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
return -EINVAL;
}
if (epf->db_msg)
return -EBUSY;
domain = of_msi_map_get_device_domain(epc->dev.parent, 0,
DOMAIN_BUS_PLATFORM_MSI);
if (!domain) {
@ -79,6 +82,8 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
if (ret) {
dev_err(dev, "Failed to allocate MSI\n");
kfree(msg);
epf->db_msg = NULL;
epf->num_db = 0;
return ret;
}

View file

@ -103,8 +103,9 @@ enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features
bar++;
for (i = bar; i < PCI_STD_NUM_BARS; i++) {
/* If the BAR is not reserved, return it. */
if (epc_features->bar[i].type != BAR_RESERVED)
/* If the BAR is not reserved or disabled, return it. */
if (epc_features->bar[i].type != BAR_RESERVED &&
epc_features->bar[i].type != BAR_DISABLED)
return i;
}

View file

@ -149,7 +149,7 @@ EXPORT_SYMBOL_GPL(pci_epf_bind);
* @epf_vf: the virtual EP function to be added
*
* A physical endpoint function can be associated with multiple virtual
* endpoint functions. Invoke pci_epf_add_epf() to add a virtual PCI endpoint
* endpoint functions. Invoke pci_epf_add_vepf() to add a virtual PCI endpoint
* function to a physical PCI endpoint function.
*/
int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)

View file

@ -256,6 +256,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @msg_clear_mask: See ntb_msg_clear_mask().
* @msg_read: See ntb_msg_read().
* @peer_msg_write: See ntb_peer_msg_write().
* @get_dma_dev: See ntb_get_dma_dev().
*/
struct ntb_dev_ops {
int (*port_number)(struct ntb_dev *ntb);
@ -329,6 +330,7 @@ struct ntb_dev_ops {
int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
u32 (*msg_read)(struct ntb_dev *ntb, int *pidx, int midx);
int (*peer_msg_write)(struct ntb_dev *ntb, int pidx, int midx, u32 msg);
struct device *(*get_dma_dev)(struct ntb_dev *ntb);
};
static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@ -391,6 +393,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->msg_clear_mask == !ops->msg_count && */
!ops->msg_read == !ops->msg_count &&
!ops->peer_msg_write == !ops->msg_count &&
/* ops->get_dma_dev is optional */
1;
}
@ -1563,6 +1567,26 @@ static inline int ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
return ntb->ops->peer_msg_write(ntb, pidx, midx, msg);
}
/**
* ntb_get_dma_dev() - get the device to use for DMA allocations/mappings
* @ntb: NTB device context.
*
* Return a struct device suitable for DMA API allocations and mappings.
* This is typically the parent of the NTB device, but may be overridden by a
* driver by implementing .get_dma_dev().
*
* Drivers that implement .get_dma_dev() must return a non-NULL pointer.
*
* Return: device pointer to use for DMA operations.
*/
static inline struct device *ntb_get_dma_dev(struct ntb_dev *ntb)
{
if (!ntb->ops->get_dma_dev)
return ntb->dev.parent;
return ntb->ops->get_dma_dev(ntb);
}
/**
* ntb_peer_resource_idx() - get a resource index for a given peer idx
* @ntb: NTB device context.

View file

@ -191,13 +191,49 @@ struct pci_epc {
* @BAR_RESIZABLE: The BAR implements the PCI-SIG Resizable BAR Capability.
* NOTE: An EPC driver can currently only set a single supported
* size.
* @BAR_RESERVED: The BAR should not be touched by an EPF driver.
* @BAR_RESERVED: Used for HW-backed BARs (e.g. MSI-X table, DMA regs). The BAR
* should not be disabled by an EPC driver. The BAR should not be
* reprogrammed by an EPF driver. An EPF driver is allowed to
* disable the BAR if absolutely necessary. (However, right now
* there is no EPC operation to disable a BAR that has not been
* programmed using pci_epc_set_bar().)
* @BAR_DISABLED: The BAR should be disabled by an EPC driver. The BAR will be
* unavailable to an EPF driver.
*/
enum pci_epc_bar_type {
BAR_PROGRAMMABLE = 0,
BAR_FIXED,
BAR_RESIZABLE,
BAR_RESERVED,
BAR_DISABLED,
};
/**
* enum pci_epc_bar_rsvd_region_type - type of a fixed subregion behind a BAR
* @PCI_EPC_BAR_RSVD_DMA_CTRL_MMIO: Integrated DMA controller MMIO window
* @PCI_EPC_BAR_RSVD_MSIX_TBL_RAM: MSI-X table structure
* @PCI_EPC_BAR_RSVD_MSIX_PBA_RAM: MSI-X PBA structure
*
* BARs marked BAR_RESERVED are owned by the SoC/EPC hardware and must not be
* reprogrammed by EPF drivers. Some of them still expose fixed subregions that
* EPFs may want to reference (e.g. embedded doorbell fallback).
*/
enum pci_epc_bar_rsvd_region_type {
PCI_EPC_BAR_RSVD_DMA_CTRL_MMIO = 0,
PCI_EPC_BAR_RSVD_MSIX_TBL_RAM,
PCI_EPC_BAR_RSVD_MSIX_PBA_RAM,
};
/**
* struct pci_epc_bar_rsvd_region - fixed subregion behind a BAR
* @type: reserved region type
* @offset: offset within the BAR aperture
* @size: size of the reserved region
*/
struct pci_epc_bar_rsvd_region {
enum pci_epc_bar_rsvd_region_type type;
resource_size_t offset;
resource_size_t size;
};
/**
@ -206,18 +242,16 @@ enum pci_epc_bar_type {
* @fixed_size: the fixed size, only applicable if type is BAR_FIXED_MASK.
* @only_64bit: if true, an EPF driver is not allowed to choose if this BAR
* should be configured as 32-bit or 64-bit, the EPF driver must
* configure this BAR as 64-bit. Additionally, the BAR succeeding
* this BAR must be set to type BAR_RESERVED.
*
* only_64bit should not be set on a BAR of type BAR_RESERVED.
* (If BARx is a 64-bit BAR that an EPF driver is not allowed to
* touch, then both BARx and BARx+1 must be set to type
* BAR_RESERVED.)
* configure this BAR as 64-bit.
* @nr_rsvd_regions: number of fixed subregions described for BAR_RESERVED
* @rsvd_regions: fixed subregions behind BAR_RESERVED
*/
struct pci_epc_bar_desc {
enum pci_epc_bar_type type;
u64 fixed_size;
bool only_64bit;
u8 nr_rsvd_regions;
const struct pci_epc_bar_rsvd_region *rsvd_regions;
};
/**

View file

@ -67,6 +67,8 @@ TEST_F(pci_ep_bar, BAR_TEST)
pci_ep_ioctl(PCITEST_BAR, variant->barno);
if (ret == -ENODATA)
SKIP(return, "BAR is disabled");
if (ret == -ENOBUFS)
SKIP(return, "BAR is reserved");
EXPECT_FALSE(ret) TH_LOG("Test failed for BAR%d", variant->barno);
}
@ -84,6 +86,10 @@ TEST_F(pci_ep_bar, BAR_SUBRANGE_TEST)
SKIP(return, "BAR is test register space");
if (ret == -EOPNOTSUPP)
SKIP(return, "Subrange map is not supported");
if (ret == -ENOBUFS)
SKIP(return, "BAR is reserved");
if (ret == -ENOSPC)
SKIP(return, "Not enough inbound windows");
EXPECT_FALSE(ret) TH_LOG("Test failed for BAR%d", variant->barno);
}
@ -276,6 +282,8 @@ TEST_F(pcie_ep_doorbell, DOORBELL_TEST)
ASSERT_EQ(0, ret) TH_LOG("Can't set AUTO IRQ type");
pci_ep_ioctl(PCITEST_DOORBELL, 0);
if (ret == -EOPNOTSUPP)
SKIP(return, "Doorbell test is not supported");
EXPECT_FALSE(ret) TH_LOG("Test failed for Doorbell\n");
}
TEST_HARNESS_MAIN