diff options
Diffstat (limited to 'drivers/misc/pci_endpoint_test.c')
| -rw-r--r-- | drivers/misc/pci_endpoint_test.c | 87 | 
1 files changed, 58 insertions, 29 deletions
| diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index c38a6083f0a7..3aaaf47fa4ee 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -7,6 +7,7 @@   */  #include <linux/crc32.h> +#include <linux/cleanup.h>  #include <linux/delay.h>  #include <linux/fs.h>  #include <linux/io.h> @@ -84,6 +85,9 @@  #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);  #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ @@ -140,18 +144,6 @@ static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,  	writel(value, test->base + offset);  } -static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test, -					      int bar, int offset) -{ -	return readl(test->bar[bar] + offset); -} - -static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test, -						int bar, u32 offset, u32 value) -{ -	writel(value, test->bar[bar] + offset); -} -  static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)  {  	struct pci_endpoint_test *test = dev_id; @@ -272,31 +264,60 @@ static const u32 bar_test_pattern[] = {  	0xA5A5A5A5,  }; +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) +{ +	memset(write_buf, bar_test_pattern[barno], size); +	memcpy_toio(test->bar[barno] + offset, write_buf, size); + +	memcpy_fromio(read_buf, test->bar[barno] + offset, size); + +	return memcmp(write_buf, read_buf, size); +} +  static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,  				  enum pci_barno barno)  { -	int j; -	u32 val; -	int size; +	int j, bar_size, buf_size, iters, remain; +	void *write_buf __free(kfree) = NULL; +	void *read_buf __free(kfree) = NULL;  	struct pci_dev *pdev = test->pdev;  	if (!test->bar[barno])  		return false; -	size = pci_resource_len(pdev, barno); +	bar_size = pci_resource_len(pdev, barno);  	if (barno == test->test_reg_bar) -		size = 0x4; +		bar_size = 0x4; + +	/* +	 * Allocate a buffer of max size 1MB, and reuse that buffer while +	 * iterating over the whole BAR size (which might be much larger). +	 */ +	buf_size = min(SZ_1M, bar_size); -	for (j = 0; j < size; j += 4) -		pci_endpoint_test_bar_writel(test, barno, j, -					     bar_test_pattern[barno]); +	write_buf = kmalloc(buf_size, GFP_KERNEL); +	if (!write_buf) +		return false; -	for (j = 0; j < size; j += 4) { -		val = pci_endpoint_test_bar_readl(test, barno, j); -		if (val != bar_test_pattern[barno]) +	read_buf = kmalloc(buf_size, GFP_KERNEL); +	if (!read_buf) +		return false; + +	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)) +			return false; + +	remain = bar_size % buf_size; +	if (remain) +		if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * iters, +						 write_buf, read_buf, remain))  			return false; -	}  	return true;  } @@ -824,11 +845,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,  	init_completion(&test->irq_raised);  	mutex_init(&test->mutex); -	if ((dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)) != 0) && -	    dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) { -		dev_err(dev, "Cannot set DMA mask\n"); -		return -EINVAL; -	} +	dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));  	err = pci_enable_device(pdev);  	if (err) { @@ -980,6 +997,15 @@ static const struct pci_endpoint_test_data j721e_data = {  	.irq_type = IRQ_TYPE_MSI,  }; +static const struct pci_endpoint_test_data rk3588_data = { +	.alignment = SZ_64K, +	.irq_type = IRQ_TYPE_MSI, +}; + +/* + * If the controller's Vendor/Device ID are programmable, you may be able to + * use one of the existing entries for testing instead of adding a new one. + */  static const struct pci_device_id pci_endpoint_test_tbl[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),  	  .driver_data = (kernel_ulong_t)&default_data, @@ -1017,6 +1043,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721S2),  	  .driver_data = (kernel_ulong_t)&j721e_data,  	}, +	{ PCI_DEVICE(PCI_VENDOR_ID_ROCKCHIP, PCI_DEVICE_ID_ROCKCHIP_RK3588), +	  .driver_data = (kernel_ulong_t)&rk3588_data, +	},  	{ }  };  MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); |