|
7 | 7 | */ |
8 | 8 |
|
9 | 9 | #include <linux/crc32.h> |
| 10 | +#include <linux/cleanup.h> |
10 | 11 | #include <linux/delay.h> |
11 | 12 | #include <linux/fs.h> |
12 | 13 | #include <linux/io.h> |
|
84 | 85 | #define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025 |
85 | 86 | #define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031 |
86 | 87 |
|
| 88 | +#define PCI_VENDOR_ID_ROCKCHIP 0x1d87 |
| 89 | +#define PCI_DEVICE_ID_ROCKCHIP_RK3588 0x3588 |
| 90 | + |
87 | 91 | static DEFINE_IDA(pci_endpoint_test_ida); |
88 | 92 |
|
89 | 93 | #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, |
140 | 144 | writel(value, test->base + offset); |
141 | 145 | } |
142 | 146 |
|
143 | | -static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test, |
144 | | - int bar, int offset) |
145 | | -{ |
146 | | - return readl(test->bar[bar] + offset); |
147 | | -} |
148 | | - |
149 | | -static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test, |
150 | | - int bar, u32 offset, u32 value) |
151 | | -{ |
152 | | - writel(value, test->bar[bar] + offset); |
153 | | -} |
154 | | - |
155 | 147 | static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id) |
156 | 148 | { |
157 | 149 | struct pci_endpoint_test *test = dev_id; |
@@ -272,31 +264,60 @@ static const u32 bar_test_pattern[] = { |
272 | 264 | 0xA5A5A5A5, |
273 | 265 | }; |
274 | 266 |
|
| 267 | +static int pci_endpoint_test_bar_memcmp(struct pci_endpoint_test *test, |
| 268 | + enum pci_barno barno, int offset, |
| 269 | + void *write_buf, void *read_buf, |
| 270 | + int size) |
| 271 | +{ |
| 272 | + memset(write_buf, bar_test_pattern[barno], size); |
| 273 | + memcpy_toio(test->bar[barno] + offset, write_buf, size); |
| 274 | + |
| 275 | + memcpy_fromio(read_buf, test->bar[barno] + offset, size); |
| 276 | + |
| 277 | + return memcmp(write_buf, read_buf, size); |
| 278 | +} |
| 279 | + |
275 | 280 | static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, |
276 | 281 | enum pci_barno barno) |
277 | 282 | { |
278 | | - int j; |
279 | | - u32 val; |
280 | | - int size; |
| 283 | + int j, bar_size, buf_size, iters, remain; |
| 284 | + void *write_buf __free(kfree) = NULL; |
| 285 | + void *read_buf __free(kfree) = NULL; |
281 | 286 | struct pci_dev *pdev = test->pdev; |
282 | 287 |
|
283 | 288 | if (!test->bar[barno]) |
284 | 289 | return false; |
285 | 290 |
|
286 | | - size = pci_resource_len(pdev, barno); |
| 291 | + bar_size = pci_resource_len(pdev, barno); |
287 | 292 |
|
288 | 293 | if (barno == test->test_reg_bar) |
289 | | - size = 0x4; |
| 294 | + bar_size = 0x4; |
| 295 | + |
| 296 | + /* |
| 297 | + * Allocate a buffer of max size 1MB, and reuse that buffer while |
| 298 | + * iterating over the whole BAR size (which might be much larger). |
| 299 | + */ |
| 300 | + buf_size = min(SZ_1M, bar_size); |
290 | 301 |
|
291 | | - for (j = 0; j < size; j += 4) |
292 | | - pci_endpoint_test_bar_writel(test, barno, j, |
293 | | - bar_test_pattern[barno]); |
| 302 | + write_buf = kmalloc(buf_size, GFP_KERNEL); |
| 303 | + if (!write_buf) |
| 304 | + return false; |
294 | 305 |
|
295 | | - for (j = 0; j < size; j += 4) { |
296 | | - val = pci_endpoint_test_bar_readl(test, barno, j); |
297 | | - if (val != bar_test_pattern[barno]) |
| 306 | + read_buf = kmalloc(buf_size, GFP_KERNEL); |
| 307 | + if (!read_buf) |
| 308 | + return false; |
| 309 | + |
| 310 | + iters = bar_size / buf_size; |
| 311 | + for (j = 0; j < iters; j++) |
| 312 | + if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * j, |
| 313 | + write_buf, read_buf, buf_size)) |
| 314 | + return false; |
| 315 | + |
| 316 | + remain = bar_size % buf_size; |
| 317 | + if (remain) |
| 318 | + if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * iters, |
| 319 | + write_buf, read_buf, remain)) |
298 | 320 | return false; |
299 | | - } |
300 | 321 |
|
301 | 322 | return true; |
302 | 323 | } |
@@ -824,11 +845,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, |
824 | 845 | init_completion(&test->irq_raised); |
825 | 846 | mutex_init(&test->mutex); |
826 | 847 |
|
827 | | - if ((dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)) != 0) && |
828 | | - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) { |
829 | | - dev_err(dev, "Cannot set DMA mask\n"); |
830 | | - return -EINVAL; |
831 | | - } |
| 848 | + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); |
832 | 849 |
|
833 | 850 | err = pci_enable_device(pdev); |
834 | 851 | if (err) { |
@@ -980,6 +997,15 @@ static const struct pci_endpoint_test_data j721e_data = { |
980 | 997 | .irq_type = IRQ_TYPE_MSI, |
981 | 998 | }; |
982 | 999 |
|
| 1000 | +static const struct pci_endpoint_test_data rk3588_data = { |
| 1001 | + .alignment = SZ_64K, |
| 1002 | + .irq_type = IRQ_TYPE_MSI, |
| 1003 | +}; |
| 1004 | + |
| 1005 | +/* |
| 1006 | + * If the controller's Vendor/Device ID are programmable, you may be able to |
| 1007 | + * use one of the existing entries for testing instead of adding a new one. |
| 1008 | + */ |
983 | 1009 | static const struct pci_device_id pci_endpoint_test_tbl[] = { |
984 | 1010 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x), |
985 | 1011 | .driver_data = (kernel_ulong_t)&default_data, |
@@ -1017,6 +1043,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { |
1017 | 1043 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721S2), |
1018 | 1044 | .driver_data = (kernel_ulong_t)&j721e_data, |
1019 | 1045 | }, |
| 1046 | + { PCI_DEVICE(PCI_VENDOR_ID_ROCKCHIP, PCI_DEVICE_ID_ROCKCHIP_RK3588), |
| 1047 | + .driver_data = (kernel_ulong_t)&rk3588_data, |
| 1048 | + }, |
1020 | 1049 | { } |
1021 | 1050 | }; |
1022 | 1051 | MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); |
|
0 commit comments