Merge branch 'pci/endpoint'

- Convert PCI device data so pci-epf-test works correctly on big-endian
  endpoint systems (Niklas Cassel)

- Add BAR_RESIZABLE type to endpoint framework (Niklas Cassel)

- Add pci_epc_bar_size_to_rebar_cap() to convert a size to the Resizable
  BAR Capability so endpoint drivers can configure what the Capability
  register advertises (Niklas Cassel)

- Add DWC core support for EPF drivers to set BAR_RESIZABLE type and size
  via dw_pcie_ep_set_bar() (Niklas Cassel)

- Describe TI AM65x (keystone) BARs 2 and 5 as Resizable, not Fixed
  (Niklas Cassel)

- Reduce TI AM65x (keystone) BAR alignment requirement from 1MB to 64KB
  (Niklas Cassel)

- Describe Rockchip rk3568 and rk3588 BARs as Resizable, not Fixed (Niklas
  Cassel)

- Drop unused devm_pci_epc_destroy() (Zijun Hu)

- Fix pci-epf-test double free that causes an oops if the host reboots and
  PERST# deassertion restarts endpoint BAR allocation (Christian Bruel)

- Drop dw_pcie_ep_find_ext_capability() and use
  dw_pcie_find_ext_capability() instead (Niklas Cassel)

* pci/endpoint:
  PCI: dwc: ep: Remove superfluous function dw_pcie_ep_find_ext_capability()
  PCI: endpoint: pci-epf-test: Fix double free that causes kernel to oops
  PCI: endpoint: Remove unused devm_pci_epc_destroy()
  PCI: dw-rockchip: Describe Resizable BARs as Resizable BARs
  PCI: keystone: Specify correct alignment requirement
  PCI: keystone: Describe Resizable BARs as Resizable BARs
  PCI: dwc: ep: Allow EPF drivers to configure the size of Resizable BARs
  PCI: dwc: ep: Move dw_pcie_ep_find_ext_capability()
  PCI: endpoint: Add pci_epc_bar_size_to_rebar_cap()
  PCI: endpoint: Allow EPF drivers to configure the size of Resizable BARs
  PCI: endpoint: pci-epf-test: Handle endianness properly
This commit is contained in:
Bjorn Helgaas 2025-03-27 13:14:46 -05:00
commit a113afb84a
8 changed files with 301 additions and 132 deletions

View file

@ -57,11 +57,10 @@ by the PCI controller driver.
The PCI controller driver can then create a new EPC device by invoking
devm_pci_epc_create()/pci_epc_create().
* devm_pci_epc_destroy()/pci_epc_destroy()
* pci_epc_destroy()
The PCI controller driver can destroy the EPC device created by either
devm_pci_epc_create() or pci_epc_create() using devm_pci_epc_destroy() or
pci_epc_destroy().
The PCI controller driver can destroy the EPC device created by
pci_epc_create() using pci_epc_destroy().
* pci_epc_linkup()

View file

@ -966,11 +966,11 @@ static const struct pci_epc_features ks_pcie_am654_epc_features = {
.msix_capable = true,
.bar[BAR_0] = { .type = BAR_RESERVED, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_2] = { .type = BAR_RESIZABLE, },
.bar[BAR_3] = { .type = BAR_FIXED, .fixed_size = SZ_64K, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256, },
.bar[BAR_5] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.align = SZ_1M,
.bar[BAR_5] = { .type = BAR_RESIZABLE, },
.align = SZ_64K,
};
static const struct pci_epc_features*

View file

