misc: pci_endpoint_test: Use full pci-endpoint-test name in request_irq()
[linux-2.6-microblaze.git] / drivers / misc / pci_endpoint_test.c
index 5998df1..bc3ae4a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/random.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 
@@ -52,6 +53,7 @@
 #define STATUS_SRC_ADDR_INVALID                        BIT(7)
 #define STATUS_DST_ADDR_INVALID                        BIT(8)
 
+#define PCI_ENDPOINT_TEST_STATUS               0x8
 #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR       0x0c
 #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR       0x10
 
@@ -64,6 +66,9 @@
 #define PCI_ENDPOINT_TEST_IRQ_TYPE             0x24
 #define PCI_ENDPOINT_TEST_IRQ_NUMBER           0x28
 
+#define PCI_ENDPOINT_TEST_FLAGS                        0x2c
+#define FLAG_USE_DMA                           BIT(0)
+
 #define PCI_DEVICE_ID_TI_AM654                 0xb00c
 
 #define is_am654_pci_dev(pdev)         \
@@ -98,11 +103,13 @@ struct pci_endpoint_test {
        struct completion irq_raised;
        int             last_irq;
        int             num_irqs;
+       int             irq_type;
        /* mutex to protect the ioctls */
        struct mutex    mutex;
        struct miscdevice miscdev;
        enum pci_barno test_reg_bar;
        size_t alignment;
+       const char *name;
 };
 
 struct pci_endpoint_test_data {
@@ -157,6 +164,7 @@ static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
        struct pci_dev *pdev = test->pdev;
 
        pci_free_irq_vectors(pdev);
+       test->irq_type = IRQ_TYPE_UNDEFINED;
 }
 
 static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
@@ -191,6 +199,8 @@ static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
                irq = 0;
                res = false;
        }
+
+       test->irq_type = type;
        test->num_irqs = irq;
 
        return res;
@@ -218,7 +228,7 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
        for (i = 0; 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);
+                                      IRQF_SHARED, test->name, test);
                if (err)
                        goto fail;
        }
@@ -315,11 +325,16 @@ static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
        return false;
 }
 
-static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
+static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
+                                  unsigned long arg)
 {
+       struct pci_endpoint_test_xfer_param param;
        bool ret = false;
        void *src_addr;
        void *dst_addr;
+       u32 flags = 0;
+       bool use_dma;
+       size_t size;
        dma_addr_t src_phys_addr;
        dma_addr_t dst_phys_addr;
        struct pci_dev *pdev = test->pdev;
@@ -330,12 +345,25 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
        dma_addr_t orig_dst_phys_addr;
        size_t offset;
        size_t alignment = test->alignment;
+       int irq_type = test->irq_type;
        u32 src_crc32;
        u32 dst_crc32;
+       int err;
 
+       err = copy_from_user(&param, (void __user *)arg, sizeof(param));
+       if (err) {
+               dev_err(dev, "Failed to get transfer param\n");
+               return false;
+       }
+
+       size = param.size;
        if (size > SIZE_MAX - alignment)
                goto err;
 
+       use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
+       if (use_dma)
+               flags |= FLAG_USE_DMA;
+
        if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
                dev_err(dev, "Invalid IRQ type option\n");
                goto err;
@@ -406,6 +434,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
                                 size);
 
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -434,9 +463,13 @@ err:
        return ret;
 }
 
-static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
+static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
+                                   unsigned long arg)
 {
+       struct pci_endpoint_test_xfer_param param;
        bool ret = false;
+       u32 flags = 0;
+       bool use_dma;
        u32 reg;
        void *addr;
        dma_addr_t phys_addr;
@@ -446,11 +479,25 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
        dma_addr_t orig_phys_addr;
        size_t offset;
        size_t alignment = test->alignment;
+       int irq_type = test->irq_type;
+       size_t size;
        u32 crc32;
+       int err;
 
+       err = copy_from_user(&param, (void __user *)arg, sizeof(param));
+       if (err != 0) {
+               dev_err(dev, "Failed to get transfer param\n");
+               return false;
+       }
+
+       size = param.size;
        if (size > SIZE_MAX - alignment)
                goto err;
 
+       use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
+       if (use_dma)
+               flags |= FLAG_USE_DMA;
+
        if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
                dev_err(dev, "Invalid IRQ type option\n");
                goto err;
@@ -493,6 +540,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
 
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
 
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -514,9 +562,14 @@ err:
        return ret;
 }
 
