aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/endpoint/functions/pci-epf-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/endpoint/functions/pci-epf-test.c')
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-test.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
new file mode 100644
index 000000000000..53fff8030337
--- /dev/null
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -0,0 +1,510 @@
1/**
2 * Test driver to test endpoint functionality
3 *
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/crc32.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/pci_ids.h>
26#include <linux/random.h>
27
28#include <linux/pci-epc.h>
29#include <linux/pci-epf.h>
30#include <linux/pci_regs.h>
31
32#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
33#define COMMAND_RAISE_MSI_IRQ BIT(1)
34#define MSI_NUMBER_SHIFT 2
35#define MSI_NUMBER_MASK (0x3f << MSI_NUMBER_SHIFT)
36#define COMMAND_READ BIT(8)
37#define COMMAND_WRITE BIT(9)
38#define COMMAND_COPY BIT(10)
39
40#define STATUS_READ_SUCCESS BIT(0)
41#define STATUS_READ_FAIL BIT(1)
42#define STATUS_WRITE_SUCCESS BIT(2)
43#define STATUS_WRITE_FAIL BIT(3)
44#define STATUS_COPY_SUCCESS BIT(4)
45#define STATUS_COPY_FAIL BIT(5)
46#define STATUS_IRQ_RAISED BIT(6)
47#define STATUS_SRC_ADDR_INVALID BIT(7)
48#define STATUS_DST_ADDR_INVALID BIT(8)
49
50#define TIMER_RESOLUTION 1
51
52static struct workqueue_struct *kpcitest_workqueue;
53
54struct pci_epf_test {
55 void *reg[6];
56 struct pci_epf *epf;
57 struct delayed_work cmd_handler;
58};
59
60struct pci_epf_test_reg {
61 u32 magic;
62 u32 command;
63 u32 status;
64 u64 src_addr;
65 u64 dst_addr;
66 u32 size;
67 u32 checksum;
68} __packed;
69
70static struct pci_epf_header test_header = {
71 .vendorid = PCI_ANY_ID,
72 .deviceid = PCI_ANY_ID,
73 .baseclass_code = PCI_CLASS_OTHERS,
74 .interrupt_pin = PCI_INTERRUPT_INTA,
75};
76
77static int bar_size[] = { 512, 1024, 16384, 131072, 1048576 };
78
79static int pci_epf_test_copy(struct pci_epf_test *epf_test)
80{
81 int ret;
82 void __iomem *src_addr;
83 void __iomem *dst_addr;
84 phys_addr_t src_phys_addr;
85 phys_addr_t dst_phys_addr;
86 struct pci_epf *epf = epf_test->epf;
87 struct device *dev = &epf->dev;
88 struct pci_epc *epc = epf->epc;
89 struct pci_epf_test_reg *reg = epf_test->reg[0];
90
91 src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
92 if (!src_addr) {
93 dev_err(dev, "failed to allocate source address\n");
94 reg->status = STATUS_SRC_ADDR_INVALID;
95 ret = -ENOMEM;
96 goto err;
97 }
98
99 ret = pci_epc_map_addr(epc, src_phys_addr, reg->src_addr, reg->size);
100 if (ret) {
101 dev_err(dev, "failed to map source address\n");
102 reg->status = STATUS_SRC_ADDR_INVALID;
103 goto err_src_addr;
104 }
105
106 dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size);
107 if (!dst_addr) {
108 dev_err(dev, "failed to allocate destination address\n");
109 reg->status = STATUS_DST_ADDR_INVALID;
110 ret = -ENOMEM;
111 goto err_src_map_addr;
112 }
113
114 ret = pci_epc_map_addr(epc, dst_phys_addr, reg->dst_addr, reg->size);
115 if (ret) {
116 dev_err(dev, "failed to map destination address\n");
117 reg->status = STATUS_DST_ADDR_INVALID;
118 goto err_dst_addr;
119 }
120
121 memcpy(dst_addr, src_addr, reg->size);
122
123 pci_epc_unmap_addr(epc, dst_phys_addr);
124
125err_dst_addr:
126 pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size);
127
128err_src_map_addr:
129 pci_epc_unmap_addr(epc, src_phys_addr);
130
131err_src_addr:
132 pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size);
133
134err:
135 return ret;
136}
137
138static int pci_epf_test_read(struct pci_epf_test *epf_test)
139{
140 int ret;
141 void __iomem *src_addr;
142 void *buf;
143 u32 crc32;
144 phys_addr_t phys_addr;
145 struct pci_epf *epf = epf_test->epf;
146 struct device *dev = &epf->dev;
147 struct pci_epc *epc = epf->epc;
148 struct pci_epf_test_reg *reg = epf_test->reg[0];
149
150 src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
151 if (!src_addr) {
152 dev_err(dev, "failed to allocate address\n");
153 reg->status = STATUS_SRC_ADDR_INVALID;
154 ret = -ENOMEM;
155 goto err;
156 }
157
158 ret = pci_epc_map_addr(epc, phys_addr, reg->src_addr, reg->size);
159 if (ret) {
160 dev_err(dev, "failed to map address\n");
161 reg->status = STATUS_SRC_ADDR_INVALID;
162 goto err_addr;
163 }
164
165 buf = kzalloc(reg->size, GFP_KERNEL);
166 if (!buf) {
167 ret = -ENOMEM;
168 goto err_map_addr;
169 }
170
171 memcpy(buf, src_addr, reg->size);
172
173 crc32 = crc32_le(~0, buf, reg->size);
174 if (crc32 != reg->checksum)
175 ret = -EIO;
176
177 kfree(buf);
178
179err_map_addr:
180 pci_epc_unmap_addr(epc, phys_addr);
181
182err_addr:
183 pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
184
185err:
186 return ret;
187}
188
189static int pci_epf_test_write(struct pci_epf_test *epf_test)
190{
191 int ret;
192 void __iomem *dst_addr;
193 void *buf;
194 phys_addr_t phys_addr;
195 struct pci_epf *epf = epf_test->epf;
196 struct device *dev = &epf->dev;
197 struct pci_epc *epc = epf->epc;
198 struct pci_epf_test_reg *reg = epf_test->reg[0];
199
200 dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
201 if (!dst_addr) {
202 dev_err(dev, "failed to allocate address\n");
203 reg->status = STATUS_DST_ADDR_INVALID;
204 ret = -ENOMEM;
205 goto err;
206 }
207
208 ret = pci_epc_map_addr(epc, phys_addr, reg->dst_addr, reg->size);
209 if (ret) {
210 dev_err(dev, "failed to map address\n");
211 reg->status = STATUS_DST_ADDR_INVALID;
212 goto err_addr;
213 }
214
215 buf = kzalloc(reg->size, GFP_KERNEL);
216 if (!buf) {
217 ret = -ENOMEM;
218 goto err_map_addr;
219 }
220
221 get_random_bytes(buf, reg->size);
222 reg->checksum = crc32_le(~0, buf, reg->size);
223
224 memcpy(dst_addr, buf, reg->size);
225
226 /*
227 * wait 1ms inorder for the write to complete. Without this delay L3
228 * error in observed in the host system.
229 */
230 mdelay(1);
231
232 kfree(buf);
233
234err_map_addr:
235 pci_epc_unmap_addr(epc, phys_addr);
236
237err_addr:
238 pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
239
240err:
241 return ret;
242}
243
244static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test)
245{
246 u8 irq;
247 u8 msi_count;
248 struct pci_epf *epf = epf_test->epf;
249 struct pci_epc *epc = epf->epc;
250 struct pci_epf_test_reg *reg = epf_test->reg[0];
251
252 reg->status |= STATUS_IRQ_RAISED;
253 msi_count = pci_epc_get_msi(epc);
254 irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT;
255 if (irq > msi_count || msi_count <= 0)
256 pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0);
257 else
258 pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq);
259}
260
261static void pci_epf_test_cmd_handler(struct work_struct *work)
262{
263 int ret;
264 u8 irq;
265 u8 msi_count;
266 struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
267 cmd_handler.work);
268 struct pci_epf *epf = epf_test->epf;
269 struct pci_epc *epc = epf->epc;
270 struct pci_epf_test_reg *reg = epf_test->reg[0];
271
272 if (!reg->command)
273 goto reset_handler;
274
275 if (reg->command & COMMAND_RAISE_LEGACY_IRQ) {
276 reg->status = STATUS_IRQ_RAISED;
277 pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0);
278 goto reset_handler;
279 }
280
281 if (reg->command & COMMAND_WRITE) {
282 ret = pci_epf_test_write(epf_test);
283 if (ret)
284 reg->status |= STATUS_WRITE_FAIL;
285 else
286 reg->status |= STATUS_WRITE_SUCCESS;
287 pci_epf_test_raise_irq(epf_test);
288 goto reset_handler;
289 }
290
291 if (reg->command & COMMAND_READ) {
292 ret = pci_epf_test_read(epf_test);
293 if (!ret)
294 reg->status |= STATUS_READ_SUCCESS;
295 else
296 reg->status |= STATUS_READ_FAIL;
297 pci_epf_test_raise_irq(epf_test);
298 goto reset_handler;
299 }
300
301 if (reg->command & COMMAND_COPY) {
302 ret = pci_epf_test_copy(epf_test);
303 if (!ret)
304 reg->status |= STATUS_COPY_SUCCESS;
305 else
306 reg->status |= STATUS_COPY_FAIL;
307 pci_epf_test_raise_irq(epf_test);
308 goto reset_handler;
309 }
310
311 if (reg->command & COMMAND_RAISE_MSI_IRQ) {
312 msi_count = pci_epc_get_msi(epc);
313 irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT;
314 if (irq > msi_count || msi_count <= 0)
315 goto reset_handler;
316 reg->status = STATUS_IRQ_RAISED;
317 pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq);
318 goto reset_handler;
319 }
320
321reset_handler:
322 reg->command = 0;
323
324 queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
325 msecs_to_jiffies(1));
326}
327
328static void pci_epf_test_linkup(struct pci_epf *epf)
329{
330 struct pci_epf_test *epf_test = epf_get_drvdata(epf);
331
332 queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
333 msecs_to_jiffies(1));
334}
335
336static void pci_epf_test_unbind(struct pci_epf *epf)
337{
338 struct pci_epf_test *epf_test = epf_get_drvdata(epf);
339 struct pci_epc *epc = epf->epc;
340 int bar;
341
342 cancel_delayed_work(&epf_test->cmd_handler);
343 pci_epc_stop(epc);
344 for (bar = BAR_0; bar <= BAR_5; bar++) {
345 if (epf_test->reg[bar]) {
346 pci_epf_free_space(epf, epf_test->reg[bar], bar);
347 pci_epc_clear_bar(epc, bar);
348 }
349 }
350}
351
352static int pci_epf_test_set_bar(struct pci_epf *epf)
353{
354 int flags;
355 int bar;
356 int ret;
357 struct pci_epf_bar *epf_bar;
358 struct pci_epc *epc = epf->epc;
359 struct device *dev = &epf->dev;
360 struct pci_epf_test *epf_test = epf_get_drvdata(epf);
361
362 flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32;
363 if (sizeof(dma_addr_t) == 0x8)
364 flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
365
366 for (bar = BAR_0; bar <= BAR_5; bar++) {
367 epf_bar = &epf->bar[bar];
368 ret = pci_epc_set_bar(epc, bar, epf_bar->phys_addr,
369 epf_bar->size, flags);
370 if (ret) {
371 pci_epf_free_space(epf, epf_test->reg[bar], bar);
372 dev_err(dev, "failed to set BAR%d\n", bar);
373 if (bar == BAR_0)
374 return ret;
375 }
376 }
377
378 return 0;
379}
380
381static int pci_epf_test_alloc_space(struct pci_epf *epf)
382{
383 struct pci_epf_test *epf_test = epf_get_drvdata(epf);
384 struct device *dev = &epf->dev;
385 void *base;
386 int bar;
387
388 base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
389 BAR_0);
390 if (!base) {
391 dev_err(dev, "failed to allocated register space\n");
392 return -ENOMEM;
393 }
394 epf_test->reg[0] = base;
395
396 for (bar = BAR_1; bar <= BAR_5; bar++) {
397 base = pci_epf_alloc_space(epf, bar_size[bar - 1], bar);
398 if (!base)
399 dev_err(dev, "failed to allocate space for BAR%d\n",
400 bar);
401 epf_test->reg[bar] = base;
402 }
403
404 return 0;
405}
406
407static int pci_epf_test_bind(struct pci_epf *epf)
408{
409 int ret;
410 struct pci_epf_header *header = epf->header;
411 struct pci_epc *epc = epf->epc;
412 struct device *dev = &epf->dev;
413
414 if (WARN_ON_ONCE(!epc))
415 return -EINVAL;
416
417 ret = pci_epc_write_header(epc, header);
418 if (ret) {
419 dev_err(dev, "configuration header write failed\n");
420 return ret;
421 }
422
423 ret = pci_epf_test_alloc_space(epf);
424 if (ret)
425 return ret;
426
427 ret = pci_epf_test_set_bar(epf);
428 if (ret)
429 return ret;
430
431 ret = pci_epc_set_msi(epc, epf->msi_interrupts);
432 if (ret)
433 return ret;
434
435 return 0;
436}
437
438static int pci_epf_test_probe(struct pci_epf *epf)
439{
440 struct pci_epf_test *epf_test;
441 struct device *dev = &epf->dev;
442
443 epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
444 if (!epf_test)
445 return -ENOMEM;
446
447 epf->header = &test_header;
448 epf_test->epf = epf;
449
450 INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
451
452 epf_set_drvdata(epf, epf_test);
453 return 0;
454}
455
456static int pci_epf_test_remove(struct pci_epf *epf)
457{
458 struct pci_epf_test *epf_test = epf_get_drvdata(epf);
459
460 kfree(epf_test);
461 return 0;
462}
463
464static struct pci_epf_ops ops = {
465 .unbind = pci_epf_test_unbind,
466 .bind = pci_epf_test_bind,
467 .linkup = pci_epf_test_linkup,
468};
469
470static const struct pci_epf_device_id pci_epf_test_ids[] = {
471 {
472 .name = "pci_epf_test",
473 },
474 {},
475};
476
477static struct pci_epf_driver test_driver = {
478 .driver.name = "pci_epf_test",
479 .probe = pci_epf_test_probe,
480 .remove = pci_epf_test_remove,
481 .id_table = pci_epf_test_ids,
482 .ops = &ops,
483 .owner = THIS_MODULE,
484};
485
486static int __init pci_epf_test_init(void)
487{
488 int ret;
489
490 kpcitest_workqueue = alloc_workqueue("kpcitest",
491 WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
492 ret = pci_epf_register_driver(&test_driver);
493 if (ret) {
494 pr_err("failed to register pci epf test driver --> %d\n", ret);
495 return ret;
496 }
497
498 return 0;
499}
500module_init(pci_epf_test_init);
501
502static void __exit pci_epf_test_exit(void)
503{
504 pci_epf_unregister_driver(&test_driver);
505}
506module_exit(pci_epf_test_exit);
507
508MODULE_DESCRIPTION("PCI EPF TEST DRIVER");
509MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
510MODULE_LICENSE("GPL v2");