diff options
Diffstat (limited to 'drivers/misc/pci_endpoint_test.c')
| -rw-r--r-- | drivers/misc/pci_endpoint_test.c | 131 | 
1 files changed, 70 insertions, 61 deletions
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index d5ac71a49386..d294850a35a1 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -28,11 +28,6 @@  #define DRV_MODULE_NAME				"pci-endpoint-test" -#define IRQ_TYPE_UNDEFINED			-1 -#define IRQ_TYPE_INTX				0 -#define IRQ_TYPE_MSI				1 -#define IRQ_TYPE_MSIX				2 -  #define PCI_ENDPOINT_TEST_MAGIC			0x0  #define PCI_ENDPOINT_TEST_COMMAND		0x4 @@ -71,6 +66,9 @@  #define PCI_ENDPOINT_TEST_CAPS			0x30  #define CAP_UNALIGNED_ACCESS			BIT(0) +#define CAP_MSI					BIT(1) +#define CAP_MSIX				BIT(2) +#define CAP_INTX				BIT(3)  #define PCI_DEVICE_ID_TI_AM654			0xb00c  #define PCI_DEVICE_ID_TI_J7200			0xb00f @@ -88,7 +86,6 @@  #define PCI_DEVICE_ID_RENESAS_R8A774E1		0x0025  #define PCI_DEVICE_ID_RENESAS_R8A779F0		0x0031 -#define PCI_VENDOR_ID_ROCKCHIP			0x1d87  #define PCI_DEVICE_ID_ROCKCHIP_RK3588		0x3588  static DEFINE_IDA(pci_endpoint_test_ida); @@ -96,14 +93,6 @@ static DEFINE_IDA(pci_endpoint_test_ida);  #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \  					    miscdev) -static bool no_msi; -module_param(no_msi, bool, 0444); -MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test"); - -static int irq_type = IRQ_TYPE_MSI; -module_param(irq_type, int, 0444); -MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)"); -  enum pci_barno {  	BAR_0,  	BAR_1, @@ -126,6 +115,7 @@ struct pci_endpoint_test {  	struct miscdevice miscdev;  	enum pci_barno test_reg_bar;  	size_t alignment; +	u32 ep_caps;  	const char *name;  }; @@ -166,7 +156,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; +	test->irq_type = PCITEST_IRQ_TYPE_UNDEFINED;  }  static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, @@ -177,7 +167,7 @@ static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,  	struct device *dev = &pdev->dev;  	switch (type) { -	case IRQ_TYPE_INTX: +	case PCITEST_IRQ_TYPE_INTX:  		irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);  		if (irq < 0) {  			dev_err(dev, "Failed to get Legacy interrupt\n"); @@ -185,7 +175,7 @@ static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,  		}  		break; -	case IRQ_TYPE_MSI: +	case PCITEST_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"); @@ -193,7 +183,7 @@ static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,  		}  		break; -	case IRQ_TYPE_MSIX: +	case PCITEST_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"); @@ -216,10 +206,9 @@ static void pci_endpoint_test_release_irq(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); +		free_irq(pci_irq_vector(pdev, i), test);  	test->num_irqs = 0;  } @@ -232,9 +221,9 @@ static int pci_endpoint_test_request_irq(struct pci_endpoint_test *test)  	struct device *dev = &pdev->dev;  	for (i = 0; i < test->num_irqs; i++) { -		ret = devm_request_irq(dev, pci_irq_vector(pdev, i), -				       pci_endpoint_test_irqhandler, -				       IRQF_SHARED, test->name, test); +		ret = request_irq(pci_irq_vector(pdev, i), +				  pci_endpoint_test_irqhandler, IRQF_SHARED, +				  test->name, test);  		if (ret)  			goto fail;  	} @@ -242,23 +231,26 @@ static int pci_endpoint_test_request_irq(struct pci_endpoint_test *test)  	return 0;  fail: -	switch (irq_type) { -	case IRQ_TYPE_INTX: +	switch (test->irq_type) { +	case PCITEST_IRQ_TYPE_INTX:  		dev_err(dev, "Failed to request IRQ %d for Legacy\n",  			pci_irq_vector(pdev, i));  		break; -	case IRQ_TYPE_MSI: +	case PCITEST_IRQ_TYPE_MSI:  		dev_err(dev, "Failed to request IRQ %d for MSI %d\n",  			pci_irq_vector(pdev, i),  			i + 1);  		break; -	case IRQ_TYPE_MSIX: +	case PCITEST_IRQ_TYPE_MSIX:  		dev_err(dev, "Failed to request IRQ %d for MSI-X %d\n",  			pci_irq_vector(pdev, i),  			i + 1);  		break;  	} +	test->num_irqs = i; +	pci_endpoint_test_release_irq(test); +  	return ret;  } @@ -272,9 +264,9 @@ static const u32 bar_test_pattern[] = {  };  static int pci_endpoint_test_bar_memcmp(struct pci_endpoint_test *test, -					enum pci_barno barno, int offset, -					void *write_buf, void *read_buf, -					int size) +					enum pci_barno barno, +					resource_size_t offset, void *write_buf, +					void *read_buf, int size)  {  	memset(write_buf, bar_test_pattern[barno], size);  	memcpy_toio(test->bar[barno] + offset, write_buf, size); @@ -287,16 +279,19 @@ static int pci_endpoint_test_bar_memcmp(struct pci_endpoint_test *test,  static int pci_endpoint_test_bar(struct pci_endpoint_test *test,  				  enum pci_barno barno)  { -	int j, bar_size, buf_size, iters; +	resource_size_t bar_size, offset = 0;  	void *write_buf __free(kfree) = NULL;  	void *read_buf __free(kfree) = NULL;  	struct pci_dev *pdev = test->pdev; +	int buf_size; + +	bar_size = pci_resource_len(pdev, barno); +	if (!bar_size) +		return -ENODATA;  	if (!test->bar[barno])  		return -ENOMEM; -	bar_size = pci_resource_len(pdev, barno); -  	if (barno == test->test_reg_bar)  		bar_size = 0x4; @@ -314,11 +309,12 @@ static int pci_endpoint_test_bar(struct pci_endpoint_test *test,  	if (!read_buf)  		return -ENOMEM; -	iters = bar_size / buf_size; -	for (j = 0; j < iters; j++) -		if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * j, -						 write_buf, read_buf, buf_size)) +	while (offset < bar_size) { +		if (pci_endpoint_test_bar_memcmp(test, barno, offset, write_buf, +						 read_buf, buf_size))  			return -EIO; +		offset += buf_size; +	}  	return 0;  } @@ -382,7 +378,7 @@ static int pci_endpoint_test_bars_read_bar(struct pci_endpoint_test *test,  static int pci_endpoint_test_bars(struct pci_endpoint_test *test)  {  	enum pci_barno bar; -	bool ret; +	int ret;  	/* Write all BARs in order (without reading). */  	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) @@ -398,7 +394,7 @@ static int pci_endpoint_test_bars(struct pci_endpoint_test *test)  	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {  		if (test->bar[bar]) {  			ret = pci_endpoint_test_bars_read_bar(test, bar); -			if (!ret) +			if (ret)  				return ret;  		}  	} @@ -411,7 +407,7 @@ static int pci_endpoint_test_intx_irq(struct pci_endpoint_test *test)  	u32 val;  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, -				 IRQ_TYPE_INTX); +				 PCITEST_IRQ_TYPE_INTX);  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,  				 COMMAND_RAISE_INTX_IRQ); @@ -431,7 +427,8 @@ static int pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,  	int ret;  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, -				 msix ? IRQ_TYPE_MSIX : IRQ_TYPE_MSI); +				 msix ? PCITEST_IRQ_TYPE_MSIX : +				 PCITEST_IRQ_TYPE_MSI);  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,  				 msix ? COMMAND_RAISE_MSIX_IRQ : @@ -507,7 +504,8 @@ static int pci_endpoint_test_copy(struct pci_endpoint_test *test,  	if (use_dma)  		flags |= FLAG_USE_DMA; -	if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) { +	if (irq_type < PCITEST_IRQ_TYPE_INTX || +	    irq_type > PCITEST_IRQ_TYPE_MSIX) {  		dev_err(dev, "Invalid IRQ type option\n");  		return -EINVAL;  	} @@ -639,7 +637,8 @@ static int pci_endpoint_test_write(struct pci_endpoint_test *test,  	if (use_dma)  		flags |= FLAG_USE_DMA; -	if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) { +	if (irq_type < PCITEST_IRQ_TYPE_INTX || +	    irq_type > PCITEST_IRQ_TYPE_MSIX) {  		dev_err(dev, "Invalid IRQ type option\n");  		return -EINVAL;  	} @@ -735,7 +734,8 @@ static int pci_endpoint_test_read(struct pci_endpoint_test *test,  	if (use_dma)  		flags |= FLAG_USE_DMA; -	if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) { +	if (irq_type < PCITEST_IRQ_TYPE_INTX || +	    irq_type > PCITEST_IRQ_TYPE_MSIX) {  		dev_err(dev, "Invalid IRQ type option\n");  		return -EINVAL;  	} @@ -805,11 +805,24 @@ static int pci_endpoint_test_set_irq(struct pci_endpoint_test *test,  	struct device *dev = &pdev->dev;  	int ret; -	if (req_irq_type < IRQ_TYPE_INTX || req_irq_type > IRQ_TYPE_MSIX) { +	if (req_irq_type < PCITEST_IRQ_TYPE_INTX || +	    req_irq_type > PCITEST_IRQ_TYPE_AUTO) {  		dev_err(dev, "Invalid IRQ type option\n");  		return -EINVAL;  	} +	if (req_irq_type == PCITEST_IRQ_TYPE_AUTO) { +		if (test->ep_caps & CAP_MSI) +			req_irq_type = PCITEST_IRQ_TYPE_MSI; +		else if (test->ep_caps & CAP_MSIX) +			req_irq_type = PCITEST_IRQ_TYPE_MSIX; +		else if (test->ep_caps & CAP_INTX) +			req_irq_type = PCITEST_IRQ_TYPE_INTX; +		else +			/* fallback to MSI if no caps defined */ +			req_irq_type = PCITEST_IRQ_TYPE_MSI; +	} +  	if (test->irq_type == req_irq_type)  		return 0; @@ -874,7 +887,7 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,  		ret = pci_endpoint_test_set_irq(test, arg);  		break;  	case PCITEST_GET_IRQTYPE: -		ret = irq_type; +		ret = test->irq_type;  		break;  	case PCITEST_CLEAR_IRQ:  		ret = pci_endpoint_test_clear_irq(test); @@ -895,13 +908,12 @@ static void pci_endpoint_test_get_capabilities(struct pci_endpoint_test *test)  {  	struct pci_dev *pdev = test->pdev;  	struct device *dev = &pdev->dev; -	u32 caps; -	caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS); -	dev_dbg(dev, "PCI_ENDPOINT_TEST_CAPS: %#x\n", caps); +	test->ep_caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS); +	dev_dbg(dev, "PCI_ENDPOINT_TEST_CAPS: %#x\n", test->ep_caps);  	/* CAP_UNALIGNED_ACCESS is set if the EP can do unaligned access */ -	if (caps & CAP_UNALIGNED_ACCESS) +	if (test->ep_caps & CAP_UNALIGNED_ACCESS)  		test->alignment = 0;  } @@ -910,7 +922,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,  {  	int ret;  	int id; -	char name[24]; +	char name[29];  	enum pci_barno bar;  	void __iomem *base;  	struct device *dev = &pdev->dev; @@ -929,17 +941,14 @@ 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_INTX; +	test->irq_type = PCITEST_IRQ_TYPE_UNDEFINED;  	data = (struct pci_endpoint_test_data *)ent->driver_data;  	if (data) {  		test_reg_bar = data->test_reg_bar;  		test->test_reg_bar = test_reg_bar;  		test->alignment = data->alignment; -		irq_type = data->irq_type; +		test->irq_type = data->irq_type;  	}  	init_completion(&test->irq_raised); @@ -961,7 +970,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,  	pci_set_master(pdev); -	ret = pci_endpoint_test_alloc_irq_vectors(test, irq_type); +	ret = pci_endpoint_test_alloc_irq_vectors(test, test->irq_type);  	if (ret)  		goto err_disable_irq; @@ -1083,23 +1092,23 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)  static const struct pci_endpoint_test_data default_data = {  	.test_reg_bar = BAR_0,  	.alignment = SZ_4K, -	.irq_type = IRQ_TYPE_MSI, +	.irq_type = PCITEST_IRQ_TYPE_MSI,  };  static const struct pci_endpoint_test_data am654_data = {  	.test_reg_bar = BAR_2,  	.alignment = SZ_64K, -	.irq_type = IRQ_TYPE_MSI, +	.irq_type = PCITEST_IRQ_TYPE_MSI,  };  static const struct pci_endpoint_test_data j721e_data = {  	.alignment = 256, -	.irq_type = IRQ_TYPE_MSI, +	.irq_type = PCITEST_IRQ_TYPE_MSI,  };  static const struct pci_endpoint_test_data rk3588_data = {  	.alignment = SZ_64K, -	.irq_type = IRQ_TYPE_MSI, +	.irq_type = PCITEST_IRQ_TYPE_MSI,  };  /*  | 
