mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00
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:
commit
a113afb84a
8 changed files with 301 additions and 132 deletions
|
@ -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()
|
||||
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue