lkml.org 
[lkml]   [2018]   [Jul]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v10 10/12] pci_endpoint_test: Add 2 ioctl commands
    Date
    Add MSI-X support and update driver documentation accordingly.

    Add 2 new IOCTL commands:
    - Allow to reconfigure driver IRQ type in runtime.
    - Allow to retrieve current driver IRQ type configured.

    Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
    ---
    Change v2->v3:
    - New patch file created base on the previous patch
    "misc: pci_endpoint_test: Add MSI-X support" patch file following
    Kishon's suggestion.
    Change v3->v4:
    - Rebased to Lorenzo's master branch v4.18-rc1.
    Change v4->v5:
    - Nothing changed, just to follow the patch set version.
    Change v5->v6:
    - Moved PCITEST_SET_IRQTYPE and PCITEST_GET_IRQTYPE ioctl entries
    from patch #10 to here.
    - Increased ioctl parameters range associated to
    drivers/misc/pci_endpoint_test.c driver.
    Change v6->v7:
    - irq_type variable update just before returning the function.
    Change v7->v8:
    - Re-sending the patch series.
    Change v8->v9:
    - Added a extra parameter to pci_endpoint_test_alloc_irq_vectors,
    that specifies which irq type should be allocated.
    Change v9->v10:
    - Nothing changed, just to follow the patch set version.

    Documentation/ioctl/ioctl-number.txt | 2 +-
    Documentation/misc-devices/pci-endpoint-test.txt | 3 +
    drivers/misc/pci_endpoint_test.c | 176 +++++++++++++++++------
    include/uapi/linux/pcitest.h | 2 +
    4 files changed, 136 insertions(+), 47 deletions(-)

    diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
    index 65259d4..c15c4f3 100644
    --- a/Documentation/ioctl/ioctl-number.txt
    +++ b/Documentation/ioctl/ioctl-number.txt
    @@ -166,7 +166,7 @@ Code Seq#(hex) Include File Comments
    'P' all linux/soundcard.h conflict!
    'P' 60-6F sound/sscape_ioctl.h conflict!
    'P' 00-0F drivers/usb/class/usblp.c conflict!
    -'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
    +'P' 01-09 drivers/misc/pci_endpoint_test.c conflict!
    'Q' all linux/soundcard.h
    'R' 00-1F linux/random.h conflict!
    'R' 01 linux/rfkill.h conflict!
    diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt
    index fdfa0f6..58ccca4 100644
    --- a/Documentation/misc-devices/pci-endpoint-test.txt
    +++ b/Documentation/misc-devices/pci-endpoint-test.txt
    @@ -28,6 +28,9 @@ ioctl
    to be tested should be passed as argument.
    PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
    to be tested should be passed as argument.
    + PCITEST_SET_IRQTYPE: Changes driver IRQ type configuration. The IRQ type
    + should be passed as argument (0: Legacy, 1:MSI, 2:MSI-X).
    + PCITEST_GET_IRQTYPE: Gets driver IRQ type configuration.
    PCITEST_WRITE: Perform write tests. The size of the buffer should be passed
    as argument.
    PCITEST_READ: Perform read tests. The size of the buffer should be passed
    diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
    index f4fef10..ce4b79a 100644
    --- a/drivers/misc/pci_endpoint_test.c
    +++ b/drivers/misc/pci_endpoint_test.c
    @@ -157,6 +157,88 @@ static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
    +{
    + int i;
    + struct pci_dev *pdev = test->pdev;
    + struct device *dev = &pdev->dev;
    +
    + for (i = 0; i < test->num_irqs; i++)
    + devm_free_irq(dev, pci_irq_vector(pdev, i), test);
    +
    + test->num_irqs = 0;
    +}
    +
    +static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
    + int type)
    +{
    + int irq = -1;
    + struct pci_dev *pdev = test->pdev;
    + struct device *dev = &pdev->dev;
    + bool res = true;
    +
    + switch (type) {
    + case IRQ_TYPE_LEGACY:
    + irq = 0;
    + break;
    + case IRQ_TYPE_MSI:
    + irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
    + if (irq < 0)
    + dev_err(dev, "Failed to get MSI interrupts\n");
    + break;
    + case IRQ_TYPE_MSIX:
    + irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
    + if (irq < 0)
    + dev_err(dev, "Failed to get MSI-X interrupts\n");
    + break;
    + default:
    + dev_err(dev, "Invalid IRQ type selected\n");
    + }
    +
    + if (irq < 0) {
    + irq = 0;
    + res = false;
    + }
    + test->num_irqs = irq;
    +
    + return res;
    +}
    +
    +static void pci_endpoint_test_release_irq(struct pci_endpoint_test *test)
    +{
    + struct pci_dev *pdev = test->pdev;
    +
    + pci_disable_msi(pdev);
    + pci_disable_msix(pdev);
    +}
    +
    +static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
    +{
    + int i;
    + int err;
    + struct pci_dev *pdev = test->pdev;
    + struct device *dev = &pdev->dev;
    +
    + err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
    + IRQF_SHARED, DRV_MODULE_NAME, test);
    + if (err) {
    + dev_err(dev, "Failed to request IRQ %d\n", pdev->irq);
    + return false;
    + }
    +
    + for (i = 1; i < test->num_irqs; i++) {
    + err = devm_request_irq(dev, pci_irq_vector(pdev, i),
    + pci_endpoint_test_irqhandler,
    + IRQF_SHARED, DRV_MODULE_NAME, test);
    + if (err)
    + dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
    + pci_irq_vector(pdev, i),
    + irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
    + }
    +
    + return true;
    +}
    +
    static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
    enum pci_barno barno)
    {
    @@ -440,6 +522,38 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
    return ret;
    }

    +static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
    + int req_irq_type)
    +{
    + struct pci_dev *pdev = test->pdev;
    + struct device *dev = &pdev->dev;
    +
    + if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) {
    + dev_err(dev, "Invalid IRQ type option\n");
    + return false;
    + }
    +
    + if (irq_type == req_irq_type)
    + return true;
    +
    + pci_endpoint_test_free_irq_vectors(test);
    + pci_endpoint_test_release_irq(test);
    +
    + if (!pci_endpoint_test_alloc_irq_vectors(test, req_irq_type)) {
    + pci_endpoint_test_release_irq(test);
    + return false;
    + }
    +
    + if (!pci_endpoint_test_request_irq(test)) {
    + pci_endpoint_test_release_irq(test);
    + return false;
    + }
    +
    + irq_type = req_irq_type;
    +
    + return true;
    +}
    +
    static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
    unsigned long arg)
    {
    @@ -471,6 +585,12 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
    case PCITEST_COPY:
    ret = pci_endpoint_test_copy(test, arg);
    break;
    + case PCITEST_SET_IRQTYPE:
    + ret = pci_endpoint_test_set_irq(test, arg);
    + break;
    + case PCITEST_GET_IRQTYPE:
    + ret = irq_type;
    + break;
    }

    ret:
    @@ -486,9 +606,7 @@ static const struct file_operations pci_endpoint_test_fops = {
    static int pci_endpoint_test_probe(struct pci_dev *pdev,
    const struct pci_device_id *ent)
    {
    - int i;
    int err;
    - int irq = 0;
    int id;
    char name[20];
    enum pci_barno bar;
    @@ -537,41 +655,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,

    pci_set_master(pdev);

    - switch (irq_type) {
    - case IRQ_TYPE_LEGACY:
    - break;
    - case IRQ_TYPE_MSI:
    - irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
    - if (irq < 0)
    - dev_err(dev, "Failed to get MSI interrupts\n");
    - test->num_irqs = irq;
    - break;
    - case IRQ_TYPE_MSIX:
    - irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
    - if (irq < 0)
    - dev_err(dev, "Failed to get MSI-X interrupts\n");
    - test->num_irqs = irq;
    - break;
    - default:
    - dev_err(dev, "Invalid IRQ type selected\n");
    - }
    -
    - err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
    - IRQF_SHARED, DRV_MODULE_NAME, test);
    - if (err) {
    - dev_err(dev, "Failed to request IRQ %d\n", pdev->irq);
    - goto err_disable_msi;
    - }
    + if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type))
    + goto err_disable_irq;

    - for (i = 1; i < irq; i++) {
    - err = devm_request_irq(dev, pci_irq_vector(pdev, i),
    - pci_endpoint_test_irqhandler,
    - IRQF_SHARED, DRV_MODULE_NAME, test);
    - if (err)
    - dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
    - pci_irq_vector(pdev, i),
    - irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
    - }
    + if (!pci_endpoint_test_request_irq(test))
    + goto err_disable_irq;

    for (bar = BAR_0; bar <= BAR_5; bar++) {
    if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
    @@ -631,12 +719,10 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
    pci_iounmap(pdev, test->bar[bar]);
    }

    - for (i = 0; i < irq; i++)
    - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
    + pci_endpoint_test_free_irq_vectors(test);

    -err_disable_msi:
    - pci_disable_msi(pdev);
    - pci_disable_msix(pdev);
    +err_disable_irq:
    + pci_endpoint_test_release_irq(test);
    pci_release_regions(pdev);

    err_disable_pdev:
    @@ -648,7 +734,6 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
    static void pci_endpoint_test_remove(struct pci_dev *pdev)
    {
    int id;
    - int i;
    enum pci_barno bar;
    struct pci_endpoint_test *test = pci_get_drvdata(pdev);
    struct miscdevice *misc_device = &test->miscdev;
    @@ -665,10 +750,9 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
    if (test->bar[bar])
    pci_iounmap(pdev, test->bar[bar]);
    }
    - for (i = 0; i < test->num_irqs; i++)
    - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
    - pci_disable_msi(pdev);
    - pci_disable_msix(pdev);
    + pci_endpoint_test_free_irq_vectors(test);
    +
    + pci_endpoint_test_release_irq(test);
    pci_release_regions(pdev);
    pci_disable_device(pdev);
    }
    diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
    index d746fb1..cbf422e 100644
    --- a/include/uapi/linux/pcitest.h
    +++ b/include/uapi/linux/pcitest.h
    @@ -17,5 +17,7 @@
    #define PCITEST_READ _IOW('P', 0x5, unsigned long)
    #define PCITEST_COPY _IOW('P', 0x6, unsigned long)
    #define PCITEST_MSIX _IOW('P', 0x7, int)
    +#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
    +#define PCITEST_GET_IRQTYPE _IO('P', 0x9)

    #endif /* __UAPI_LINUX_PCITEST_H */
    --
    2.7.4
    \
     
     \ /
      Last update: 2018-07-15 22:07    [W:4.401 / U:0.400 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site