-static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
+static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
+                                  unsigned long arg)
 {
+       struct pci_endpoint_test_xfer_param param;
        bool ret = false;
+       u32 flags = 0;
+       bool use_dma;
+       size_t size;
        void *addr;
        dma_addr_t phys_addr;
        struct pci_dev *pdev = test->pdev;
@@ -525,11 +578,24 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
        dma_addr_t orig_phys_addr;
        size_t offset;
        size_t alignment = test->alignment;
+       int irq_type = test->irq_type;
        u32 crc32;
+       int err;
 
+       err = copy_from_user(&param, (void __user *)arg, sizeof(param));
+       if (err) {
+               dev_err(dev, "Failed to get transfer param\n");
+               return false;
+       }
+
+       size = param.size;
        if (size > SIZE_MAX - alignment)
                goto err;
 
+       use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
+       if (use_dma)
+               flags |= FLAG_USE_DMA;
+
        if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
                dev_err(dev, "Invalid IRQ type option\n");
                goto err;
@@ -566,6 +632,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
 
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
 
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
        pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -586,6 +653,13 @@ err:
        return ret;
 }
 
+static bool pci_endpoint_test_clear_irq(struct pci_endpoint_test *test)
+{
+       pci_endpoint_test_release_irq(test);
+       pci_endpoint_test_free_irq_vectors(test);
+       return true;
+}
+
 static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
                                      int req_irq_type)
 {
@@ -597,7 +671,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
                return false;
        }
 
-       if (irq_type == req_irq_type)
+       if (test->irq_type == req_irq_type)
                return true;
 
        pci_endpoint_test_release_irq(test);
@@ -609,12 +683,10 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
        if (!pci_endpoint_test_request_irq(test))
                goto err;
 
-       irq_type = req_irq_type;
        return true;
 
 err:
        pci_endpoint_test_free_irq_vectors(test);
-       irq_type = IRQ_TYPE_UNDEFINED;
        return false;
 }
 
@@ -658,6 +730,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
        case PCITEST_GET_IRQTYPE:
                ret = irq_type;
                break;
+       case PCITEST_CLEAR_IRQ:
+               ret = pci_endpoint_test_clear_irq(test);
+               break;
        }
 
 ret:
@@ -675,7 +750,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 {
        int err;
        int id;
-       char name[20];
+       char name[24];
        enum pci_barno bar;
        void __iomem *base;
        struct device *dev = &pdev->dev;
@@ -694,6 +769,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
        test->test_reg_bar = 0;
        test->alignment = 0;
        test->pdev = pdev;
+       test->irq_type = IRQ_TYPE_UNDEFINED;
 
        if (no_msi)
                irq_type = IRQ_TYPE_LEGACY;
@@ -732,9 +808,6 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
        if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type))
                goto err_disable_irq;
 
-       if (!pci_endpoint_test_request_irq(test))
-               goto err_disable_irq;
-
        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
                        base = pci_ioremap_bar(pdev, bar);
@@ -764,12 +837,21 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
        }
 
        snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id);
+       test->name = kstrdup(name, GFP_KERNEL);
+       if (!test->name) {
+               err = -ENOMEM;
+               goto err_ida_remove;
+       }
+
+       if (!pci_endpoint_test_request_irq(test))
+               goto err_kfree_test_name;
+
        misc_device = &test->miscdev;
        misc_device->minor = MISC_DYNAMIC_MINOR;
        misc_device->name = kstrdup(name, GFP_KERNEL);
        if (!misc_device->name) {
                err = -ENOMEM;
-               goto err_ida_remove;
+               goto err_release_irq;
        }
        misc_device->fops = &pci_endpoint_test_fops,
 
@@ -784,6 +866,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 err_kfree_name:
        kfree(misc_device->name);
 
+err_release_irq:
+       pci_endpoint_test_release_irq(test);
+
+err_kfree_test_name:
+       kfree(test->name);
+
 err_ida_remove:
        ida_simple_remove(&pci_endpoint_test_ida, id);
 
@@ -792,7 +880,6 @@ err_iounmap:
                if (test->bar[bar])
                        pci_iounmap(pdev, test->bar[bar]);
        }
-       pci_endpoint_test_release_irq(test);
 
 err_disable_irq:
        pci_endpoint_test_free_irq_vectors(test);
@@ -818,6 +905,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
 
        misc_deregister(&test->miscdev);
        kfree(misc_device->name);
+       kfree(test->name);
        ida_simple_remove(&pci_endpoint_test_ida, id);
        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (test->bar[bar])