@ -205,6 +205,125 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
ep->bar_to_atu[bar] = 0;
}
static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci,
enum pci_barno bar)
{
u32 reg, bar_index;
unsigned int offset, nbars;
int i;
offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
if (!offset)
return offset;
reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> PCI_REBAR_CTRL_NBAR_SHIFT;
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) {
reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
bar_index = reg & PCI_REBAR_CTRL_BAR_IDX;
if (bar_index == bar)
return offset;
}
return 0;
}
static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no,
struct pci_epf_bar *epf_bar)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar = epf_bar->barno;
size_t size = epf_bar->size;
int flags = epf_bar->flags;
u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
unsigned int rebar_offset;
u32 rebar_cap, rebar_ctrl;
int ret;
rebar_offset = dw_pcie_ep_get_rebar_offset(pci, bar);
if (!rebar_offset)
return -EINVAL;
ret = pci_epc_bar_size_to_rebar_cap(size, &rebar_cap);
if (ret)
return ret;
dw_pcie_dbi_ro_wr_en(pci);
/*
* A BAR mask should not be written for a resizable BAR. The BAR mask
* is automatically derived by the controller every time the "selected
* size" bits are updated, see "Figure 3-26 Resizable BAR Example for
* 32-bit Memory BAR0" in DWC EP databook 5.96a. We simply need to write
* BIT(0) to set the BAR enable bit.
*/
dw_pcie_ep_writel_dbi2(ep, func_no, reg, BIT(0));
dw_pcie_ep_writel_dbi(ep, func_no, reg, flags);
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
dw_pcie_ep_writel_dbi2(ep, func_no, reg + 4, 0);
dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0);
}
/*
* Bits 31:0 in PCI_REBAR_CAP define "supported sizes" bits for sizes
* 1 MB to 128 TB. Bits 31:16 in PCI_REBAR_CTRL define "supported sizes"
* bits for sizes 256 TB to 8 EB. Disallow sizes 256 TB to 8 EB.
*/
rebar_ctrl = dw_pcie_readl_dbi(pci, rebar_offset + PCI_REBAR_CTRL);
rebar_ctrl &= ~GENMASK(31, 16);
dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl);
/*
* The "selected size" (bits 13:8) in PCI_REBAR_CTRL are automatically
* updated when writing PCI_REBAR_CAP, see "Figure 3-26 Resizable BAR
* Example for 32-bit Memory BAR0" in DWC EP databook 5.96a.
*/
dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CAP, rebar_cap);
dw_pcie_dbi_ro_wr_dis(pci);
return 0;
}
static int dw_pcie_ep_set_bar_programmable(struct dw_pcie_ep *ep, u8 func_no,
struct pci_epf_bar *epf_bar)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar = epf_bar->barno;
size_t size = epf_bar->size;
int flags = epf_bar->flags;
u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
dw_pcie_dbi_ro_wr_en(pci);
dw_pcie_ep_writel_dbi2(ep, func_no, reg, lower_32_bits(size - 1));
dw_pcie_ep_writel_dbi(ep, func_no, reg, flags);
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
dw_pcie_ep_writel_dbi2(ep, func_no, reg + 4, upper_32_bits(size - 1));
dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0);
}
dw_pcie_dbi_ro_wr_dis(pci);
return 0;
}
static enum pci_epc_bar_type dw_pcie_ep_get_bar_type(struct dw_pcie_ep *ep,
enum pci_barno bar)
{
const struct pci_epc_features *epc_features;
if (!ep->ops->get_features)
return BAR_PROGRAMMABLE;
epc_features = ep->ops->get_features(ep);
return epc_features->bar[bar].type;
}
static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
struct pci_epf_bar *epf_bar)
{
@ -212,9 +331,9 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar = epf_bar->barno;
size_t size = epf_bar->size;
enum pci_epc_bar_type bar_type;
int flags = epf_bar->flags;
int ret, type;
u32 reg;
/*
* DWC does not allow BAR pairs to overlap, e.g. you cannot combine BARs
@ -246,19 +365,30 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
goto config_atu;
}
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
dw_pcie_dbi_ro_wr_en(pci);
dw_pcie_ep_writel_dbi2(ep, func_no, reg, lower_32_bits(size - 1));
dw_pcie_ep_writel_dbi(ep, func_no, reg, flags);
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
dw_pcie_ep_writel_dbi2(ep, func_no, reg + 4, upper_32_bits(size - 1));
dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0);
bar_type = dw_pcie_ep_get_bar_type(ep, bar);
switch (bar_type) {
case BAR_FIXED:
/*
* There is no need to write a BAR mask for a fixed BAR (except
* to write 1 to the LSB of the BAR mask register, to enable the
* BAR). Write the BAR mask regardless. (The fixed bits in the
* BAR mask register will be read-only anyway.)
*/
fallthrough;
case BAR_PROGRAMMABLE:
ret = dw_pcie_ep_set_bar_programmable(ep, func_no, epf_bar);
break;
case BAR_RESIZABLE:
ret = dw_pcie_ep_set_bar_resizable(ep, func_no, epf_bar);
break;
default:
ret = -EINVAL;
dev_err(pci->dev, "Invalid BAR type\n");
break;
}
dw_pcie_dbi_ro_wr_dis(pci);
if (ret)
return ret;
config_atu:
if (!(flags & PCI_BASE_ADDRESS_SPACE))
@ -690,31 +820,15 @@ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep)
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit);
static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
{
u32 header;
int pos = PCI_CFG_SPACE_SIZE;
while (pos) {
header = dw_pcie_readl_dbi(pci, pos);
if (PCI_EXT_CAP_ID(header) == cap)
return pos;
pos = PCI_EXT_CAP_NEXT(header);
if (!pos)
break;
}
return 0;
}
static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
{
struct dw_pcie_ep *ep = &pci->ep;
unsigned int offset;
unsigned int nbars;
u32 reg, i;
enum pci_barno bar;
u32 reg, i, val;
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
dw_pcie_dbi_ro_wr_en(pci);
@ -727,9 +841,29 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
* PCIe r6.0, sec 7.8.6.2 require us to support at least one
* size in the range from 1 MB to 512 GB. Advertise support
* for 1 MB BAR size only.
*
* For a BAR that has been configured via dw_pcie_ep_set_bar(),
* advertise support for only that size instead.
*/
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, BIT(4));
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) {
/*
* While the RESBAR_CAP_REG_* fields are sticky, the
* RESBAR_CTRL_REG_BAR_SIZE field is non-sticky (it is
* sticky in certain versions of DWC PCIe, but not all).
*
* RESBAR_CTRL_REG_BAR_SIZE is updated automatically by
* the controller when RESBAR_CAP_REG is written, which
* is why RESBAR_CAP_REG is written here.
*/
val = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
bar = val & PCI_REBAR_CTRL_BAR_IDX;
if (ep->epf_bar[bar])
pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val);
else
val = BIT(4);
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, val);
}
}
dw_pcie_setup(pci);
@ -817,7 +951,7 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
if (ep->ops->init)
ep->ops->init(ep);
ptm_cap_base = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
/*
* PTM responder capability can be disabled only after disabling

View file

@ -273,12 +273,12 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = {
.msi_capable = true,
.msix_capable = true,
.align = SZ_64K,
.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_3] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_5] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_0] = { .type = BAR_RESIZABLE, },
.bar[BAR_1] = { .type = BAR_RESIZABLE, },
.bar[BAR_2] = { .type = BAR_RESIZABLE, },
.bar[BAR_3] = { .type = BAR_RESIZABLE, },
.bar[BAR_4] = { .type = BAR_RESIZABLE, },
.bar[BAR_5] = { .type = BAR_RESIZABLE, },
};
/*
@ -293,12 +293,12 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = {
.msi_capable = true,
.msix_capable = true,
.align = SZ_64K,
.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_3] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_0] = { .type = BAR_RESIZABLE, },
.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_5] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_5] = { .type = BAR_RESIZABLE, },
};
static const struct pci_epc_features *

View file

@ -66,17 +66,17 @@ struct pci_epf_test {
};
struct pci_epf_test_reg {
u32 magic;
u32 command;
u32 status;
u64 src_addr;
u64 dst_addr;
u32 size;
u32 checksum;
u32 irq_type;
u32 irq_number;
u32 flags;
u32 caps;
__le32 magic;
__le32 command;
__le32 status;
__le64 src_addr;
__le64 dst_addr;
__le32 size;
__le32 checksum;
__le32 irq_type;
__le32 irq_number;
__le32 flags;
__le32 caps;
} __packed;
static struct pci_epf_header test_header = {
@ -324,13 +324,17 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
struct pci_epc *epc = epf->epc;
struct device *dev = &epf->dev;
struct pci_epc_map src_map, dst_map;
u64 src_addr = reg->src_addr;
u64 dst_addr = reg->dst_addr;
size_t copy_size = reg->size;
u64 src_addr = le64_to_cpu(reg->src_addr);
u64 dst_addr = le64_to_cpu(reg->dst_addr);
size_t orig_size, copy_size;
ssize_t map_size = 0;
u32 flags = le32_to_cpu(reg->flags);
u32 status = 0;
void *copy_buf = NULL, *buf;
if (reg->flags & FLAG_USE_DMA) {
orig_size = copy_size = le32_to_cpu(reg->size);
if (flags & FLAG_USE_DMA) {
if (!dma_has_cap(DMA_MEMCPY, epf_test->dma_chan_tx->device->cap_mask)) {
dev_err(dev, "DMA controller doesn't support MEMCPY\n");
ret = -EINVAL;
@ -350,7 +354,7 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
src_addr, copy_size, &src_map);
if (ret) {
dev_err(dev, "Failed to map source address\n");
reg->status = STATUS_SRC_ADDR_INVALID;
status = STATUS_SRC_ADDR_INVALID;
goto free_buf;
}
@ -358,7 +362,7 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
dst_addr, copy_size, &dst_map);
if (ret) {
dev_err(dev, "Failed to map destination address\n");
reg->status = STATUS_DST_ADDR_INVALID;
status = STATUS_DST_ADDR_INVALID;
pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no,
&src_map);
goto free_buf;
@ -367,7 +371,7 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
map_size = min_t(size_t, dst_map.pci_size, src_map.pci_size);
ktime_get_ts64(&start);
if (reg->flags & FLAG_USE_DMA) {
if (flags & FLAG_USE_DMA) {
ret = pci_epf_test_data_transfer(epf_test,
dst_map.phys_addr, src_map.phys_addr,
map_size, 0, DMA_MEM_TO_MEM);
@ -391,8 +395,8 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
map_size = 0;
}
pci_epf_test_print_rate(epf_test, "COPY", reg->size, &start,
&end, reg->flags & FLAG_USE_DMA);
pci_epf_test_print_rate(epf_test, "COPY", orig_size, &start, &end,
flags & FLAG_USE_DMA);
unmap:
if (map_size) {
@ -405,9 +409,10 @@ free_buf:
set_status:
if (!ret)
reg->status |= STATUS_COPY_SUCCESS;
status |= STATUS_COPY_SUCCESS;
else
reg->status |= STATUS_COPY_FAIL;
status |= STATUS_COPY_FAIL;
reg->status = cpu_to_le32(status);
}
static void pci_epf_test_read(struct pci_epf_test *epf_test,
@ -423,9 +428,14 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
struct pci_epc *epc = epf->epc;
struct device *dev = &epf->dev;
struct device *dma_dev = epf->epc->dev.parent;
u64 src_addr = reg->src_addr;
size_t src_size = reg->size;
u64 src_addr = le64_to_cpu(reg->src_addr);
size_t orig_size, src_size;
ssize_t map_size = 0;
u32 flags = le32_to_cpu(reg->flags);
u32 checksum = le32_to_cpu(reg->checksum);
u32 status = 0;
orig_size = src_size = le32_to_cpu(reg->size);
src_buf = kzalloc(src_size, GFP_KERNEL);
if (!src_buf) {
@ -439,12 +449,12 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
src_addr, src_size, &map);
if (ret) {
dev_err(dev, "Failed to map address\n");
reg->status = STATUS_SRC_ADDR_INVALID;
status = STATUS_SRC_ADDR_INVALID;
goto free_buf;
}
map_size = map.pci_size;
if (reg->flags & FLAG_USE_DMA) {
if (flags & FLAG_USE_DMA) {
dst_phys_addr = dma_map_single(dma_dev, buf, map_size,
DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, dst_phys_addr)) {
@ -481,11 +491,11 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
map_size = 0;
}
pci_epf_test_print_rate(epf_test, "READ", reg->size, &start,
&end, reg->flags & FLAG_USE_DMA);
pci_epf_test_print_rate(epf_test, "READ", orig_size, &start, &end,
flags & FLAG_USE_DMA);
crc32 = crc32_le(~0, src_buf, reg->size);
if (crc32 != reg->checksum)
crc32 = crc32_le(~0, src_buf, orig_size);
if (crc32 != checksum)
ret = -EIO;
unmap:
@ -497,9 +507,10 @@ free_buf:
set_status:
if (!ret)
reg->status |= STATUS_READ_SUCCESS;
status |= STATUS_READ_SUCCESS;
else
reg->status |= STATUS_READ_FAIL;
status |= STATUS_READ_FAIL;
reg->status = cpu_to_le32(status);
}
static void pci_epf_test_write(struct pci_epf_test *epf_test,
@ -514,9 +525,13 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
struct pci_epc *epc = epf->epc;
struct device *dev = &epf->dev;
struct device *dma_dev = epf->epc->dev.parent;
u64 dst_addr = reg->dst_addr;
size_t dst_size = reg->size;
u64 dst_addr = le64_to_cpu(reg->dst_addr);
size_t orig_size, dst_size;
ssize_t map_size = 0;
u32 flags = le32_to_cpu(reg->flags);
u32 status = 0;
orig_size = dst_size = le32_to_cpu(reg->size);
dst_buf = kzalloc(dst_size, GFP_KERNEL);
if (!dst_buf) {
@ -524,7 +539,7 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
goto set_status;
}
get_random_bytes(dst_buf, dst_size);
reg->checksum = crc32_le(~0, dst_buf, dst_size);
reg->checksum = cpu_to_le32(crc32_le(~0, dst_buf, dst_size));
buf = dst_buf;
while (dst_size) {
@ -532,12 +547,12 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
dst_addr, dst_size, &map);
if (ret) {
dev_err(dev, "Failed to map address\n");
reg->status = STATUS_DST_ADDR_INVALID;
status = STATUS_DST_ADDR_INVALID;
goto free_buf;
}
map_size = map.pci_size;
if (reg->flags & FLAG_USE_DMA) {
if (flags & FLAG_USE_DMA) {
src_phys_addr = dma_map_single(dma_dev, buf, map_size,
DMA_TO_DEVICE);
if (dma_mapping_error(dma_dev, src_phys_addr)) {
@ -576,8 +591,8 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
map_size = 0;
}
pci_epf_test_print_rate(epf_test, "WRITE", reg->size, &start,
&end, reg->flags & FLAG_USE_DMA);
pci_epf_test_print_rate(epf_test, "WRITE", orig_size, &start, &end,
flags & FLAG_USE_DMA);
/*
* wait 1ms inorder for the write to complete. Without this delay L3
@ -594,9 +609,10 @@ free_buf:
set_status:
if (!ret)
reg->status |= STATUS_WRITE_SUCCESS;
status |= STATUS_WRITE_SUCCESS;
else
reg->status |= STATUS_WRITE_FAIL;
status |= STATUS_WRITE_FAIL;
reg->status = cpu_to_le32(status);
}
static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
@ -605,39 +621,42 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
u32 status = reg->status | STATUS_IRQ_RAISED;
u32 status = le32_to_cpu(reg->status);
u32 irq_number = le32_to_cpu(reg->irq_number);
u32 irq_type = le32_to_cpu(reg->irq_type);
int count;
/*
* Set the status before raising the IRQ to ensure that the host sees
* the updated value when it gets the IRQ.
*/
WRITE_ONCE(reg->status, status);
status |= STATUS_IRQ_RAISED;
WRITE_ONCE(reg->status, cpu_to_le32(status));
switch (reg->irq_type) {
switch (irq_type) {
case IRQ_TYPE_INTX:
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
PCI_IRQ_INTX, 0);
break;
case IRQ_TYPE_MSI:
count = pci_epc_get_msi(epc, epf->func_no, epf->vfunc_no);
if (reg->irq_number > count || count <= 0) {
if (irq_number > count || count <= 0) {
dev_err(dev, "Invalid MSI IRQ number %d / %d\n",
reg->irq_number, count);
irq_number, count);
return;
}
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
PCI_IRQ_MSI, reg->irq_number);
PCI_IRQ_MSI, irq_number);
break;
case IRQ_TYPE_MSIX:
count = pci_epc_get_msix(epc, epf->func_no, epf->vfunc_no);
if (reg->irq_number > count || count <= 0) {
if (irq_number > count || count <= 0) {
dev_err(dev, "Invalid MSIX IRQ number %d / %d\n",
reg->irq_number, count);
irq_number, count);
return;
}
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
PCI_IRQ_MSIX, reg->irq_number);
PCI_IRQ_MSIX, irq_number);
break;
default:
dev_err(dev, "Failed to raise IRQ, unknown type\n");
@ -654,21 +673,22 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
struct device *dev = &epf->dev;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
u32 irq_type = le32_to_cpu(reg->irq_type);
command = READ_ONCE(reg->command);
command = le32_to_cpu(READ_ONCE(reg->command));
if (!command)
goto reset_handler;
WRITE_ONCE(reg->command, 0);
WRITE_ONCE(reg->status, 0);
if ((READ_ONCE(reg->flags) & FLAG_USE_DMA) &&
if ((le32_to_cpu(READ_ONCE(reg->flags)) & FLAG_USE_DMA) &&
!epf_test->dma_supported) {
dev_err(dev, "Cannot transfer data using DMA\n");
goto reset_handler;
}
if (reg->irq_type > IRQ_TYPE_MSIX) {
if (irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Failed to detect IRQ type\n");
goto reset_handler;
}
@ -718,6 +738,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
if (ret) {
pci_epf_free_space(epf, epf_test->reg[bar], bar,
PRIMARY_INTERFACE);
epf_test->reg[bar] = NULL;
dev_err(dev, "Failed to set BAR%d\n", bar);
if (bar == test_reg_bar)
return ret;
@ -909,6 +930,7 @@ static void pci_epf_test_free_space(struct pci_epf *epf)
pci_epf_free_space(epf, epf_test->reg[bar], bar,
PRIMARY_INTERFACE);
epf_test->reg[bar] = NULL;
}
}

View file

@ -25,13 +25,6 @@ static void devm_pci_epc_release(struct device *dev, void *res)
pci_epc_destroy(epc);
}
static int devm_pci_epc_match(struct device *dev, void *res, void *match_data)
{
struct pci_epc **epc = res;
return *epc == match_data;
}
/**
* pci_epc_put() - release the PCI endpoint controller
* @epc: epc returned by pci_epc_get()
@ -609,6 +602,10 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
if (!epc_features)
return -EINVAL;
if (epc_features->bar[bar].type == BAR_RESIZABLE &&
(epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024)))
return -EINVAL;
if (epc_features->bar[bar].type == BAR_FIXED &&
(epc_features->bar[bar].fixed_size != epf_bar->size))
return -EINVAL;
@ -634,6 +631,33 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
}
EXPORT_SYMBOL_GPL(pci_epc_set_bar);
/**
* pci_epc_bar_size_to_rebar_cap() - convert a size to the representation used
* by the Resizable BAR Capability Register
* @size: the size to convert
* @cap: where to store the result
*
* Returns 0 on success and a negative error code in case of error.
*/
int pci_epc_bar_size_to_rebar_cap(size_t size, u32 *cap)
{
/*
* As per PCIe r6.0, sec 7.8.6.2, min size for a resizable BAR is 1 MB,
* thus disallow a requested BAR size smaller than 1 MB.
* Disallow a requested BAR size larger than 128 TB.
*/
if (size < SZ_1M || (u64)size > (SZ_128G * 1024))
return -EINVAL;
*cap = ilog2(size) - ilog2(SZ_1M);
/* Sizes in REBAR_CAP start at BIT(4). */
*cap = BIT(*cap + 4);
return 0;
}
EXPORT_SYMBOL_GPL(pci_epc_bar_size_to_rebar_cap);
/**
* pci_epc_write_header() - write standard configuration header
* @epc: the EPC device to which the configuration header should be written
@ -931,24 +955,6 @@ void pci_epc_destroy(struct pci_epc *epc)
}
EXPORT_SYMBOL_GPL(pci_epc_destroy);
/**
* devm_pci_epc_destroy() - destroy the EPC device
* @dev: device that wants to destroy the EPC
* @epc: the EPC device that has to be destroyed
*
* Invoke to destroy the devres associated with this
* pci_epc and destroy the EPC device.
*/
void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc)
{
int r;
r = devres_release(dev, devm_pci_epc_release, devm_pci_epc_match,
epc);
dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n");
}
EXPORT_SYMBOL_GPL(devm_pci_epc_destroy);
static void pci_epc_release(struct device *dev)
{
kfree(to_pci_epc(dev));

View file

@ -274,6 +274,10 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
if (size < 128)
size = 128;
/* According to PCIe base spec, min size for a resizable BAR is 1 MB. */
if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M)
size = SZ_1M;
if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
if (size > bar_fixed_size) {
dev_err(&epf->dev,

View file

@ -188,11 +188,15 @@ struct pci_epc {
* enum pci_epc_bar_type - configurability of endpoint BAR
* @BAR_PROGRAMMABLE: The BAR mask can be configured by the EPC.
* @BAR_FIXED: The BAR mask is fixed by the hardware.
* @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.
*/
enum pci_epc_bar_type {
BAR_PROGRAMMABLE = 0,
BAR_FIXED,
BAR_RESIZABLE,
BAR_RESERVED,
};
@ -257,7 +261,6 @@ __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
struct pci_epc *
__pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
struct module *owner);
void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc);
void pci_epc_destroy(struct pci_epc *epc);
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
enum pci_epc_interface_type type);
@ -271,6 +274,7 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
enum pci_epc_interface_type type);
int pci_epc_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
struct pci_epf_header *hdr);
int pci_epc_bar_size_to_rebar_cap(size_t size, u32 *cap);
int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
struct pci_epf_bar *epf_bar);
void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,