1 /** 2 * Host side test driver to test endpoint functionality 3 * 4 * Copyright (C) 2017 Texas Instruments 5 * Author: Kishon Vijay Abraham I <kishon@ti.com> 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 of 9 * the License as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <linux/crc32.h> 21 #include <linux/delay.h> 22 #include <linux/fs.h> 23 #include <linux/io.h> 24 #include <linux/interrupt.h> 25 #include <linux/irq.h> 26 #include <linux/miscdevice.h> 27 #include <linux/module.h> 28 #include <linux/mutex.h> 29 #include <linux/random.h> 30 #include <linux/slab.h> 31 #include <linux/pci.h> 32 #include <linux/pci_ids.h> 33 34 #include <linux/pci_regs.h> 35 36 #include <uapi/linux/pcitest.h> 37 38 #define DRV_MODULE_NAME "pci-endpoint-test" 39 40 #define PCI_ENDPOINT_TEST_MAGIC 0x0 41 42 #define PCI_ENDPOINT_TEST_COMMAND 0x4 43 #define COMMAND_RAISE_LEGACY_IRQ BIT(0) 44 #define COMMAND_RAISE_MSI_IRQ BIT(1) 45 #define MSI_NUMBER_SHIFT 2 46 /* 6 bits for MSI number */ 47 #define COMMAND_READ BIT(8) 48 #define COMMAND_WRITE BIT(9) 49 #define COMMAND_COPY BIT(10) 50 51 #define PCI_ENDPOINT_TEST_STATUS 0x8 52 #define STATUS_READ_SUCCESS BIT(0) 53 #define STATUS_READ_FAIL BIT(1) 54 #define STATUS_WRITE_SUCCESS BIT(2) 55 #define STATUS_WRITE_FAIL BIT(3) 56 #define STATUS_COPY_SUCCESS BIT(4) 57 #define STATUS_COPY_FAIL BIT(5) 58 #define STATUS_IRQ_RAISED BIT(6) 59 #define STATUS_SRC_ADDR_INVALID BIT(7) 60 #define STATUS_DST_ADDR_INVALID BIT(8) 61 62 #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0xc 63 #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 64 65 #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14 66 #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18 67 68 #define PCI_ENDPOINT_TEST_SIZE 0x1c 69 #define PCI_ENDPOINT_TEST_CHECKSUM 0x20 70 71 static DEFINE_IDA(pci_endpoint_test_ida); 72 73 #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ 74 miscdev) 75 enum pci_barno { 76 BAR_0, 77 BAR_1, 78 BAR_2, 79 BAR_3, 80 BAR_4, 81 BAR_5, 82 }; 83 84 struct pci_endpoint_test { 85 struct pci_dev *pdev; 86 void __iomem *base; 87 void __iomem *bar[6]; 88 struct completion irq_raised; 89 int last_irq; 90 /* mutex to protect the ioctls */ 91 struct mutex mutex; 92 struct miscdevice miscdev; 93 }; 94 95 static int bar_size[] = { 4, 512, 1024, 16384, 131072, 1048576 }; 96 97 static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, 98 u32 offset) 99 { 100 return readl(test->base + offset); 101 } 102 103 static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test, 104 u32 offset, u32 value) 105 { 106 writel(value, test->base + offset); 107 } 108 109 static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test, 110 int bar, int offset) 111 { 112 return readl(test->bar[bar] + offset); 113 } 114 115 static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test, 116 int bar, u32 offset, u32 value) 117 { 118 writel(value, test->bar[bar] + offset); 119 } 120 121 static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id) 122 { 123 struct pci_endpoint_test *test = dev_id; 124 u32 reg; 125 126 reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); 127 if (reg & STATUS_IRQ_RAISED) { 128 test->last_irq = irq; 129 complete(&test->irq_raised); 130 reg &= ~STATUS_IRQ_RAISED; 131 } 132 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 133 reg); 134 135 return IRQ_HANDLED; 136 } 137 138 static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, 139 enum pci_barno barno) 140 { 141 int j; 142 u32 val; 143 int size; 144 145 if (!test->bar[barno]) 146 return false; 147 148 size = bar_size[barno]; 149 150 for (j = 0; j < size; j += 4) 151 pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); 152 153 for (j = 0; j < size; j += 4) { 154 val = pci_endpoint_test_bar_readl(test, barno, j); 155 if (val != 0xA0A0A0A0) 156 return false; 157 } 158 159 return true; 160 } 161 162 static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test) 163 { 164 u32 val; 165 166 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, 167 COMMAND_RAISE_LEGACY_IRQ); 168 val = wait_for_completion_timeout(&test->irq_raised, 169 msecs_to_jiffies(1000)); 170 if (!val) 171 return false; 172 173 return true; 174 } 175 176 static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, 177 u8 msi_num) 178 { 179 u32 val; 180 struct pci_dev *pdev = test->pdev; 181 182 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, 183 msi_num << MSI_NUMBER_SHIFT | 184 COMMAND_RAISE_MSI_IRQ); 185 val = wait_for_completion_timeout(&test->irq_raised, 186 msecs_to_jiffies(1000)); 187 if (!val) 188 return false; 189 190 if (test->last_irq - pdev->irq == msi_num - 1) 191 return true; 192 193 return false; 194 } 195 196 static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) 197 { 198 bool ret = false; 199 void *src_addr; 200 void *dst_addr; 201 dma_addr_t src_phys_addr; 202 dma_addr_t dst_phys_addr; 203 struct pci_dev *pdev = test->pdev; 204 struct device *dev = &pdev->dev; 205 u32 src_crc32; 206 u32 dst_crc32; 207 208 src_addr = dma_alloc_coherent(dev, size, &src_phys_addr, GFP_KERNEL); 209 if (!src_addr) { 210 dev_err(dev, "failed to allocate source buffer\n"); 211 ret = false; 212 goto err; 213 } 214 215 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, 216 lower_32_bits(src_phys_addr)); 217 218 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR, 219 upper_32_bits(src_phys_addr)); 220 221 get_random_bytes(src_addr, size); 222 src_crc32 = crc32_le(~0, src_addr, size); 223 224 dst_addr = dma_alloc_coherent(dev, size, &dst_phys_addr, GFP_KERNEL); 225 if (!dst_addr) { 226 dev_err(dev, "failed to allocate destination address\n"); 227 ret = false; 228 goto err_src_addr; 229 } 230 231 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, 232 lower_32_bits(dst_phys_addr)); 233 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, 234 upper_32_bits(dst_phys_addr)); 235 236 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, 237 size); 238 239 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, 240 1 << MSI_NUMBER_SHIFT | COMMAND_COPY); 241 242 wait_for_completion(&test->irq_raised); 243 244 dst_crc32 = crc32_le(~0, dst_addr, size); 245 if (dst_crc32 == src_crc32) 246 ret = true; 247 248 dma_free_coherent(dev, size, dst_addr, dst_phys_addr); 249 250 err_src_addr: 251 dma_free_coherent(dev, size, src_addr, src_phys_addr); 252 253 err: 254 return ret; 255 } 256 257 static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) 258 { 259 bool ret = false; 260 u32 reg; 261 void *addr; 262 dma_addr_t phys_addr; 263 struct pci_dev *pdev = test->pdev; 264 struct device *dev = &pdev->dev; 265 u32 crc32; 266 267 addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); 268 if (!addr) { 269 dev_err(dev, "failed to allocate address\n"); 270 ret = false; 271 goto err; 272 } 273 274 get_random_bytes(addr, size); 275 276 crc32 = crc32_le(~0, addr, size); 277 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM, 278 crc32); 279 280 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, 281 lower_32_bits(phys_addr)); 282 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR, 283 upper_32_bits(phys_addr)); 284 285 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); 286 287 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, 288 1 << MSI_NUMBER_SHIFT | COMMAND_READ); 289 290 wait_for_completion(&test->irq_raised); 291 292 reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); 293 if (reg & STATUS_READ_SUCCESS) 294 ret = true; 295 296 dma_free_coherent(dev, size, addr, phys_addr); 297 298 err: 299 return ret; 300 } 301 302 static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) 303 { 304 bool ret = false; 305 void *addr; 306 dma_addr_t phys_addr; 307 struct pci_dev *pdev = test->pdev; 308 struct device *dev = &pdev->dev; 309 u32 crc32; 310 311 addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); 312 if (!addr) { 313 dev_err(dev, "failed to allocate destination address\n"); 314 ret = false; 315 goto err; 316 } 317 318 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, 319 lower_32_bits(phys_addr)); 320 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, 321 upper_32_bits(phys_addr)); 322 323 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); 324 325 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, 326 1 << MSI_NUMBER_SHIFT | COMMAND_WRITE); 327 328 wait_for_completion(&test->irq_raised); 329 330 crc32 = crc32_le(~0, addr, size); 331 if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) 332 ret = true; 333 334 dma_free_coherent(dev, size, addr, phys_addr); 335 err: 336 return ret; 337 } 338 339 static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, 340 unsigned long arg) 341 { 342 int ret = -EINVAL; 343 enum pci_barno bar; 344 struct pci_endpoint_test *test = to_endpoint_test(file->private_data); 345 346 mutex_lock(&test->mutex); 347 switch (cmd) { 348 case PCITEST_BAR: 349 bar = arg; 350 if (bar < 0 || bar > 5) 351 goto ret; 352 ret = pci_endpoint_test_bar(test, bar); 353 break; 354 case PCITEST_LEGACY_IRQ: 355 ret = pci_endpoint_test_legacy_irq(test); 356 break; 357 case PCITEST_MSI: 358 ret = pci_endpoint_test_msi_irq(test, arg); 359 break; 360 case PCITEST_WRITE: 361 ret = pci_endpoint_test_write(test, arg); 362 break; 363 case PCITEST_READ: 364 ret = pci_endpoint_test_read(test, arg); 365 break; 366 case PCITEST_COPY: 367 ret = pci_endpoint_test_copy(test, arg); 368 break; 369 } 370 371 ret: 372 mutex_unlock(&test->mutex); 373 return ret; 374 } 375 376 static const struct file_operations pci_endpoint_test_fops = { 377 .owner = THIS_MODULE, 378 .unlocked_ioctl = pci_endpoint_test_ioctl, 379 }; 380 381 static int pci_endpoint_test_probe(struct pci_dev *pdev, 382 const struct pci_device_id *ent) 383 { 384 int i; 385 int err; 386 int irq; 387 int id; 388 char name[20]; 389 enum pci_barno bar; 390 void __iomem *base; 391 struct device *dev = &pdev->dev; 392 struct pci_endpoint_test *test; 393 struct miscdevice *misc_device; 394 395 if (pci_is_bridge(pdev)) 396 return -ENODEV; 397 398 test = devm_kzalloc(dev, sizeof(*test), GFP_KERNEL); 399 if (!test) 400 return -ENOMEM; 401 402 test->pdev = pdev; 403 init_completion(&test->irq_raised); 404 mutex_init(&test->mutex); 405 406 err = pci_enable_device(pdev); 407 if (err) { 408 dev_err(dev, "Cannot enable PCI device\n"); 409 return err; 410 } 411 412 err = pci_request_regions(pdev, DRV_MODULE_NAME); 413 if (err) { 414 dev_err(dev, "Cannot obtain PCI resources\n"); 415 goto err_disable_pdev; 416 } 417 418 pci_set_master(pdev); 419 420 irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); 421 if (irq < 0) 422 dev_err(dev, "failed to get MSI interrupts\n"); 423 424 err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, 425 IRQF_SHARED, DRV_MODULE_NAME, test); 426 if (err) { 427 dev_err(dev, "failed to request IRQ %d\n", pdev->irq); 428 goto err_disable_msi; 429 } 430 431 for (i = 1; i < irq; i++) { 432 err = devm_request_irq(dev, pdev->irq + i, 433 pci_endpoint_test_irqhandler, 434 IRQF_SHARED, DRV_MODULE_NAME, test); 435 if (err) 436 dev_err(dev, "failed to request IRQ %d for MSI %d\n", 437 pdev->irq + i, i + 1); 438 } 439 440 for (bar = BAR_0; bar <= BAR_5; bar++) { 441 base = pci_ioremap_bar(pdev, bar); 442 if (!base) { 443 dev_err(dev, "failed to read BAR%d\n", bar); 444 WARN_ON(bar == BAR_0); 445 } 446 test->bar[bar] = base; 447 } 448 449 test->base = test->bar[0]; 450 if (!test->base) { 451 dev_err(dev, "Cannot perform PCI test without BAR0\n"); 452 goto err_iounmap; 453 } 454 455 pci_set_drvdata(pdev, test); 456 457 id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL); 458 if (id < 0) { 459 dev_err(dev, "unable to get id\n"); 460 goto err_iounmap; 461 } 462 463 snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id); 464 misc_device = &test->miscdev; 465 misc_device->minor = MISC_DYNAMIC_MINOR; 466 misc_device->name = name; 467 misc_device->fops = &pci_endpoint_test_fops, 468 469 err = misc_register(misc_device); 470 if (err) { 471 dev_err(dev, "failed to register device\n"); 472 goto err_ida_remove; 473 } 474 475 return 0; 476 477 err_ida_remove: 478 ida_simple_remove(&pci_endpoint_test_ida, id); 479 480 err_iounmap: 481 for (bar = BAR_0; bar <= BAR_5; bar++) { 482 if (test->bar[bar]) 483 pci_iounmap(pdev, test->bar[bar]); 484 } 485 486 err_disable_msi: 487 pci_disable_msi(pdev); 488 pci_release_regions(pdev); 489 490 err_disable_pdev: 491 pci_disable_device(pdev); 492 493 return err; 494 } 495 496 static void pci_endpoint_test_remove(struct pci_dev *pdev) 497 { 498 int id; 499 enum pci_barno bar; 500 struct pci_endpoint_test *test = pci_get_drvdata(pdev); 501 struct miscdevice *misc_device = &test->miscdev; 502 503 if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1) 504 return; 505 506 misc_deregister(&test->miscdev); 507 ida_simple_remove(&pci_endpoint_test_ida, id); 508 for (bar = BAR_0; bar <= BAR_5; bar++) { 509 if (test->bar[bar]) 510 pci_iounmap(pdev, test->bar[bar]); 511 } 512 pci_disable_msi(pdev); 513 pci_release_regions(pdev); 514 pci_disable_device(pdev); 515 } 516 517 static const struct pci_device_id pci_endpoint_test_tbl[] = { 518 { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) }, 519 { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) }, 520 { } 521 }; 522 MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); 523 524 static struct pci_driver pci_endpoint_test_driver = { 525 .name = DRV_MODULE_NAME, 526 .id_table = pci_endpoint_test_tbl, 527 .probe = pci_endpoint_test_probe, 528 .remove = pci_endpoint_test_remove, 529 }; 530 module_pci_driver(pci_endpoint_test_driver); 531 532 MODULE_DESCRIPTION("PCI ENDPOINT TEST HOST DRIVER"); 533 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 534 MODULE_LICENSE("GPL v2"); 535