diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2017-09-07 13:24:11 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-09-07 13:24:11 -0500 |
commit | 3a749ea1c0271cbadf234befe307f14267325836 (patch) | |
tree | 994011aaa620f43a0c61d14320f329dc04c330e6 | |
parent | 99fd1b958cd36dc13fa441d63c4e93a39e17fb65 (diff) | |
parent | e475842232042b0581b5488105fc17adef8fcff8 (diff) |
Merge branch 'pci/endpoint' into next
* pci/endpoint:
tools: PCI: Add a missing option help line
misc: pci_endpoint_test: Enable/Disable MSI using module param
misc: pci_endpoint_test: Avoid using hard-coded BAR sizes
misc: pci_endpoint_test: Add support to not enable MSI interrupts
misc: pci_endpoint_test: Add support to provide aligned buffer addresses
misc: pci_endpoint_test: Add support for PCI_ENDPOINT_TEST regs to be mapped to any BAR
PCI: designware-ep: Do not disable BARs during initialization
PCI: dra7xx: Reset all BARs during initialization
PCI: dwc: designware: Provide page_size to pci_epc_mem
PCI: endpoint: Remove the ->remove() callback
PCI: endpoint: Add support to poll early for host commands
PCI: endpoint: Add support to use _any_ BAR to map PCI_ENDPOINT_TEST regs
PCI: endpoint: Do not reset *command* inadvertently
PCI: endpoint: Add "volatile" to pci_epf_test_reg
PCI: endpoint: Add support for configurable page size
PCI: endpoint: Make ->remove() callback optional
PCI: endpoint: Add an API to get matching "pci_epf_device_id"
PCI: endpoint: Use of_dma_configure() to set initial DMA mask
-rw-r--r-- | drivers/misc/pci_endpoint_test.c | 132 | ||||
-rw-r--r-- | drivers/pci/dwc/pci-dra7xx.c | 13 | ||||
-rw-r--r-- | drivers/pci/dwc/pcie-designware-ep.c | 7 | ||||
-rw-r--r-- | drivers/pci/dwc/pcie-designware.h | 1 | ||||
-rw-r--r-- | drivers/pci/endpoint/functions/pci-epf-test.c | 99 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-epc-core.c | 11 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-epc-mem.c | 59 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-epf-core.c | 21 | ||||
-rw-r--r-- | include/linux/pci-epc.h | 8 | ||||
-rw-r--r-- | include/linux/pci-epf.h | 2 | ||||
-rw-r--r-- | tools/pci/pcitest.c | 1 |
11 files changed, 276 insertions, 78 deletions
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 09c10f426b64..deb203026496 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -72,6 +72,11 @@ static DEFINE_IDA(pci_endpoint_test_ida); #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ miscdev) + +static bool no_msi; +module_param(no_msi, bool, 0444); +MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test"); + enum pci_barno { BAR_0, BAR_1, @@ -90,9 +95,15 @@ struct pci_endpoint_test { /* mutex to protect the ioctls */ struct mutex mutex; struct miscdevice miscdev; + enum pci_barno test_reg_bar; + size_t alignment; }; -static int bar_size[] = { 4, 512, 1024, 16384, 131072, 1048576 }; +struct pci_endpoint_test_data { + enum pci_barno test_reg_bar; + size_t alignment; + bool no_msi; +}; static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, u32 offset) @@ -141,11 +152,15 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, int j; u32 val; int size; + struct pci_dev *pdev = test->pdev; if (!test->bar[barno]) return false; - size = bar_size[barno]; + size = pci_resource_len(pdev, barno); + + if (barno == test->test_reg_bar) + size = 0x4; for (j = 0; j < size; j += 4) pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); @@ -202,16 +217,32 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) dma_addr_t dst_phys_addr; struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; + void *orig_src_addr; + dma_addr_t orig_src_phys_addr; + void *orig_dst_addr; + dma_addr_t orig_dst_phys_addr; + size_t offset; + size_t alignment = test->alignment; u32 src_crc32; u32 dst_crc32; - src_addr = dma_alloc_coherent(dev, size, &src_phys_addr, GFP_KERNEL); - if (!src_addr) { + orig_src_addr = dma_alloc_coherent(dev, size + alignment, + &orig_src_phys_addr, GFP_KERNEL); + if (!orig_src_addr) { dev_err(dev, "failed to allocate source buffer\n"); ret = false; goto err; } + if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) { + src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment); + offset = src_phys_addr - orig_src_phys_addr; + src_addr = orig_src_addr + offset; + } else { + src_phys_addr = orig_src_phys_addr; + src_addr = orig_src_addr; + } + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, lower_32_bits(src_phys_addr)); @@ -221,11 +252,21 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) get_random_bytes(src_addr, size); src_crc32 = crc32_le(~0, src_addr, size); - dst_addr = dma_alloc_coherent(dev, size, &dst_phys_addr, GFP_KERNEL); - if (!dst_addr) { + orig_dst_addr = dma_alloc_coherent(dev, size + alignment, + &orig_dst_phys_addr, GFP_KERNEL); + if (!orig_dst_addr) { dev_err(dev, "failed to allocate destination address\n"); ret = false; - goto err_src_addr; + goto err_orig_src_addr; + } + + if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) { + dst_phys_addr = PTR_ALIGN(orig_dst_phys_addr, alignment); + offset = dst_phys_addr - orig_dst_phys_addr; + dst_addr = orig_dst_addr + offset; + } else { + dst_phys_addr = orig_dst_phys_addr; + dst_addr = orig_dst_addr; } pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, @@ -245,10 +286,12 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) if (dst_crc32 == src_crc32) ret = true; - dma_free_coherent(dev, size, dst_addr, dst_phys_addr); + dma_free_coherent(dev, size + alignment, orig_dst_addr, + orig_dst_phys_addr); -err_src_addr: - dma_free_coherent(dev, size, src_addr, src_phys_addr); +err_orig_src_addr: + dma_free_coherent(dev, size + alignment, orig_src_addr, + orig_src_phys_addr); err: return ret; @@ -262,15 +305,29 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) dma_addr_t phys_addr; struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; + void *orig_addr; + dma_addr_t orig_phys_addr; + size_t offset; + size_t alignment = test->alignment; u32 crc32; - addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); - if (!addr) { + orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, + GFP_KERNEL); + if (!orig_addr) { dev_err(dev, "failed to allocate address\n"); ret = false; goto err; } + if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) { + phys_addr = PTR_ALIGN(orig_phys_addr, alignment); + offset = phys_addr - orig_phys_addr; + addr = orig_addr + offset; + } else { + phys_addr = orig_phys_addr; + addr = orig_addr; + } + get_random_bytes(addr, size); crc32 = crc32_le(~0, addr, size); @@ -293,7 +350,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) if (reg & STATUS_READ_SUCCESS) ret = true; - dma_free_coherent(dev, size, addr, phys_addr); + dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); err: return ret; @@ -306,15 +363,29 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) dma_addr_t phys_addr; struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; + void *orig_addr; + dma_addr_t orig_phys_addr; + size_t offset; + size_t alignment = test->alignment; u32 crc32; - addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); - if (!addr) { + orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, + GFP_KERNEL); + if (!orig_addr) { dev_err(dev, "failed to allocate destination address\n"); ret = false; goto err; } + if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) { + phys_addr = PTR_ALIGN(orig_phys_addr, alignment); + offset = phys_addr - orig_phys_addr; + addr = orig_addr + offset; + } else { + phys_addr = orig_phys_addr; + addr = orig_addr; + } + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, lower_32_bits(phys_addr)); pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, @@ -331,7 +402,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) ret = true; - dma_free_coherent(dev, size, addr, phys_addr); + dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); err: return ret; } @@ -383,13 +454,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, { int i; int err; - int irq; + int irq = 0; int id; char name[20]; enum pci_barno bar; void __iomem *base; struct device *dev = &pdev->dev; struct pci_endpoint_test *test; + struct pci_endpoint_test_data *data; + enum pci_barno test_reg_bar = BAR_0; struct miscdevice *misc_device; if (pci_is_bridge(pdev)) @@ -399,7 +472,17 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, if (!test) return -ENOMEM; + test->test_reg_bar = 0; + test->alignment = 0; test->pdev = pdev; + + data = (struct pci_endpoint_test_data *)ent->driver_data; + if (data) { + test_reg_bar = data->test_reg_bar; + test->alignment = data->alignment; + no_msi = data->no_msi; + } + init_completion(&test->irq_raised); mutex_init(&test->mutex); @@ -417,9 +500,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, pci_set_master(pdev); - irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); - if (irq < 0) - dev_err(dev, "failed to get MSI interrupts\n"); + if (!no_msi) { + irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); + if (irq < 0) + dev_err(dev, "failed to get MSI interrupts\n"); + } err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, IRQF_SHARED, DRV_MODULE_NAME, test); @@ -441,14 +526,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, base = pci_ioremap_bar(pdev, bar); if (!base) { dev_err(dev, "failed to read BAR%d\n", bar); - WARN_ON(bar == BAR_0); + WARN_ON(bar == test_reg_bar); } test->bar[bar] = base; } - test->base = test->bar[0]; + test->base = test->bar[test_reg_bar]; if (!test->base) { - dev_err(dev, "Cannot perform PCI test without BAR0\n"); + dev_err(dev, "Cannot perform PCI test without BAR%d\n", + test_reg_bar); goto err_iounmap; } diff --git a/drivers/pci/dwc/pci-dra7xx.c b/drivers/pci/dwc/pci-dra7xx.c index ced9319cf76a..1e2aaedbebf2 100644 --- a/drivers/pci/dwc/pci-dra7xx.c +++ b/drivers/pci/dwc/pci-dra7xx.c @@ -337,10 +337,23 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) return IRQ_HANDLED; } +static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) +{ + u32 reg; + + reg = PCI_BASE_ADDRESS_0 + (4 * bar); + dw_pcie_writel_dbi2(pci, reg, 0x0); + dw_pcie_writel_dbi(pci, reg, 0x0); +} + 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 = BAR_0; bar <= BAR_5; bar++) + dw_pcie_ep_reset_bar(pci, bar); dra7xx_pcie_enable_wrapper_interrupts(dra7xx); } diff --git a/drivers/pci/dwc/pcie-designware-ep.c b/drivers/pci/dwc/pcie-designware-ep.c index 398406393f37..b3205df38d52 100644 --- a/drivers/pci/dwc/pcie-designware-ep.c +++ b/drivers/pci/dwc/pcie-designware-ep.c @@ -283,7 +283,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) { int ret; void *addr; - enum pci_barno bar; struct pci_epc *epc; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct device *dev = pci->dev; @@ -312,9 +311,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) return -ENOMEM; ep->outbound_addr = addr; - for (bar = BAR_0; bar <= BAR_5; bar++) - dw_pcie_ep_reset_bar(pci, bar); - if (ep->ops->ep_init) ep->ops->ep_init(ep); @@ -328,7 +324,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; - ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size); + ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, + ep->page_size); if (ret < 0) { dev_err(dev, "Failed to initialize address space\n"); return ret; diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h index 0c5f874345f6..744876d8ef66 100644 --- a/drivers/pci/dwc/pcie-designware.h +++ b/drivers/pci/dwc/pcie-designware.h @@ -189,6 +189,7 @@ struct dw_pcie_ep { struct dw_pcie_ep_ops *ops; phys_addr_t phys_base; size_t addr_size; + size_t page_size; u8 bar_to_atu[6]; phys_addr_t *outbound_addr; unsigned long ib_window_map; diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 53fff8030337..4ddc6e8f9fe7 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -54,6 +54,8 @@ static struct workqueue_struct *kpcitest_workqueue; struct pci_epf_test { void *reg[6]; struct pci_epf *epf; + enum pci_barno test_reg_bar; + bool linkup_notifier; struct delayed_work cmd_handler; }; @@ -74,7 +76,12 @@ static struct pci_epf_header test_header = { .interrupt_pin = PCI_INTERRUPT_INTA, }; -static int bar_size[] = { 512, 1024, 16384, 131072, 1048576 }; +struct pci_epf_test_data { + enum pci_barno test_reg_bar; + bool linkup_notifier; +}; + +static int bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 }; static int pci_epf_test_copy(struct pci_epf_test *epf_test) { @@ -86,7 +93,8 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test) struct pci_epf *epf = epf_test->epf; struct device *dev = &epf->dev; struct pci_epc *epc = epf->epc; - struct pci_epf_test_reg *reg = epf_test->reg[0]; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size); if (!src_addr) { @@ -145,7 +153,8 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test) struct pci_epf *epf = epf_test->epf; struct device *dev = &epf->dev; struct pci_epc *epc = epf->epc; - struct pci_epf_test_reg *reg = epf_test->reg[0]; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); if (!src_addr) { @@ -195,7 +204,8 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test) struct pci_epf *epf = epf_test->epf; struct device *dev = &epf->dev; struct pci_epc *epc = epf->epc; - struct pci_epf_test_reg *reg = epf_test->reg[0]; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); if (!dst_addr) { @@ -247,7 +257,8 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test) u8 msi_count; struct pci_epf *epf = epf_test->epf; struct pci_epc *epc = epf->epc; - struct pci_epf_test_reg *reg = epf_test->reg[0]; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; reg->status |= STATUS_IRQ_RAISED; msi_count = pci_epc_get_msi(epc); @@ -263,22 +274,28 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) int ret; u8 irq; u8 msi_count; + u32 command; struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test, cmd_handler.work); struct pci_epf *epf = epf_test->epf; struct pci_epc *epc = epf->epc; - struct pci_epf_test_reg *reg = epf_test->reg[0]; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; - if (!reg->command) + command = reg->command; + if (!command) goto reset_handler; - if (reg->command & COMMAND_RAISE_LEGACY_IRQ) { + reg->command = 0; + reg->status = 0; + + if (command & COMMAND_RAISE_LEGACY_IRQ) { reg->status = STATUS_IRQ_RAISED; pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0); goto reset_handler; } - if (reg->command & COMMAND_WRITE) { + if (command & COMMAND_WRITE) { ret = pci_epf_test_write(epf_test); if (ret) reg->status |= STATUS_WRITE_FAIL; @@ -288,7 +305,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) goto reset_handler; } - if (reg->command & COMMAND_READ) { + if (command & COMMAND_READ) { ret = pci_epf_test_read(epf_test); if (!ret) reg->status |= STATUS_READ_SUCCESS; @@ -298,7 +315,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) goto reset_handler; } - if (reg->command & COMMAND_COPY) { + if (command & COMMAND_COPY) { ret = pci_epf_test_copy(epf_test); if (!ret) reg->status |= STATUS_COPY_SUCCESS; @@ -308,9 +325,9 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) goto reset_handler; } - if (reg->command & COMMAND_RAISE_MSI_IRQ) { + if (command & COMMAND_RAISE_MSI_IRQ) { msi_count = pci_epc_get_msi(epc); - irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; + irq = (command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; if (irq > msi_count || msi_count <= 0) goto reset_handler; reg->status = STATUS_IRQ_RAISED; @@ -319,8 +336,6 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) } reset_handler: - reg->command = 0; - queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler, msecs_to_jiffies(1)); } @@ -358,6 +373,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf) struct pci_epc *epc = epf->epc; struct device *dev = &epf->dev; struct pci_epf_test *epf_test = epf_get_drvdata(epf); + enum pci_barno test_reg_bar = epf_test->test_reg_bar; flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32; if (sizeof(dma_addr_t) == 0x8) @@ -370,7 +386,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf) if (ret) { pci_epf_free_space(epf, epf_test->reg[bar], bar); dev_err(dev, "failed to set BAR%d\n", bar); - if (bar == BAR_0) + if (bar == test_reg_bar) return ret; } } @@ -384,17 +400,20 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) struct device *dev = &epf->dev; void *base; int bar; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg), - BAR_0); + test_reg_bar); if (!base) { dev_err(dev, "failed to allocated register space\n"); return -ENOMEM; } - epf_test->reg[0] = base; + epf_test->reg[test_reg_bar] = base; - for (bar = BAR_1; bar <= BAR_5; bar++) { - base = pci_epf_alloc_space(epf, bar_size[bar - 1], bar); + for (bar = BAR_0; bar <= BAR_5; bar++) { + if (bar == test_reg_bar) + continue; + base = pci_epf_alloc_space(epf, bar_size[bar], bar); if (!base) dev_err(dev, "failed to allocate space for BAR%d\n", bar); @@ -407,6 +426,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) static int pci_epf_test_bind(struct pci_epf *epf) { int ret; + struct pci_epf_test *epf_test = epf_get_drvdata(epf); struct pci_epf_header *header = epf->header; struct pci_epc *epc = epf->epc; struct device *dev = &epf->dev; @@ -432,13 +452,34 @@ static int pci_epf_test_bind(struct pci_epf *epf) if (ret) return ret; + if (!epf_test->linkup_notifier) + queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work); + return 0; } +static const struct pci_epf_device_id pci_epf_test_ids[] = { + { + .name = "pci_epf_test", + }, + {}, +}; + static int pci_epf_test_probe(struct pci_epf *epf) { struct pci_epf_test *epf_test; struct device *dev = &epf->dev; + const struct pci_epf_device_id *match; + struct pci_epf_test_data *data; + enum pci_barno test_reg_bar = BAR_0; + bool linkup_notifier = true; + + match = pci_epf_match_device(pci_epf_test_ids, epf); + data = (struct pci_epf_test_data *)match->driver_data; + if (data) { + test_reg_bar = data->test_reg_bar; + linkup_notifier = data->linkup_notifier; + } epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL); if (!epf_test) @@ -446,6 +487,8 @@ static int pci_epf_test_probe(struct pci_epf *epf) epf->header = &test_header; epf_test->epf = epf; + epf_test->test_reg_bar = test_reg_bar; + epf_test->linkup_notifier = linkup_notifier; INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler); @@ -453,31 +496,15 @@ static int pci_epf_test_probe(struct pci_epf *epf) return 0; } -static int pci_epf_test_remove(struct pci_epf *epf) -{ - struct pci_epf_test *epf_test = epf_get_drvdata(epf); - - kfree(epf_test); - return 0; -} - static struct pci_epf_ops ops = { .unbind = pci_epf_test_unbind, .bind = pci_epf_test_bind, .linkup = pci_epf_test_linkup, }; -static const struct pci_epf_device_id pci_epf_test_ids[] = { - { - .name = "pci_epf_test", - }, - {}, -}; - static struct pci_epf_driver test_driver = { .driver.name = "pci_epf_test", .probe = pci_epf_test_probe, - .remove = pci_epf_test_remove, .id_table = pci_epf_test_ids, .ops = &ops, .owner = THIS_MODULE, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index caa7be10e473..42c2a1156325 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -21,6 +21,7 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/pci-epc.h> #include <linux/pci-epf.h> @@ -370,6 +371,7 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header); int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) { unsigned long flags; + struct device *dev = epc->dev.parent; if (epf->epc) return -EBUSY; @@ -381,8 +383,12 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) return -EINVAL; epf->epc = epc; - dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask); - epf->dev.dma_mask = epc->dev.dma_mask; + if (dev->of_node) { + of_dma_configure(&epf->dev, dev->of_node); + } else { + dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask); + epf->dev.dma_mask = epc->dev.dma_mask; + } spin_lock_irqsave(&epc->lock, flags); list_add_tail(&epf->list, &epc->pci_epf); @@ -500,6 +506,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask); epc->dev.class = pci_epc_class; epc->dev.dma_mask = dev->dma_mask; + epc->dev.parent = dev; epc->ops = ops; ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c index 3a94cc1caf22..83b7d5d3fc3e 100644 --- a/drivers/pci/endpoint/pci-epc-mem.c +++ b/drivers/pci/endpoint/pci-epc-mem.c @@ -24,21 +24,54 @@ #include <linux/pci-epc.h> /** - * pci_epc_mem_init() - initialize the pci_epc_mem structure + * pci_epc_mem_get_order() - determine the allocation order of a memory size + * @mem: address space of the endpoint controller + * @size: the size for which to get the order + * + * Reimplement get_order() for mem->page_size since the generic get_order + * always gets order with a constant PAGE_SIZE. + */ +static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) +{ + int order; + unsigned int page_shift = ilog2(mem->page_size); + + size--; + size >>= page_shift; +#if BITS_PER_LONG == 32 + order = fls(size); +#else + order = fls64(size); +#endif + return order; +} + +/** + * __pci_epc_mem_init() - initialize the pci_epc_mem structure * @epc: the EPC device that invoked pci_epc_mem_init * @phys_base: the physical address of the base * @size: the size of the address space + * @page_size: size of each page * * Invoke to initialize the pci_epc_mem structure used by the * endpoint functions to allocate mapped PCI address. */ -int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size) +int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size, + size_t page_size) { int ret; struct pci_epc_mem *mem; unsigned long *bitmap; - int pages = size >> PAGE_SHIFT; - int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); + unsigned int page_shift; + int pages; + int bitmap_size; + + if (page_size < PAGE_SIZE) + page_size = PAGE_SIZE; + + page_shift = ilog2(page_size); + pages = size >> page_shift; + bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) { @@ -54,6 +87,7 @@ int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size) mem->bitmap = bitmap; mem->phys_base = phys_base; + mem->page_size = page_size; mem->pages = pages; mem->size = size; @@ -67,7 +101,7 @@ err_mem: err: return ret; } -EXPORT_SYMBOL_GPL(pci_epc_mem_init); +EXPORT_SYMBOL_GPL(__pci_epc_mem_init); /** * pci_epc_mem_exit() - cleanup the pci_epc_mem structure @@ -101,13 +135,17 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, int pageno; void __iomem *virt_addr; struct pci_epc_mem *mem = epc->mem; - int order = get_order(size); + unsigned int page_shift = ilog2(mem->page_size); + int order; + + size = ALIGN(size, mem->page_size); + order = pci_epc_mem_get_order(mem, size); pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); if (pageno < 0) return NULL; - *phys_addr = mem->phys_base + (pageno << PAGE_SHIFT); + *phys_addr = mem->phys_base + (pageno << page_shift); virt_addr = ioremap(*phys_addr, size); if (!virt_addr) bitmap_release_region(mem->bitmap, pageno, order); @@ -129,11 +167,14 @@ void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, void __iomem *virt_addr, size_t size) { int pageno; - int order = get_order(size); struct pci_epc_mem *mem = epc->mem; + unsigned int page_shift = ilog2(mem->page_size); + int order; iounmap(virt_addr); - pageno = (phys_addr - mem->phys_base) >> PAGE_SHIFT; + pageno = (phys_addr - mem->phys_base) >> page_shift; + size = ALIGN(size, mem->page_size); + order = pci_epc_mem_get_order(mem, size); bitmap_release_region(mem->bitmap, pageno, order); } EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr); diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c index 6877d6a5bcc9..70eccc04ee7f 100644 --- a/drivers/pci/endpoint/pci-epf-core.c +++ b/drivers/pci/endpoint/pci-epf-core.c @@ -267,6 +267,22 @@ err_ret: } EXPORT_SYMBOL_GPL(pci_epf_create); +const struct pci_epf_device_id * +pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf) +{ + if (!id || !epf) + return NULL; + + while (*id->name) { + if (strcmp(epf->name, id->name) == 0) + return id; + id++; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(pci_epf_match_device); + static void pci_epf_dev_release(struct device *dev) { struct pci_epf *epf = to_pci_epf(dev); @@ -317,11 +333,12 @@ static int pci_epf_device_probe(struct device *dev) static int pci_epf_device_remove(struct device *dev) { - int ret; + int ret = 0; struct pci_epf *epf = to_pci_epf(dev); struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver); - ret = driver->remove(epf); + if (driver->remove) + ret = driver->remove(epf); epf->driver = NULL; return ret; diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index af5edbf3eea3..f7a04e1af112 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -62,11 +62,13 @@ struct pci_epc_ops { * @size: the size of the PCI address space * @bitmap: bitmap to manage the PCI address space * @pages: number of bits representing the address region + * @page_size: size of each page */ struct pci_epc_mem { phys_addr_t phys_base; size_t size; unsigned long *bitmap; + size_t page_size; int pages; }; @@ -98,6 +100,9 @@ struct pci_epc { #define devm_pci_epc_create(dev, ops) \ __devm_pci_epc_create((dev), (ops), THIS_MODULE) +#define pci_epc_mem_init(epc, phys_addr, size) \ + __pci_epc_mem_init((epc), (phys_addr), (size), PAGE_SIZE) + static inline void epc_set_drvdata(struct pci_epc *epc, void *data) { dev_set_drvdata(&epc->dev, data); @@ -135,7 +140,8 @@ void pci_epc_stop(struct pci_epc *epc); struct pci_epc *pci_epc_get(const char *epc_name); void pci_epc_put(struct pci_epc *epc); -int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size); +int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size, + size_t page_size); void pci_epc_mem_exit(struct pci_epc *epc); void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, phys_addr_t *phys_addr, size_t size); diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h index bc8750688348..60d551a9a1ba 100644 --- a/include/linux/pci-epf.h +++ b/include/linux/pci-epf.h @@ -142,6 +142,8 @@ static inline void *epf_get_drvdata(struct pci_epf *epf) return dev_get_drvdata(&epf->dev); } +const struct pci_epf_device_id * +pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf); struct pci_epf *pci_epf_create(const char *name); void pci_epf_destroy(struct pci_epf *epf); int __pci_epf_register_driver(struct pci_epf_driver *driver, diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index ad54a58d7dda..9074b477bff0 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c @@ -173,6 +173,7 @@ usage: "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" "\t-b <bar num> BAR test (bar number between 0..5)\n" "\t-m <msi num> MSI test (msi number between 1..32)\n" + "\t-l Legacy IRQ test\n" "\t-r Read buffer test\n" "\t-w Write buffer test\n" "\t-c Copy buffer test\n" |