diff options
Diffstat (limited to 'drivers/pci/endpoint/functions/pci-epf-test.c')
-rw-r--r-- | drivers/pci/endpoint/functions/pci-epf-test.c | 165 |
1 files changed, 109 insertions, 56 deletions
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index ef6677f34116..50eb4106369f 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -44,6 +44,11 @@ #define TIMER_RESOLUTION 1 +#define CAP_UNALIGNED_ACCESS BIT(0) +#define CAP_MSI BIT(1) +#define CAP_MSIX BIT(2) +#define CAP_INTX BIT(3) + static struct workqueue_struct *kpcitest_workqueue; struct pci_epf_test { @@ -64,16 +69,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; + __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 = { @@ -251,7 +257,7 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test) fail_back_rx: dma_release_channel(epf_test->dma_chan_rx); - epf_test->dma_chan_tx = NULL; + epf_test->dma_chan_rx = NULL; fail_back_tx: dma_cap_zero(mask); @@ -321,15 +327,19 @@ 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) { - if (epf_test->dma_private) { - dev_err(dev, "Cannot transfer data using DMA\n"); + 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; goto set_status; } @@ -347,7 +357,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; } @@ -355,7 +365,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; @@ -364,7 +374,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); @@ -388,8 +398,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) { @@ -402,9 +412,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, @@ -420,9 +431,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) { @@ -436,12 +452,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)) { @@ -478,11 +494,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: @@ -494,9 +510,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, @@ -511,9 +528,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) { @@ -521,7 +542,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) { @@ -529,12 +550,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)) { @@ -573,8 +594,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 @@ -591,9 +612,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, @@ -602,39 +624,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) { - dev_err(dev, "Invalid MSIX IRQ number %d / %d\n", - reg->irq_number, count); + if (irq_number > count || count <= 0) { + dev_err(dev, "Invalid MSI-X IRQ number %d / %d\n", + 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"); @@ -651,21 +676,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; } @@ -715,6 +741,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; @@ -739,6 +766,29 @@ 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; + + if (epf_test->epc_features->msi_capable) + caps |= CAP_MSI; + + if (epf_test->epc_features->msix_capable) + caps |= CAP_MSIX; + + if (epf_test->epc_features->intx_capable) + caps |= CAP_INTX; + + 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 +813,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; @@ -890,6 +942,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; } } |