mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
Merge branch 'endpoint'
* endpoint: misc: pci_endpoint_test: Add support for capabilities PCI: endpoint: pci-epf-test: Add support for capabilities PCI: endpoint: Verify that requested BAR size is a power of two PCI: endpoint: Add size check for fixed size BARs in pci_epc_set_bar() PCI: artpec6: Implement dw_pcie_ep operation get_features PCI: dwc: ep: Add 'address' alignment to 'size' check in dw_pcie_prog_ep_inbound_atu() PCI: dwc: ep: Prevent changing BAR size/flags in pci_epc_set_bar() PCI: dwc: ep: Write BAR_MASK before iATU registers in pci_epc_set_bar() PCI: endpoint: Finish virtual EP removal in pci_epf_remove_vepf() PCI: endpoint: Simplify pci_epc_get() PCI: endpoint: Destroy the EPC device in devm_pci_epc_destroy() PCI: endpoint: Replace magic number '6' by PCI_STD_NUM_BARS
This commit is contained in:
commit
889d559f82
@ -69,6 +69,9 @@
|
||||
#define PCI_ENDPOINT_TEST_FLAGS 0x2c
|
||||
#define FLAG_USE_DMA BIT(0)
|
||||
|
||||
#define PCI_ENDPOINT_TEST_CAPS 0x30
|
||||
#define CAP_UNALIGNED_ACCESS BIT(0)
|
||||
|
||||
#define PCI_DEVICE_ID_TI_AM654 0xb00c
|
||||
#define PCI_DEVICE_ID_TI_J7200 0xb00f
|
||||
#define PCI_DEVICE_ID_TI_AM64 0xb010
|
||||
@ -893,6 +896,20 @@ static const struct file_operations pci_endpoint_test_fops = {
|
||||
.unlocked_ioctl = pci_endpoint_test_ioctl,
|
||||
};
|
||||
|
||||
static void pci_endpoint_test_get_capabilities(struct pci_endpoint_test *test)
|
||||
{
|
||||
struct pci_dev *pdev = test->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
u32 caps;
|
||||
|
||||
caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS);
|
||||
dev_dbg(dev, "PCI_ENDPOINT_TEST_CAPS: %#x\n", caps);
|
||||
|
||||
/* CAP_UNALIGNED_ACCESS is set if the EP can do unaligned access */
|
||||
if (caps & CAP_UNALIGNED_ACCESS)
|
||||
test->alignment = 0;
|
||||
}
|
||||
|
||||
static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
@ -994,6 +1011,8 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
||||
goto err_kfree_test_name;
|
||||
}
|
||||
|
||||
pci_endpoint_test_get_capabilities(test);
|
||||
|
||||
misc_device = &test->miscdev;
|
||||
misc_device->minor = MISC_DYNAMIC_MINOR;
|
||||
misc_device->name = kstrdup(name, GFP_KERNEL);
|
||||
|
@ -369,9 +369,22 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_epc_features artpec6_pcie_epc_features = {
|
||||
.linkup_notifier = false,
|
||||
.msi_capable = true,
|
||||
.msix_capable = false,
|
||||
};
|
||||
|
||||
static const struct pci_epc_features *
|
||||
artpec6_pcie_get_features(struct dw_pcie_ep *ep)
|
||||
{
|
||||
return &artpec6_pcie_epc_features;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.init = artpec6_pcie_ep_init,
|
||||
.raise_irq = artpec6_pcie_raise_irq,
|
||||
.get_features = artpec6_pcie_get_features,
|
||||
};
|
||||
|
||||
static int artpec6_pcie_probe(struct platform_device *pdev)
|
||||
|
@ -128,7 +128,8 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
|
||||
dma_addr_t cpu_addr, enum pci_barno bar)
|
||||
dma_addr_t cpu_addr, enum pci_barno bar,
|
||||
size_t size)
|
||||
{
|
||||
int ret;
|
||||
u32 free_win;
|
||||
@ -145,7 +146,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
|
||||
}
|
||||
|
||||
ret = dw_pcie_prog_ep_inbound_atu(pci, func_no, free_win, type,
|
||||
cpu_addr, bar);
|
||||
cpu_addr, bar, size);
|
||||
if (ret < 0) {
|
||||
dev_err(pci->dev, "Failed to program IB window\n");
|
||||
return ret;
|
||||
@ -222,20 +223,31 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
if ((flags & PCI_BASE_ADDRESS_MEM_TYPE_64) && (bar & 1))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Certain EPF drivers dynamically change the physical address of a BAR
|
||||
* (i.e. they call set_bar() twice, without ever calling clear_bar(), as
|
||||
* calling clear_bar() would clear the BAR's PCI address assigned by the
|
||||
* host).
|
||||
*/
|
||||
if (ep->epf_bar[bar]) {
|
||||
/*
|
||||
* We can only dynamically change a BAR if the new BAR size and
|
||||
* BAR flags do not differ from the existing configuration.
|
||||
*/
|
||||
if (ep->epf_bar[bar]->barno != bar ||
|
||||
ep->epf_bar[bar]->size != size ||
|
||||
ep->epf_bar[bar]->flags != flags)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* When dynamically changing a BAR, skip writing the BAR reg, as
|
||||
* that would clear the BAR's PCI address assigned by the host.
|
||||
*/
|
||||
goto config_atu;
|
||||
}
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
|
||||
if (!(flags & PCI_BASE_ADDRESS_SPACE))
|
||||
type = PCIE_ATU_TYPE_MEM;
|
||||
else
|
||||
type = PCIE_ATU_TYPE_IO;
|
||||
|
||||
ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ep->epf_bar[bar])
|
||||
return 0;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
dw_pcie_ep_writel_dbi2(ep, func_no, reg, lower_32_bits(size - 1));
|
||||
@ -246,9 +258,21 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0);
|
||||
}
|
||||
|
||||
ep->epf_bar[bar] = epf_bar;
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
config_atu:
|
||||
if (!(flags & PCI_BASE_ADDRESS_SPACE))
|
||||
type = PCIE_ATU_TYPE_MEM;
|
||||
else
|
||||
type = PCIE_ATU_TYPE_IO;
|
||||
|
||||
ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar,
|
||||
size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ep->epf_bar[bar] = epf_bar;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -597,11 +597,12 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
}
|
||||
|
||||
int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u8 bar)
|
||||
int type, u64 cpu_addr, u8 bar, size_t size)
|
||||
{
|
||||
u32 retries, val;
|
||||
|
||||
if (!IS_ALIGNED(cpu_addr, pci->region_align))
|
||||
if (!IS_ALIGNED(cpu_addr, pci->region_align) ||
|
||||
!IS_ALIGNED(cpu_addr, size))
|
||||
return -EINVAL;
|
||||
|
||||
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
|
||||
|
@ -491,7 +491,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u64 size);
|
||||
int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u8 bar);
|
||||
int type, u64 cpu_addr, u8 bar, size_t size);
|
||||
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
|
||||
void dw_pcie_setup(struct dw_pcie *pci);
|
||||
void dw_pcie_iatu_detect(struct dw_pcie *pci);
|
||||
|
@ -44,6 +44,8 @@
|
||||
|
||||
#define TIMER_RESOLUTION 1
|
||||
|
||||
#define CAP_UNALIGNED_ACCESS BIT(0)
|
||||
|
||||
static struct workqueue_struct *kpcitest_workqueue;
|
||||
|
||||
struct pci_epf_test {
|
||||
@ -74,6 +76,7 @@ struct pci_epf_test_reg {
|
||||
u32 irq_type;
|
||||
u32 irq_number;
|
||||
u32 flags;
|
||||
u32 caps;
|
||||
} __packed;
|
||||
|
||||
static struct pci_epf_header test_header = {
|
||||
@ -739,6 +742,20 @@ static void pci_epf_test_clear_bar(struct pci_epf *epf)
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_epf_test_set_capabilities(struct pci_epf *epf)
|
||||
{
|
||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
struct pci_epc *epc = epf->epc;
|
||||
u32 caps = 0;
|
||||
|
||||
if (epc->ops->align_addr)
|
||||
caps |= CAP_UNALIGNED_ACCESS;
|
||||
|
||||
reg->caps = cpu_to_le32(caps);
|
||||
}
|
||||
|
||||
static int pci_epf_test_epc_init(struct pci_epf *epf)
|
||||
{
|
||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
@ -763,6 +780,8 @@ static int pci_epf_test_epc_init(struct pci_epf *epf)
|
||||
}
|
||||
}
|
||||
|
||||
pci_epf_test_set_capabilities(epf);
|
||||
|
||||
ret = pci_epf_test_set_bar(epf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -60,26 +60,17 @@ struct pci_epc *pci_epc_get(const char *epc_name)
|
||||
int ret = -EINVAL;
|
||||
struct pci_epc *epc;
|
||||
struct device *dev;
|
||||
struct class_dev_iter iter;
|
||||
|
||||
class_dev_iter_init(&iter, &pci_epc_class, NULL, NULL);
|
||||
while ((dev = class_dev_iter_next(&iter))) {
|
||||
if (strcmp(epc_name, dev_name(dev)))
|
||||
continue;
|
||||
dev = class_find_device_by_name(&pci_epc_class, epc_name);
|
||||
if (!dev)
|
||||
goto err;
|
||||
|
||||
epc = to_pci_epc(dev);
|
||||
if (!try_module_get(epc->ops->owner)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
class_dev_iter_exit(&iter);
|
||||
get_device(&epc->dev);
|
||||
epc = to_pci_epc(dev);
|
||||
if (try_module_get(epc->ops->owner))
|
||||
return epc;
|
||||
}
|
||||
|
||||
err:
|
||||
class_dev_iter_exit(&iter);
|
||||
put_device(dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epc_get);
|
||||
@ -609,10 +600,20 @@ EXPORT_SYMBOL_GPL(pci_epc_clear_bar);
|
||||
int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
struct pci_epf_bar *epf_bar)
|
||||
{
|
||||
int ret;
|
||||
const struct pci_epc_features *epc_features;
|
||||
enum pci_barno bar = epf_bar->barno;
|
||||
int flags = epf_bar->flags;
|
||||
int ret;
|
||||
|
||||
if (!pci_epc_function_is_valid(epc, func_no, vfunc_no))
|
||||
epc_features = pci_epc_get_features(epc, func_no, vfunc_no);
|
||||
if (!epc_features)
|
||||
return -EINVAL;
|
||||
|
||||
if (epc_features->bar[bar].type == BAR_FIXED &&
|
||||
(epc_features->bar[bar].fixed_size != epf_bar->size))
|
||||
return -EINVAL;
|
||||
|
||||
if (!is_power_of_2(epf_bar->size))
|
||||
return -EINVAL;
|
||||
|
||||
if ((epf_bar->barno == BAR_5 && flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ||
|
||||
@ -942,7 +943,7 @@ void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match,
|
||||
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");
|
||||
}
|
||||
|
@ -202,6 +202,7 @@ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
|
||||
|
||||
mutex_lock(&epf_pf->lock);
|
||||
clear_bit(epf_vf->vfunc_no, &epf_pf->vfunction_num_map);
|
||||
epf_vf->epf_pf = NULL;
|
||||
list_del(&epf_vf->list);
|
||||
mutex_unlock(&epf_pf->lock);
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ struct pci_epf {
|
||||
struct device dev;
|
||||
const char *name;
|
||||
struct pci_epf_header *header;
|
||||
struct pci_epf_bar bar[6];
|
||||
struct pci_epf_bar bar[PCI_STD_NUM_BARS];
|
||||
u8 msi_interrupts;
|
||||
u16 msix_interrupts;
|
||||
u8 func_no;
|
||||
@ -174,7 +174,7 @@ struct pci_epf {
|
||||
/* Below members are to attach secondary EPC to an endpoint function */
|
||||
struct pci_epc *sec_epc;
|
||||
struct list_head sec_epc_list;
|
||||
struct pci_epf_bar sec_epc_bar[6];
|
||||
struct pci_epf_bar sec_epc_bar[PCI_STD_NUM_BARS];
|
||||
u8 sec_epc_func_no;
|
||||
struct config_group *group;
|
||||
unsigned int is_bound;
|
||||
|
Loading…
Reference in New Issue
Block a user