linux/drivers/misc/pci_endpoint_test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/**
   3 * Host side test driver to test endpoint functionality
   4 *
   5 * Copyright (C) 2017 Texas Instruments
   6 * Author: Kishon Vijay Abraham I <kishon@ti.com>
   7 */
   8
   9#include <linux/crc32.h>
  10#include <linux/delay.h>
  11#include <linux/fs.h>
  12#include <linux/io.h>
  13#include <linux/interrupt.h>
  14#include <linux/irq.h>
  15#include <linux/miscdevice.h>
  16#include <linux/module.h>
  17#include <linux/mutex.h>
  18#include <linux/random.h>
  19#include <linux/slab.h>
  20#include <linux/pci.h>
  21#include <linux/pci_ids.h>
  22
  23#include <linux/pci_regs.h>
  24
  25#include <uapi/linux/pcitest.h>
  26
  27#define DRV_MODULE_NAME                         "pci-endpoint-test"
  28
  29#define IRQ_TYPE_UNDEFINED                      -1
  30#define IRQ_TYPE_LEGACY                         0
  31#define IRQ_TYPE_MSI                            1
  32#define IRQ_TYPE_MSIX                           2
  33
  34#define PCI_ENDPOINT_TEST_MAGIC                 0x0
  35
  36#define PCI_ENDPOINT_TEST_COMMAND               0x4
  37#define COMMAND_RAISE_LEGACY_IRQ                BIT(0)
  38#define COMMAND_RAISE_MSI_IRQ                   BIT(1)
  39#define COMMAND_RAISE_MSIX_IRQ                  BIT(2)
  40#define COMMAND_READ                            BIT(3)
  41#define COMMAND_WRITE                           BIT(4)
  42#define COMMAND_COPY                            BIT(5)
  43
  44#define PCI_ENDPOINT_TEST_STATUS                0x8
  45#define STATUS_READ_SUCCESS                     BIT(0)
  46#define STATUS_READ_FAIL                        BIT(1)
  47#define STATUS_WRITE_SUCCESS                    BIT(2)
  48#define STATUS_WRITE_FAIL                       BIT(3)
  49#define STATUS_COPY_SUCCESS                     BIT(4)
  50#define STATUS_COPY_FAIL                        BIT(5)
  51#define STATUS_IRQ_RAISED                       BIT(6)
  52#define STATUS_SRC_ADDR_INVALID                 BIT(7)
  53#define STATUS_DST_ADDR_INVALID                 BIT(8)
  54
  55#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR        0x0c
  56#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR        0x10
  57
  58#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR        0x14
  59#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR        0x18
  60
  61#define PCI_ENDPOINT_TEST_SIZE                  0x1c
  62#define PCI_ENDPOINT_TEST_CHECKSUM              0x20
  63
  64#define PCI_ENDPOINT_TEST_IRQ_TYPE              0x24
  65#define PCI_ENDPOINT_TEST_IRQ_NUMBER            0x28
  66
  67#define PCI_DEVICE_ID_TI_AM654                  0xb00c
  68
  69#define is_am654_pci_dev(pdev)          \
  70                ((pdev)->device == PCI_DEVICE_ID_TI_AM654)
  71
  72static DEFINE_IDA(pci_endpoint_test_ida);
  73
  74#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
  75                                            miscdev)
  76
  77static bool no_msi;
  78module_param(no_msi, bool, 0444);
  79MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
  80
  81static int irq_type = IRQ_TYPE_MSI;
  82module_param(irq_type, int, 0444);
  83MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)");
  84
  85enum pci_barno {
  86        BAR_0,
  87        BAR_1,
  88        BAR_2,
  89        BAR_3,
  90        BAR_4,
  91        BAR_5,
  92};
  93
  94struct pci_endpoint_test {
  95        struct pci_dev  *pdev;
  96        void __iomem    *base;
  97        void __iomem    *bar[6];
  98        struct completion irq_raised;
  99        int             last_irq;
 100        int             num_irqs;
 101        /* mutex to protect the ioctls */
 102        struct mutex    mutex;
 103        struct miscdevice miscdev;
 104        enum pci_barno test_reg_bar;
 105        size_t alignment;
 106};
 107
 108struct pci_endpoint_test_data {
 109        enum pci_barno test_reg_bar;
 110        size_t alignment;
 111        int irq_type;
 112};
 113
 114static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
 115                                          u32 offset)
 116{
 117        return readl(test->base + offset);
 118}
 119
 120static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,
 121                                            u32 offset, u32 value)
 122{
 123        writel(value, test->base + offset);
 124}
 125
 126static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test,
 127                                              int bar, int offset)
 128{
 129        return readl(test->bar[bar] + offset);
 130}
 131
 132static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test,
 133                                                int bar, u32 offset, u32 value)
 134{
 135        writel(value, test->bar[bar] + offset);
 136}
 137
 138static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
 139{
 140        struct pci_endpoint_test *test = dev_id;
 141        u32 reg;
 142
 143        reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
 144        if (reg & STATUS_IRQ_RAISED) {
 145                test->last_irq = irq;
 146                complete(&test->irq_raised);
 147                reg &= ~STATUS_IRQ_RAISED;
 148        }
 149        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS,
 150                                 reg);
 151
 152        return IRQ_HANDLED;
 153}
 154
 155static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
 156{
 157        struct pci_dev *pdev = test->pdev;
 158
 159        pci_free_irq_vectors(pdev);
 160}
 161
 162static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
 163                                                int type)
 164{
 165        int irq = -1;
 166        struct pci_dev *pdev = test->pdev;
 167        struct device *dev = &pdev->dev;
 168        bool res = true;
 169
 170        switch (type) {
 171        case IRQ_TYPE_LEGACY:
 172                irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
 173                if (irq < 0)
 174                        dev_err(dev, "Failed to get Legacy interrupt\n");
 175                break;
 176        case IRQ_TYPE_MSI:
 177                irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
 178                if (irq < 0)
 179                        dev_err(dev, "Failed to get MSI interrupts\n");
 180                break;
 181        case IRQ_TYPE_MSIX:
 182                irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
 183                if (irq < 0)
 184                        dev_err(dev, "Failed to get MSI-X interrupts\n");
 185                break;
 186        default:
 187                dev_err(dev, "Invalid IRQ type selected\n");
 188        }
 189
 190        if (irq < 0) {
 191                irq = 0;
 192                res = false;
 193        }
 194        test->num_irqs = irq;
 195
 196        return res;
 197}
 198
 199static void pci_endpoint_test_release_irq(struct pci_endpoint_test *test)
 200{
 201        int i;
 202        struct pci_dev *pdev = test->pdev;
 203        struct device *dev = &pdev->dev;
 204
 205        for (i = 0; i < test->num_irqs; i++)
 206                devm_free_irq(dev, pci_irq_vector(pdev, i), test);
 207
 208        test->num_irqs = 0;
 209}
 210
 211static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
 212{
 213        int i;
 214        int err;
 215        struct pci_dev *pdev = test->pdev;
 216        struct device *dev = &pdev->dev;
 217
 218        for (i = 0; i < test->num_irqs; i++) {
 219                err = devm_request_irq(dev, pci_irq_vector(pdev, i),
 220                                       pci_endpoint_test_irqhandler,
 221                                       IRQF_SHARED, DRV_MODULE_NAME, test);
 222                if (err)
 223                        goto fail;
 224        }
 225
 226        return true;
 227
 228fail:
 229        switch (irq_type) {
 230        case IRQ_TYPE_LEGACY:
 231                dev_err(dev, "Failed to request IRQ %d for Legacy\n",
 232                        pci_irq_vector(pdev, i));
 233                break;
 234        case IRQ_TYPE_MSI:
 235                dev_err(dev, "Failed to request IRQ %d for MSI %d\n",
 236                        pci_irq_vector(pdev, i),
 237                        i + 1);
 238                break;
 239        case IRQ_TYPE_MSIX:
 240                dev_err(dev, "Failed to request IRQ %d for MSI-X %d\n",
 241                        pci_irq_vector(pdev, i),
 242                        i + 1);
 243                break;
 244        }
 245
 246        return false;
 247}
 248
 249static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
 250                                  enum pci_barno barno)
 251{
 252        int j;
 253        u32 val;
 254        int size;
 255        struct pci_dev *pdev = test->pdev;
 256
 257        if (!test->bar[barno])
 258                return false;
 259
 260        size = pci_resource_len(pdev, barno);
 261
 262        if (barno == test->test_reg_bar)
 263                size = 0x4;
 264
 265        for (j = 0; j < size; j += 4)
 266                pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0);
 267
 268        for (j = 0; j < size; j += 4) {
 269                val = pci_endpoint_test_bar_readl(test, barno, j);
 270                if (val != 0xA0A0A0A0)
 271                        return false;
 272        }
 273
 274        return true;
 275}
 276
 277static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
 278{
 279        u32 val;
 280
 281        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
 282                                 IRQ_TYPE_LEGACY);
 283        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
 284        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
 285                                 COMMAND_RAISE_LEGACY_IRQ);
 286        val = wait_for_completion_timeout(&test->irq_raised,
 287                                          msecs_to_jiffies(1000));
 288        if (!val)
 289                return false;
 290
 291        return true;
 292}
 293
 294static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
 295                                       u16 msi_num, bool msix)
 296{
 297        u32 val;
 298        struct pci_dev *pdev = test->pdev;
 299
 300        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
 301                                 msix == false ? IRQ_TYPE_MSI :
 302                                 IRQ_TYPE_MSIX);
 303        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
 304        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
 305                                 msix == false ? COMMAND_RAISE_MSI_IRQ :
 306                                 COMMAND_RAISE_MSIX_IRQ);
 307        val = wait_for_completion_timeout(&test->irq_raised,
 308                                          msecs_to_jiffies(1000));
 309        if (!val)
 310                return false;
 311
 312        if (pci_irq_vector(pdev, msi_num - 1) == test->last_irq)
 313                return true;
 314
 315        return false;
 316}
 317
 318static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
 319{
 320        bool ret = false;
 321        void *src_addr;
 322        void *dst_addr;
 323        dma_addr_t src_phys_addr;
 324        dma_addr_t dst_phys_addr;
 325        struct pci_dev *pdev = test->pdev;
 326        struct device *dev = &pdev->dev;
 327        void *orig_src_addr;
 328        dma_addr_t orig_src_phys_addr;
 329        void *orig_dst_addr;
 330        dma_addr_t orig_dst_phys_addr;
 331        size_t offset;
 332        size_t alignment = test->alignment;
 333        u32 src_crc32;
 334        u32 dst_crc32;
 335
 336        if (size > SIZE_MAX - alignment)
 337                goto err;
 338
 339        if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
 340                dev_err(dev, "Invalid IRQ type option\n");
 341                goto err;
 342        }
 343
 344        orig_src_addr = dma_alloc_coherent(dev, size + alignment,
 345                                           &orig_src_phys_addr, GFP_KERNEL);
 346        if (!orig_src_addr) {
 347                dev_err(dev, "Failed to allocate source buffer\n");
 348                ret = false;
 349                goto err;
 350        }
 351
 352        if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) {
 353                src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment);
 354                offset = src_phys_addr - orig_src_phys_addr;
 355                src_addr = orig_src_addr + offset;
 356        } else {
 357                src_phys_addr = orig_src_phys_addr;
 358                src_addr = orig_src_addr;
 359        }
 360
 361        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
 362                                 lower_32_bits(src_phys_addr));
 363
 364        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
 365                                 upper_32_bits(src_phys_addr));
 366
 367        get_random_bytes(src_addr, size);
 368        src_crc32 = crc32_le(~0, src_addr, size);
 369
 370        orig_dst_addr = dma_alloc_coherent(dev, size + alignment,
 371                                           &orig_dst_phys_addr, GFP_KERNEL);
 372        if (!orig_dst_addr) {
 373                dev_err(dev, "Failed to allocate destination address\n");
 374                ret = false;
 375                goto err_orig_src_addr;
 376        }
 377
 378        if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) {
 379                dst_phys_addr = PTR_ALIGN(orig_dst_phys_addr, alignment);
 380                offset = dst_phys_addr - orig_dst_phys_addr;
 381                dst_addr = orig_dst_addr + offset;
 382        } else {
 383                dst_phys_addr = orig_dst_phys_addr;
 384                dst_addr = orig_dst_addr;
 385        }
 386
 387        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
 388                                 lower_32_bits(dst_phys_addr));
 389        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
 390                                 upper_32_bits(dst_phys_addr));
 391
 392        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
 393                                 size);
 394
 395        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
 396        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
 397        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
 398                                 COMMAND_COPY);
 399
 400        wait_for_completion(&test->irq_raised);
 401
 402        dst_crc32 = crc32_le(~0, dst_addr, size);
 403        if (dst_crc32 == src_crc32)
 404                ret = true;
 405
 406        dma_free_coherent(dev, size + alignment, orig_dst_addr,
 407                          orig_dst_phys_addr);
 408
 409err_orig_src_addr:
 410        dma_free_coherent(dev, size + alignment, orig_src_addr,
 411                          orig_src_phys_addr);
 412
 413err:
 414        return ret;
 415}
 416
 417static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
 418{
 419        bool ret = false;
 420        u32 reg;
 421        void *addr;
 422        dma_addr_t phys_addr;
 423        struct pci_dev *pdev = test->pdev;
 424        struct device *dev = &pdev->dev;
 425        void *orig_addr;
 426        dma_addr_t orig_phys_addr;
 427        size_t offset;
 428        size_t alignment = test->alignment;
 429        u32 crc32;
 430
 431        if (size > SIZE_MAX - alignment)
 432                goto err;
 433
 434        if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
 435                dev_err(dev, "Invalid IRQ type option\n");
 436                goto err;
 437        }
 438
 439        orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
 440                                       GFP_KERNEL);
 441        if (!orig_addr) {
 442                dev_err(dev, "Failed to allocate address\n");
 443                ret = false;
 444                goto err;
 445        }
 446
 447        if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
 448                phys_addr =  PTR_ALIGN(orig_phys_addr, alignment);
 449                offset = phys_addr - orig_phys_addr;
 450                addr = orig_addr + offset;
 451        } else {
 452                phys_addr = orig_phys_addr;
 453                addr = orig_addr;
 454        }
 455
 456        get_random_bytes(addr, size);
 457
 458        crc32 = crc32_le(~0, addr, size);
 459        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
 460                                 crc32);
 461
 462        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
 463                                 lower_32_bits(phys_addr));
 464        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
 465                                 upper_32_bits(phys_addr));
 466
 467        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
 468
 469        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
 470        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
 471        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
 472                                 COMMAND_READ);
 473
 474        wait_for_completion(&test->irq_raised);
 475
 476        reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
 477        if (reg & STATUS_READ_SUCCESS)
 478                ret = true;
 479
 480        dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
 481
 482err:
 483        return ret;
 484}
 485
 486static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
 487{
 488        bool ret = false;
 489        void *addr;
 490        dma_addr_t phys_addr;
 491        struct pci_dev *pdev = test->pdev;
 492        struct device *dev = &pdev->dev;
 493        void *orig_addr;
 494        dma_addr_t orig_phys_addr;
 495        size_t offset;
 496        size_t alignment = test->alignment;
 497        u32 crc32;
 498
 499        if (size > SIZE_MAX - alignment)
 500                goto err;
 501
 502        if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
 503                dev_err(dev, "Invalid IRQ type option\n");
 504                goto err;
 505        }
 506
 507        orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
 508                                       GFP_KERNEL);
 509        if (!orig_addr) {
 510                dev_err(dev, "Failed to allocate destination address\n");
 511                ret = false;
 512                goto err;
 513        }
 514
 515        if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
 516                phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
 517                offset = phys_addr - orig_phys_addr;
 518                addr = orig_addr + offset;
 519        } else {
 520                phys_addr = orig_phys_addr;
 521                addr = orig_addr;
 522        }
 523
 524        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
 525                                 lower_32_bits(phys_addr));
 526        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
 527                                 upper_32_bits(phys_addr));
 528
 529        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
 530
 531        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
 532        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
 533        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
 534                                 COMMAND_WRITE);
 535
 536        wait_for_completion(&test->irq_raised);
 537
 538        crc32 = crc32_le(~0, addr, size);
 539        if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
 540                ret = true;
 541
 542        dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
 543err:
 544        return ret;
 545}
 546
 547static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
 548                                      int req_irq_type)
 549{
 550        struct pci_dev *pdev = test->pdev;
 551        struct device *dev = &pdev->dev;
 552
 553        if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) {
 554                dev_err(dev, "Invalid IRQ type option\n");
 555                return false;
 556        }
 557
 558        if (irq_type == req_irq_type)
 559                return true;
 560
 561        pci_endpoint_test_release_irq(test);
 562        pci_endpoint_test_free_irq_vectors(test);
 563
 564        if (!pci_endpoint_test_alloc_irq_vectors(test, req_irq_type))
 565                goto err;
 566
 567        if (!pci_endpoint_test_request_irq(test))
 568                goto err;
 569
 570        irq_type = req_irq_type;
 571        return true;
 572
 573err:
 574        pci_endpoint_test_free_irq_vectors(test);
 575        irq_type = IRQ_TYPE_UNDEFINED;
 576        return false;
 577}
 578
 579static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
 580                                    unsigned long arg)
 581{
 582        int ret = -EINVAL;
 583        enum pci_barno bar;
 584        struct pci_endpoint_test *test = to_endpoint_test(file->private_data);
 585        struct pci_dev *pdev = test->pdev;
 586
 587        mutex_lock(&test->mutex);
 588        switch (cmd) {
 589        case PCITEST_BAR:
 590                bar = arg;
 591                if (bar < 0 || bar > 5)
 592                        goto ret;
 593                if (is_am654_pci_dev(pdev) && bar == BAR_0)
 594                        goto ret;
 595                ret = pci_endpoint_test_bar(test, bar);
 596                break;
 597        case PCITEST_LEGACY_IRQ:
 598                ret = pci_endpoint_test_legacy_irq(test);
 599                break;
 600        case PCITEST_MSI:
 601        case PCITEST_MSIX:
 602                ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX);
 603                break;
 604        case PCITEST_WRITE:
 605                ret = pci_endpoint_test_write(test, arg);
 606                break;
 607        case PCITEST_READ:
 608                ret = pci_endpoint_test_read(test, arg);
 609                break;
 610        case PCITEST_COPY:
 611                ret = pci_endpoint_test_copy(test, arg);
 612                break;
 613        case PCITEST_SET_IRQTYPE:
 614                ret = pci_endpoint_test_set_irq(test, arg);
 615                break;
 616        case PCITEST_GET_IRQTYPE:
 617                ret = irq_type;
 618                break;
 619        }
 620
 621ret:
 622        mutex_unlock(&test->mutex);
 623        return ret;
 624}
 625
 626static const struct file_operations pci_endpoint_test_fops = {
 627        .owner = THIS_MODULE,
 628        .unlocked_ioctl = pci_endpoint_test_ioctl,
 629};
 630
 631static int pci_endpoint_test_probe(struct pci_dev *pdev,
 632                                   const struct pci_device_id *ent)
 633{
 634        int err;
 635        int id;
 636        char name[20];
 637        enum pci_barno bar;
 638        void __iomem *base;
 639        struct device *dev = &pdev->dev;
 640        struct pci_endpoint_test *test;
 641        struct pci_endpoint_test_data *data;
 642        enum pci_barno test_reg_bar = BAR_0;
 643        struct miscdevice *misc_device;
 644
 645        if (pci_is_bridge(pdev))
 646                return -ENODEV;
 647
 648        test = devm_kzalloc(dev, sizeof(*test), GFP_KERNEL);
 649        if (!test)
 650                return -ENOMEM;
 651
 652        test->test_reg_bar = 0;
 653        test->alignment = 0;
 654        test->pdev = pdev;
 655
 656        if (no_msi)
 657                irq_type = IRQ_TYPE_LEGACY;
 658
 659        data = (struct pci_endpoint_test_data *)ent->driver_data;
 660        if (data) {
 661                test_reg_bar = data->test_reg_bar;
 662                test->test_reg_bar = test_reg_bar;
 663                test->alignment = data->alignment;
 664                irq_type = data->irq_type;
 665        }
 666
 667        init_completion(&test->irq_raised);
 668        mutex_init(&test->mutex);
 669
 670        err = pci_enable_device(pdev);
 671        if (err) {
 672                dev_err(dev, "Cannot enable PCI device\n");
 673                return err;
 674        }
 675
 676        err = pci_request_regions(pdev, DRV_MODULE_NAME);
 677        if (err) {
 678                dev_err(dev, "Cannot obtain PCI resources\n");
 679                goto err_disable_pdev;
 680        }
 681
 682        pci_set_master(pdev);
 683
 684        if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type))
 685                goto err_disable_irq;
 686
 687        if (!pci_endpoint_test_request_irq(test))
 688                goto err_disable_irq;
 689
 690        for (bar = BAR_0; bar <= BAR_5; bar++) {
 691                if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
 692                        base = pci_ioremap_bar(pdev, bar);
 693                        if (!base) {
 694                                dev_err(dev, "Failed to read BAR%d\n", bar);
 695                                WARN_ON(bar == test_reg_bar);
 696                        }
 697                        test->bar[bar] = base;
 698                }
 699        }
 700
 701        test->base = test->bar[test_reg_bar];
 702        if (!test->base) {
 703                err = -ENOMEM;
 704                dev_err(dev, "Cannot perform PCI test without BAR%d\n",
 705                        test_reg_bar);
 706                goto err_iounmap;
 707        }
 708
 709        pci_set_drvdata(pdev, test);
 710
 711        id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL);
 712        if (id < 0) {
 713                err = id;
 714                dev_err(dev, "Unable to get id\n");
 715                goto err_iounmap;
 716        }
 717
 718        snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id);
 719        misc_device = &test->miscdev;
 720        misc_device->minor = MISC_DYNAMIC_MINOR;
 721        misc_device->name = kstrdup(name, GFP_KERNEL);
 722        if (!misc_device->name) {
 723                err = -ENOMEM;
 724                goto err_ida_remove;
 725        }
 726        misc_device->fops = &pci_endpoint_test_fops,
 727
 728        err = misc_register(misc_device);
 729        if (err) {
 730                dev_err(dev, "Failed to register device\n");
 731                goto err_kfree_name;
 732        }
 733
 734        return 0;
 735
 736err_kfree_name:
 737        kfree(misc_device->name);
 738
 739err_ida_remove:
 740        ida_simple_remove(&pci_endpoint_test_ida, id);
 741
 742err_iounmap:
 743        for (bar = BAR_0; bar <= BAR_5; bar++) {
 744                if (test->bar[bar])
 745                        pci_iounmap(pdev, test->bar[bar]);
 746        }
 747        pci_endpoint_test_release_irq(test);
 748
 749err_disable_irq:
 750        pci_endpoint_test_free_irq_vectors(test);
 751        pci_release_regions(pdev);
 752
 753err_disable_pdev:
 754        pci_disable_device(pdev);
 755
 756        return err;
 757}
 758
 759static void pci_endpoint_test_remove(struct pci_dev *pdev)
 760{
 761        int id;
 762        enum pci_barno bar;
 763        struct pci_endpoint_test *test = pci_get_drvdata(pdev);
 764        struct miscdevice *misc_device = &test->miscdev;
 765
 766        if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1)
 767                return;
 768        if (id < 0)
 769                return;
 770
 771        misc_deregister(&test->miscdev);
 772        kfree(misc_device->name);
 773        ida_simple_remove(&pci_endpoint_test_ida, id);
 774        for (bar = BAR_0; bar <= BAR_5; bar++) {
 775                if (test->bar[bar])
 776                        pci_iounmap(pdev, test->bar[bar]);
 777        }
 778
 779        pci_endpoint_test_release_irq(test);
 780        pci_endpoint_test_free_irq_vectors(test);
 781
 782        pci_release_regions(pdev);
 783        pci_disable_device(pdev);
 784}
 785
 786static const struct pci_endpoint_test_data am654_data = {
 787        .test_reg_bar = BAR_2,
 788        .alignment = SZ_64K,
 789        .irq_type = IRQ_TYPE_MSI,
 790};
 791
 792static const struct pci_device_id pci_endpoint_test_tbl[] = {
 793        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
 794        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
 795        { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
 796        { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
 797        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
 798          .driver_data = (kernel_ulong_t)&am654_data
 799        },
 800        { }
 801};
 802MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
 803
 804static struct pci_driver pci_endpoint_test_driver = {
 805        .name           = DRV_MODULE_NAME,
 806        .id_table       = pci_endpoint_test_tbl,
 807        .probe          = pci_endpoint_test_probe,
 808        .remove         = pci_endpoint_test_remove,
 809};
 810module_pci_driver(pci_endpoint_test_driver);
 811
 812MODULE_DESCRIPTION("PCI ENDPOINT TEST HOST DRIVER");
 813MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
 814MODULE_LICENSE("GPL v2");
 815