Blame view

drivers/misc/pci_endpoint_test.c 24.9 KB
6b1baefec   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
2
3
4
5
6
  /**
   * Host side test driver to test endpoint functionality
   *
   * Copyright (C) 2017 Texas Instruments
   * Author: Kishon Vijay Abraham I <kishon@ti.com>
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
7
8
9
10
11
12
13
14
15
16
17
18
19
   */
  
  #include <linux/crc32.h>
  #include <linux/delay.h>
  #include <linux/fs.h>
  #include <linux/io.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
  #include <linux/miscdevice.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
  #include <linux/random.h>
  #include <linux/slab.h>
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
20
  #include <linux/uaccess.h>
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
21
22
23
24
25
26
  #include <linux/pci.h>
  #include <linux/pci_ids.h>
  
  #include <linux/pci_regs.h>
  
  #include <uapi/linux/pcitest.h>
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
27
  #define DRV_MODULE_NAME				"pci-endpoint-test"
e03327122   Gustavo Pimentel   pci_endpoint_test...
28
  #define IRQ_TYPE_UNDEFINED			-1
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
29
30
  #define IRQ_TYPE_LEGACY				0
  #define IRQ_TYPE_MSI				1
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
31
  #define IRQ_TYPE_MSIX				2
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
32
33
34
35
36
37
  
  #define PCI_ENDPOINT_TEST_MAGIC			0x0
  
  #define PCI_ENDPOINT_TEST_COMMAND		0x4
  #define COMMAND_RAISE_LEGACY_IRQ		BIT(0)
  #define COMMAND_RAISE_MSI_IRQ			BIT(1)
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
38
  #define COMMAND_RAISE_MSIX_IRQ			BIT(2)
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  #define COMMAND_READ				BIT(3)
  #define COMMAND_WRITE				BIT(4)
  #define COMMAND_COPY				BIT(5)
  
  #define PCI_ENDPOINT_TEST_STATUS		0x8
  #define STATUS_READ_SUCCESS			BIT(0)
  #define STATUS_READ_FAIL			BIT(1)
  #define STATUS_WRITE_SUCCESS			BIT(2)
  #define STATUS_WRITE_FAIL			BIT(3)
  #define STATUS_COPY_SUCCESS			BIT(4)
  #define STATUS_COPY_FAIL			BIT(5)
  #define STATUS_IRQ_RAISED			BIT(6)
  #define STATUS_SRC_ADDR_INVALID			BIT(7)
  #define STATUS_DST_ADDR_INVALID			BIT(8)
  
  #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR	0x0c
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
55
56
57
58
  #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR	0x10
  
  #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR	0x14
  #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR	0x18
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
59
60
61
62
63
  #define PCI_ENDPOINT_TEST_SIZE			0x1c
  #define PCI_ENDPOINT_TEST_CHECKSUM		0x20
  
  #define PCI_ENDPOINT_TEST_IRQ_TYPE		0x24
  #define PCI_ENDPOINT_TEST_IRQ_NUMBER		0x28
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
64

cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
65
66
  #define PCI_ENDPOINT_TEST_FLAGS			0x2c
  #define FLAG_USE_DMA				BIT(0)
6546ae299   Kishon Vijay Abraham I   misc: pci_endpoin...
67
  #define PCI_DEVICE_ID_TI_J721E			0xb00d
5bb04b192   Kishon Vijay Abraham I   misc: pci_endpoin...
68
  #define PCI_DEVICE_ID_TI_AM654			0xb00c
dd149cd72   Xiaowei Bao   misc: pci_endpoin...
69
  #define PCI_DEVICE_ID_LS1028A			0x82c0
6b8ab4213   Xiaowei Bao   misc: pci_endpoin...
70
  #define PCI_DEVICE_ID_LS1088A			0x80c0
322b3d229   Xiaowei Bao   misc: pci_endpoin...
71
  #define PCI_DEVICE_ID_LX2160A			0x8d80
14e7bb86e   Hou Zhiqiang   misc: pci_endpoin...
72
  #define PCI_DEVICE_ID_LX2162A			0x8d88
5836dc7b9   Richard Zhu   MLK-24012-11 misc...
73
74
  #define PCI_DEVICE_ID_IMX8			0x0808
  #define PCI_DEVICE_ID_IMX6			0x0606
5bb04b192   Kishon Vijay Abraham I   misc: pci_endpoin...
75
76
77
  
  #define is_am654_pci_dev(pdev)		\
  		((pdev)->device == PCI_DEVICE_ID_TI_AM654)
cfb824ddd   Lad Prabhakar   misc: pci_endpoin...
78
79
  #define PCI_DEVICE_ID_RENESAS_R8A774A1		0x0028
  #define PCI_DEVICE_ID_RENESAS_R8A774B1		0x002b
b03025c57   Lad Prabhakar   misc: pci_endpoin...
80
  #define PCI_DEVICE_ID_RENESAS_R8A774C0		0x002d
a63c5f3db   Lad Prabhakar   misc: pci_endpoin...
81
  #define PCI_DEVICE_ID_RENESAS_R8A774E1		0x0025
b03025c57   Lad Prabhakar   misc: pci_endpoin...
82

2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
83
84
85
86
  static DEFINE_IDA(pci_endpoint_test_ida);
  
  #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
  					    miscdev)
0c8a5f9d8   Kishon Vijay Abraham I   misc: pci_endpoin...
87
88
89
90
  
  static bool no_msi;
  module_param(no_msi, bool, 0444);
  MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
91
92
  static int irq_type = IRQ_TYPE_MSI;
  module_param(irq_type, int, 0444);
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
93
  MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)");
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
94

2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
95
96
97
98
99
100
101
102
103
104
105
106
  enum pci_barno {
  	BAR_0,
  	BAR_1,
  	BAR_2,
  	BAR_3,
  	BAR_4,
  	BAR_5,
  };
  
  struct pci_endpoint_test {
  	struct pci_dev	*pdev;
  	void __iomem	*base;
c9c13ba42   Denis Efremov   PCI: Add PCI_STD_...
107
  	void __iomem	*bar[PCI_STD_NUM_BARS];
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
108
109
  	struct completion irq_raised;
  	int		last_irq;
b7636e816   Kishon Vijay Abraham I   misc: pci_endpoin...
110
  	int		num_irqs;
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
111
  	int		irq_type;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
112
113
114
  	/* mutex to protect the ioctls */
  	struct mutex	mutex;
  	struct miscdevice miscdev;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
115
  	enum pci_barno test_reg_bar;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
116
  	size_t alignment;
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
117
  	const char *name;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
118
  };
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
119
120
  struct pci_endpoint_test_data {
  	enum pci_barno test_reg_bar;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
121
  	size_t alignment;
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
122
  	int irq_type;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
123
  };
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
  					  u32 offset)
  {
  	return readl(test->base + offset);
  }
  
  static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,
  					    u32 offset, u32 value)
  {
  	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;
  	u32 reg;
  
  	reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
  	if (reg & STATUS_IRQ_RAISED) {
  		test->last_irq = irq;
  		complete(&test->irq_raised);
  		reg &= ~STATUS_IRQ_RAISED;
  	}
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS,
  				 reg);
  
  	return IRQ_HANDLED;
  }
e03327122   Gustavo Pimentel   pci_endpoint_test...
164
165
166
167
168
  static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
  {
  	struct pci_dev *pdev = test->pdev;
  
  	pci_free_irq_vectors(pdev);
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
169
  	test->irq_type = IRQ_TYPE_UNDEFINED;
e03327122   Gustavo Pimentel   pci_endpoint_test...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  }
  
  static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
  						int type)
  {
  	int irq = -1;
  	struct pci_dev *pdev = test->pdev;
  	struct device *dev = &pdev->dev;
  	bool res = true;
  
  	switch (type) {
  	case IRQ_TYPE_LEGACY:
  		irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
  		if (irq < 0)
  			dev_err(dev, "Failed to get Legacy interrupt
  ");
  		break;
  	case 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
  ");
  		break;
  	case 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
  ");
  		break;
  	default:
  		dev_err(dev, "Invalid IRQ type selected
  ");
  	}
  
  	if (irq < 0) {
  		irq = 0;
  		res = false;
  	}
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
208
209
  
  	test->irq_type = type;
e03327122   Gustavo Pimentel   pci_endpoint_test...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  	test->num_irqs = irq;
  
  	return res;
  }
  
  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);
  
  	test->num_irqs = 0;
  }
  
  static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
  {
  	int i;
  	int err;
  	struct pci_dev *pdev = test->pdev;
  	struct device *dev = &pdev->dev;
  
  	for (i = 0; i < test->num_irqs; i++) {
  		err = devm_request_irq(dev, pci_irq_vector(pdev, i),
  				       pci_endpoint_test_irqhandler,
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
237
  				       IRQF_SHARED, test->name, test);
e03327122   Gustavo Pimentel   pci_endpoint_test...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  		if (err)
  			goto fail;
  	}
  
  	return true;
  
  fail:
  	switch (irq_type) {
  	case IRQ_TYPE_LEGACY:
  		dev_err(dev, "Failed to request IRQ %d for Legacy
  ",
  			pci_irq_vector(pdev, i));
  		break;
  	case IRQ_TYPE_MSI:
  		dev_err(dev, "Failed to request IRQ %d for MSI %d
  ",
  			pci_irq_vector(pdev, i),
  			i + 1);
  		break;
  	case IRQ_TYPE_MSIX:
  		dev_err(dev, "Failed to request IRQ %d for MSI-X %d
  ",
  			pci_irq_vector(pdev, i),
  			i + 1);
  		break;
  	}
  
  	return false;
  }
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
267
268
269
270
271
272
  static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
  				  enum pci_barno barno)
  {
  	int j;
  	u32 val;
  	int size;
cda370ec6   Kishon Vijay Abraham I   misc: pci_endpoin...
273
  	struct pci_dev *pdev = test->pdev;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
274
275
276
  
  	if (!test->bar[barno])
  		return false;
cda370ec6   Kishon Vijay Abraham I   misc: pci_endpoin...
277
  	size = pci_resource_len(pdev, barno);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
278

834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
279
280
  	if (barno == test->test_reg_bar)
  		size = 0x4;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	for (j = 0; j < size; j += 4)
  		pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0);
  
  	for (j = 0; j < size; j += 4) {
  		val = pci_endpoint_test_bar_readl(test, barno, j);
  		if (val != 0xA0A0A0A0)
  			return false;
  	}
  
  	return true;
  }
  
  static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
  {
  	u32 val;
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
296
297
298
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
  				 IRQ_TYPE_LEGACY);
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
299
300
301
302
303
304
305
306
307
308
309
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
  				 COMMAND_RAISE_LEGACY_IRQ);
  	val = wait_for_completion_timeout(&test->irq_raised,
  					  msecs_to_jiffies(1000));
  	if (!val)
  		return false;
  
  	return true;
  }
  
  static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
310
  				       u16 msi_num, bool msix)
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
311
312
313
  {
  	u32 val;
  	struct pci_dev *pdev = test->pdev;
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
314
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
315
316
  				 msix == false ? IRQ_TYPE_MSI :
  				 IRQ_TYPE_MSIX);
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
317
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
318
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
319
320
  				 msix == false ? COMMAND_RAISE_MSI_IRQ :
  				 COMMAND_RAISE_MSIX_IRQ);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
321
322
323
324
  	val = wait_for_completion_timeout(&test->irq_raised,
  					  msecs_to_jiffies(1000));
  	if (!val)
  		return false;
ecc57efe9   Gustavo Pimentel   misc: pci_endpoin...
325
  	if (pci_irq_vector(pdev, msi_num - 1) == test->last_irq)
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
326
327
328
329
  		return true;
  
  	return false;
  }
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
330
331
  static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
  				   unsigned long arg)
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
332
  {
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
333
  	struct pci_endpoint_test_xfer_param param;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
334
335
336
  	bool ret = false;
  	void *src_addr;
  	void *dst_addr;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
337
338
339
  	u32 flags = 0;
  	bool use_dma;
  	size_t size;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
340
341
342
343
  	dma_addr_t src_phys_addr;
  	dma_addr_t dst_phys_addr;
  	struct pci_dev *pdev = test->pdev;
  	struct device *dev = &pdev->dev;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
344
345
346
347
348
349
  	void *orig_src_addr;
  	dma_addr_t orig_src_phys_addr;
  	void *orig_dst_addr;
  	dma_addr_t orig_dst_phys_addr;
  	size_t offset;
  	size_t alignment = test->alignment;
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
350
  	int irq_type = test->irq_type;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
351
352
  	u32 src_crc32;
  	u32 dst_crc32;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
353
  	int err;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
354

cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
355
356
357
358
359
360
361
362
  	err = copy_from_user(&param, (void __user *)arg, sizeof(param));
  	if (err) {
  		dev_err(dev, "Failed to get transfer param
  ");
  		return false;
  	}
  
  	size = param.size;
343dc693f   Dan Carpenter   misc: pci_endpoin...
363
364
  	if (size > SIZE_MAX - alignment)
  		goto err;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
365
366
367
  	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
  	if (use_dma)
  		flags |= FLAG_USE_DMA;
e03327122   Gustavo Pimentel   pci_endpoint_test...
368
369
370
371
372
  	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
  		dev_err(dev, "Invalid IRQ type option
  ");
  		goto err;
  	}
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
373
  	orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
374
  	if (!orig_src_addr) {
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
375
376
  		dev_err(dev, "Failed to allocate source buffer
  ");
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
377
378
379
  		ret = false;
  		goto err;
  	}
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
380
381
382
383
384
385
386
387
388
  	get_random_bytes(orig_src_addr, size + alignment);
  	orig_src_phys_addr = dma_map_single(dev, orig_src_addr,
  					    size + alignment, DMA_TO_DEVICE);
  	if (dma_mapping_error(dev, orig_src_phys_addr)) {
  		dev_err(dev, "failed to map source buffer address
  ");
  		ret = false;
  		goto err_src_phys_addr;
  	}
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
389
390
391
392
393
394
395
396
  	if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) {
  		src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment);
  		offset = src_phys_addr - orig_src_phys_addr;
  		src_addr = orig_src_addr + offset;
  	} else {
  		src_phys_addr = orig_src_phys_addr;
  		src_addr = orig_src_addr;
  	}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
397
398
399
400
401
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
  				 lower_32_bits(src_phys_addr));
  
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
  				 upper_32_bits(src_phys_addr));
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
402
  	src_crc32 = crc32_le(~0, src_addr, size);
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
403
  	orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL);
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
404
  	if (!orig_dst_addr) {
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
405
406
  		dev_err(dev, "Failed to allocate destination address
  ");
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
407
  		ret = false;
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
408
409
410
411
412
413
414
415
416
417
  		goto err_dst_addr;
  	}
  
  	orig_dst_phys_addr = dma_map_single(dev, orig_dst_addr,
  					    size + alignment, DMA_FROM_DEVICE);
  	if (dma_mapping_error(dev, orig_dst_phys_addr)) {
  		dev_err(dev, "failed to map destination buffer address
  ");
  		ret = false;
  		goto err_dst_phys_addr;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
418
419
420
421
422
423
424
425
426
  	}
  
  	if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) {
  		dst_phys_addr = PTR_ALIGN(orig_dst_phys_addr, alignment);
  		offset = dst_phys_addr - orig_dst_phys_addr;
  		dst_addr = orig_dst_addr + offset;
  	} else {
  		dst_phys_addr = orig_dst_phys_addr;
  		dst_addr = orig_dst_addr;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
427
428
429
430
431
432
433
434
435
  	}
  
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
  				 lower_32_bits(dst_phys_addr));
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
  				 upper_32_bits(dst_phys_addr));
  
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
  				 size);
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
436
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
437
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
438
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
439
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
440
  				 COMMAND_COPY);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
441
442
  
  	wait_for_completion(&test->irq_raised);
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
443
444
  	dma_unmap_single(dev, orig_dst_phys_addr, size + alignment,
  			 DMA_FROM_DEVICE);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
445
446
447
  	dst_crc32 = crc32_le(~0, dst_addr, size);
  	if (dst_crc32 == src_crc32)
  		ret = true;
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
448
449
  err_dst_phys_addr:
  	kfree(orig_dst_addr);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
450

0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
451
452
453
454
455
456
  err_dst_addr:
  	dma_unmap_single(dev, orig_src_phys_addr, size + alignment,
  			 DMA_TO_DEVICE);
  
  err_src_phys_addr:
  	kfree(orig_src_addr);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
457
458
459
460
  
  err:
  	return ret;
  }
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
461
462
  static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
  				    unsigned long arg)
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
463
  {
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
464
  	struct pci_endpoint_test_xfer_param param;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
465
  	bool ret = false;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
466
467
  	u32 flags = 0;
  	bool use_dma;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
468
469
470
471
472
  	u32 reg;
  	void *addr;
  	dma_addr_t phys_addr;
  	struct pci_dev *pdev = test->pdev;
  	struct device *dev = &pdev->dev;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
473
474
475
476
  	void *orig_addr;
  	dma_addr_t orig_phys_addr;
  	size_t offset;
  	size_t alignment = test->alignment;
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
477
  	int irq_type = test->irq_type;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
478
  	size_t size;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
479
  	u32 crc32;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
480
  	int err;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
481

cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
482
483
484
485
486
487
488
489
  	err = copy_from_user(&param, (void __user *)arg, sizeof(param));
  	if (err != 0) {
  		dev_err(dev, "Failed to get transfer param
  ");
  		return false;
  	}
  
  	size = param.size;
343dc693f   Dan Carpenter   misc: pci_endpoin...
490
491
  	if (size > SIZE_MAX - alignment)
  		goto err;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
492
493
494
  	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
  	if (use_dma)
  		flags |= FLAG_USE_DMA;
e03327122   Gustavo Pimentel   pci_endpoint_test...
495
496
497
498
499
  	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
  		dev_err(dev, "Invalid IRQ type option
  ");
  		goto err;
  	}
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
500
  	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
501
  	if (!orig_addr) {
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
502
503
  		dev_err(dev, "Failed to allocate address
  ");
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
504
505
506
  		ret = false;
  		goto err;
  	}
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
507
508
509
510
511
512
513
514
515
516
  	get_random_bytes(orig_addr, size + alignment);
  
  	orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
  					DMA_TO_DEVICE);
  	if (dma_mapping_error(dev, orig_phys_addr)) {
  		dev_err(dev, "failed to map source buffer address
  ");
  		ret = false;
  		goto err_phys_addr;
  	}
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
517
518
519
520
521
522
523
524
  	if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
  		phys_addr =  PTR_ALIGN(orig_phys_addr, alignment);
  		offset = phys_addr - orig_phys_addr;
  		addr = orig_addr + offset;
  	} else {
  		phys_addr = orig_phys_addr;
  		addr = orig_addr;
  	}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
525
526
527
528
529
530
531
532
533
534
  	crc32 = crc32_le(~0, addr, size);
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
  				 crc32);
  
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
  				 lower_32_bits(phys_addr));
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
  				 upper_32_bits(phys_addr));
  
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
535
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
536
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
537
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
538
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
539
  				 COMMAND_READ);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
540
541
542
543
544
545
  
  	wait_for_completion(&test->irq_raised);
  
  	reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
  	if (reg & STATUS_READ_SUCCESS)
  		ret = true;
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
546
547
548
549
550
  	dma_unmap_single(dev, orig_phys_addr, size + alignment,
  			 DMA_TO_DEVICE);
  
  err_phys_addr:
  	kfree(orig_addr);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
551
552
553
554
  
  err:
  	return ret;
  }
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
555
556
  static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
  				   unsigned long arg)
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
557
  {
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
558
  	struct pci_endpoint_test_xfer_param param;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
559
  	bool ret = false;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
560
561
562
  	u32 flags = 0;
  	bool use_dma;
  	size_t size;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
563
564
565
566
  	void *addr;
  	dma_addr_t phys_addr;
  	struct pci_dev *pdev = test->pdev;
  	struct device *dev = &pdev->dev;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
567
568
569
570
  	void *orig_addr;
  	dma_addr_t orig_phys_addr;
  	size_t offset;
  	size_t alignment = test->alignment;
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
571
  	int irq_type = test->irq_type;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
572
  	u32 crc32;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
573
  	int err;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
574

cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
575
576
577
578
579
580
581
582
  	err = copy_from_user(&param, (void __user *)arg, sizeof(param));
  	if (err) {
  		dev_err(dev, "Failed to get transfer param
  ");
  		return false;
  	}
  
  	size = param.size;
343dc693f   Dan Carpenter   misc: pci_endpoin...
583
584
  	if (size > SIZE_MAX - alignment)
  		goto err;
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
585
586
587
  	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
  	if (use_dma)
  		flags |= FLAG_USE_DMA;
e03327122   Gustavo Pimentel   pci_endpoint_test...
588
589
590
591
592
  	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
  		dev_err(dev, "Invalid IRQ type option
  ");
  		goto err;
  	}
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
593
  	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
594
  	if (!orig_addr) {
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
595
596
  		dev_err(dev, "Failed to allocate destination address
  ");
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
597
598
599
  		ret = false;
  		goto err;
  	}
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
600
601
602
603
604
605
606
607
  	orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
  					DMA_FROM_DEVICE);
  	if (dma_mapping_error(dev, orig_phys_addr)) {
  		dev_err(dev, "failed to map source buffer address
  ");
  		ret = false;
  		goto err_phys_addr;
  	}
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
608
609
610
611
612
613
614
615
  	if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
  		phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
  		offset = phys_addr - orig_phys_addr;
  		addr = orig_addr + offset;
  	} else {
  		phys_addr = orig_phys_addr;
  		addr = orig_addr;
  	}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
616
617
618
619
620
621
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
  				 lower_32_bits(phys_addr));
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
  				 upper_32_bits(phys_addr));
  
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
cf376b4b5   Kishon Vijay Abraham I   misc: pci_endpoin...
622
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
623
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
624
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
625
  	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
e8817de7f   Gustavo Pimentel   pci-epf-test/pci_...
626
  				 COMMAND_WRITE);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
627
628
  
  	wait_for_completion(&test->irq_raised);
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
629
630
  	dma_unmap_single(dev, orig_phys_addr, size + alignment,
  			 DMA_FROM_DEVICE);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
631
632
633
  	crc32 = crc32_le(~0, addr, size);
  	if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
  		ret = true;
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
634
635
  err_phys_addr:
  	kfree(orig_addr);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
636
637
638
  err:
  	return ret;
  }
475007f9c   Kishon Vijay Abraham I   misc: pci_endpoin...
639
640
641
642
643
644
  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;
  }
e03327122   Gustavo Pimentel   pci_endpoint_test...
645
646
647
648
649
650
651
652
653
654
655
  static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
  				      int req_irq_type)
  {
  	struct pci_dev *pdev = test->pdev;
  	struct device *dev = &pdev->dev;
  
  	if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) {
  		dev_err(dev, "Invalid IRQ type option
  ");
  		return false;
  	}
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
656
  	if (test->irq_type == req_irq_type)
e03327122   Gustavo Pimentel   pci_endpoint_test...
657
658
659
660
661
662
663
664
665
666
  		return true;
  
  	pci_endpoint_test_release_irq(test);
  	pci_endpoint_test_free_irq_vectors(test);
  
  	if (!pci_endpoint_test_alloc_irq_vectors(test, req_irq_type))
  		goto err;
  
  	if (!pci_endpoint_test_request_irq(test))
  		goto err;
e03327122   Gustavo Pimentel   pci_endpoint_test...
667
668
669
670
  	return true;
  
  err:
  	pci_endpoint_test_free_irq_vectors(test);
e03327122   Gustavo Pimentel   pci_endpoint_test...
671
672
  	return false;
  }
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
673
674
675
676
677
678
  static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
  				    unsigned long arg)
  {
  	int ret = -EINVAL;
  	enum pci_barno bar;
  	struct pci_endpoint_test *test = to_endpoint_test(file->private_data);
5bb04b192   Kishon Vijay Abraham I   misc: pci_endpoin...
679
  	struct pci_dev *pdev = test->pdev;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
680
681
682
683
684
685
686
  
  	mutex_lock(&test->mutex);
  	switch (cmd) {
  	case PCITEST_BAR:
  		bar = arg;
  		if (bar < 0 || bar > 5)
  			goto ret;
5bb04b192   Kishon Vijay Abraham I   misc: pci_endpoin...
687
688
  		if (is_am654_pci_dev(pdev) && bar == BAR_0)
  			goto ret;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
689
690
691
692
693
694
  		ret = pci_endpoint_test_bar(test, bar);
  		break;
  	case PCITEST_LEGACY_IRQ:
  		ret = pci_endpoint_test_legacy_irq(test);
  		break;
  	case PCITEST_MSI:
c2e00e310   Gustavo Pimentel   pci-epf-test/pci_...
695
696
  	case PCITEST_MSIX:
  		ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
697
698
699
700
701
702
703
704
705
706
  		break;
  	case PCITEST_WRITE:
  		ret = pci_endpoint_test_write(test, arg);
  		break;
  	case PCITEST_READ:
  		ret = pci_endpoint_test_read(test, arg);
  		break;
  	case PCITEST_COPY:
  		ret = pci_endpoint_test_copy(test, arg);
  		break;
e03327122   Gustavo Pimentel   pci_endpoint_test...
707
708
709
710
711
712
  	case PCITEST_SET_IRQTYPE:
  		ret = pci_endpoint_test_set_irq(test, arg);
  		break;
  	case PCITEST_GET_IRQTYPE:
  		ret = irq_type;
  		break;
475007f9c   Kishon Vijay Abraham I   misc: pci_endpoin...
713
714
715
  	case PCITEST_CLEAR_IRQ:
  		ret = pci_endpoint_test_clear_irq(test);
  		break;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  	}
  
  ret:
  	mutex_unlock(&test->mutex);
  	return ret;
  }
  
  static const struct file_operations pci_endpoint_test_fops = {
  	.owner = THIS_MODULE,
  	.unlocked_ioctl = pci_endpoint_test_ioctl,
  };
  
  static int pci_endpoint_test_probe(struct pci_dev *pdev,
  				   const struct pci_device_id *ent)
  {
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
731
  	int err;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
732
  	int id;
6b443e5c8   Kishon Vijay Abraham I   misc: pci_endpoin...
733
  	char name[24];
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
734
735
736
737
  	enum pci_barno bar;
  	void __iomem *base;
  	struct device *dev = &pdev->dev;
  	struct pci_endpoint_test *test;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
738
739
  	struct pci_endpoint_test_data *data;
  	enum pci_barno test_reg_bar = BAR_0;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
740
741
742
743
744
745
746
747
  	struct miscdevice *misc_device;
  
  	if (pci_is_bridge(pdev))
  		return -ENODEV;
  
  	test = devm_kzalloc(dev, sizeof(*test), GFP_KERNEL);
  	if (!test)
  		return -ENOMEM;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
748
  	test->test_reg_bar = 0;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
749
  	test->alignment = 0;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
750
  	test->pdev = pdev;
b2ba9225e   Kishon Vijay Abraham I   misc: pci_endpoin...
751
  	test->irq_type = IRQ_TYPE_UNDEFINED;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
752

9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
753
754
  	if (no_msi)
  		irq_type = IRQ_TYPE_LEGACY;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
755
  	data = (struct pci_endpoint_test_data *)ent->driver_data;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
756
  	if (data) {
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
757
  		test_reg_bar = data->test_reg_bar;
8f2206645   Kishon Vijay Abraham I   misc: pci_endpoin...
758
  		test->test_reg_bar = test_reg_bar;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
759
  		test->alignment = data->alignment;
9133e394d   Gustavo Pimentel   pci-epf-test/pci_...
760
  		irq_type = data->irq_type;
13107c606   Kishon Vijay Abraham I   misc: pci_endpoin...
761
  	}
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
762

2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
763
764
  	init_completion(&test->irq_raised);
  	mutex_init(&test->mutex);
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
765
766
767
768
769
770
  	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
  ");
  		return -EINVAL;
  	}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
  	err = pci_enable_device(pdev);
  	if (err) {
  		dev_err(dev, "Cannot enable PCI device
  ");
  		return err;
  	}
  
  	err = pci_request_regions(pdev, DRV_MODULE_NAME);
  	if (err) {
  		dev_err(dev, "Cannot obtain PCI resources
  ");
  		goto err_disable_pdev;
  	}
  
  	pci_set_master(pdev);
096ee6ebd   Xiongfeng Wang   misc: pci_endpoin...
786
787
  	if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type)) {
  		err = -EINVAL;
e03327122   Gustavo Pimentel   pci_endpoint_test...
788
  		goto err_disable_irq;
096ee6ebd   Xiongfeng Wang   misc: pci_endpoin...
789
  	}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
790

c9c13ba42   Denis Efremov   PCI: Add PCI_STD_...
791
  	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
16b17cad0   Niklas Cassel   misc: pci_endpoin...
792
793
794
  		if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
  			base = pci_ioremap_bar(pdev, bar);
  			if (!base) {
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
795
796
  				dev_err(dev, "Failed to read BAR%d
  ", bar);
16b17cad0   Niklas Cassel   misc: pci_endpoin...
797
798
799
  				WARN_ON(bar == test_reg_bar);
  			}
  			test->bar[bar] = base;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
800
  		}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
801
  	}
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
802
  	test->base = test->bar[test_reg_bar];
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
803
  	if (!test->base) {
80068c936   Kishon Vijay Abraham I   misc: pci_endpoin...
804
  		err = -ENOMEM;
834b90519   Kishon Vijay Abraham I   misc: pci_endpoin...
805
806
807
  		dev_err(dev, "Cannot perform PCI test without BAR%d
  ",
  			test_reg_bar);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
808
809
810
811
812
813
814
  		goto err_iounmap;
  	}
  
  	pci_set_drvdata(pdev, test);
  
  	id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL);
  	if (id < 0) {
80068c936   Kishon Vijay Abraham I   misc: pci_endpoin...
815
  		err = id;
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
816
817
  		dev_err(dev, "Unable to get id
  ");
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
818
819
820
821
  		goto err_iounmap;
  	}
  
  	snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id);
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
822
823
824
825
826
  	test->name = kstrdup(name, GFP_KERNEL);
  	if (!test->name) {
  		err = -ENOMEM;
  		goto err_ida_remove;
  	}
096ee6ebd   Xiongfeng Wang   misc: pci_endpoin...
827
828
  	if (!pci_endpoint_test_request_irq(test)) {
  		err = -EINVAL;
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
829
  		goto err_kfree_test_name;
096ee6ebd   Xiongfeng Wang   misc: pci_endpoin...
830
  	}
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
831

2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
832
833
  	misc_device = &test->miscdev;
  	misc_device->minor = MISC_DYNAMIC_MINOR;
139838fff   Kishon Vijay Abraham I   misc: pci_endpoin...
834
835
836
  	misc_device->name = kstrdup(name, GFP_KERNEL);
  	if (!misc_device->name) {
  		err = -ENOMEM;
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
837
  		goto err_release_irq;
139838fff   Kishon Vijay Abraham I   misc: pci_endpoin...
838
  	}
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
839
840
841
842
  	misc_device->fops = &pci_endpoint_test_fops,
  
  	err = misc_register(misc_device);
  	if (err) {
0e52ea611   Gustavo Pimentel   misc: pci_endpoin...
843
844
  		dev_err(dev, "Failed to register device
  ");
139838fff   Kishon Vijay Abraham I   misc: pci_endpoin...
845
  		goto err_kfree_name;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
846
847
848
  	}
  
  	return 0;
139838fff   Kishon Vijay Abraham I   misc: pci_endpoin...
849
850
  err_kfree_name:
  	kfree(misc_device->name);
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
851
852
853
854
855
  err_release_irq:
  	pci_endpoint_test_release_irq(test);
  
  err_kfree_test_name:
  	kfree(test->name);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
856
857
858
859
  err_ida_remove:
  	ida_simple_remove(&pci_endpoint_test_ida, id);
  
  err_iounmap:
c9c13ba42   Denis Efremov   PCI: Add PCI_STD_...
860
  	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
861
862
863
  		if (test->bar[bar])
  			pci_iounmap(pdev, test->bar[bar]);
  	}
e03327122   Gustavo Pimentel   pci_endpoint_test...
864
865
  err_disable_irq:
  	pci_endpoint_test_free_irq_vectors(test);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
  	pci_release_regions(pdev);
  
  err_disable_pdev:
  	pci_disable_device(pdev);
  
  	return err;
  }
  
  static void pci_endpoint_test_remove(struct pci_dev *pdev)
  {
  	int id;
  	enum pci_barno bar;
  	struct pci_endpoint_test *test = pci_get_drvdata(pdev);
  	struct miscdevice *misc_device = &test->miscdev;
  
  	if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1)
  		return;
a2db2663b   Dan Carpenter   misc: pci_endpoin...
883
884
  	if (id < 0)
  		return;
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
885
886
  
  	misc_deregister(&test->miscdev);
139838fff   Kishon Vijay Abraham I   misc: pci_endpoin...
887
  	kfree(misc_device->name);
c2be14ab3   Kishon Vijay Abraham I   misc: pci_endpoin...
888
  	kfree(test->name);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
889
  	ida_simple_remove(&pci_endpoint_test_ida, id);
c9c13ba42   Denis Efremov   PCI: Add PCI_STD_...
890
  	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
891
892
893
  		if (test->bar[bar])
  			pci_iounmap(pdev, test->bar[bar]);
  	}
e03327122   Gustavo Pimentel   pci_endpoint_test...
894
895
896
  
  	pci_endpoint_test_release_irq(test);
  	pci_endpoint_test_free_irq_vectors(test);
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
897
898
899
  	pci_release_regions(pdev);
  	pci_disable_device(pdev);
  }
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
900
901
902
903
904
  static const struct pci_endpoint_test_data default_data = {
  	.test_reg_bar = BAR_0,
  	.alignment = SZ_4K,
  	.irq_type = IRQ_TYPE_MSI,
  };
5836dc7b9   Richard Zhu   MLK-24012-11 misc...
905
906
907
908
909
  static const struct pci_endpoint_test_data imx6q_data = {
  	.test_reg_bar = BAR_3,
  	.alignment = SZ_64K,
  	.irq_type = IRQ_TYPE_MSI,
  };
5bb04b192   Kishon Vijay Abraham I   misc: pci_endpoin...
910
911
912
913
914
  static const struct pci_endpoint_test_data am654_data = {
  	.test_reg_bar = BAR_2,
  	.alignment = SZ_64K,
  	.irq_type = IRQ_TYPE_MSI,
  };
6546ae299   Kishon Vijay Abraham I   misc: pci_endpoin...
915
916
917
918
  static const struct pci_endpoint_test_data j721e_data = {
  	.alignment = 256,
  	.irq_type = IRQ_TYPE_MSI,
  };
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
919
  static const struct pci_device_id pci_endpoint_test_tbl[] = {
0a121f9bc   Kishon Vijay Abraham I   misc: pci_endpoin...
920
921
922
923
924
925
  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
  	  .driver_data = (kernel_ulong_t)&default_data,
  	},
  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x),
  	  .driver_data = (kernel_ulong_t)&default_data,
  	},
09fb37b35   Hou Zhiqiang   misc: pci_endpoin...
926
927
928
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0),
  	  .driver_data = (kernel_ulong_t)&default_data,
  	},
dd149cd72   Xiaowei Bao   misc: pci_endpoin...
929
930
931
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1028A),
  	  .driver_data = (kernel_ulong_t)&default_data,
  	},
09fb37b35   Hou Zhiqiang   misc: pci_endpoin...
932
933
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A),
  	  .driver_data = (kernel_ulong_t)&default_data,
322b3d229   Xiaowei Bao   misc: pci_endpoin...
934
935
936
  	},
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LX2160A),
  	  .driver_data = (kernel_ulong_t)&default_data,
09fb37b35   Hou Zhiqiang   misc: pci_endpoin...
937
  	},
14e7bb86e   Hou Zhiqiang   misc: pci_endpoin...
938
939
940
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LX2162A),
  	  .driver_data = (kernel_ulong_t)&default_data,
  	},
d1d177e78   Richard Zhu   LF-2681-2 misc: p...
941
942
943
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_IMX8),
  	  .driver_data = (kernel_ulong_t)&default_data,
  	},
5836dc7b9   Richard Zhu   MLK-24012-11 misc...
944
945
946
  	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_IMX6),
  	  .driver_data = (kernel_ulong_t)&imx6q_data
  	},
1f418f465   Gustavo Pimentel   PCI: Add Synopsys...
947
  	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
5bb04b192   Kishon Vijay Abraham I   misc: pci_endpoin...
948
949
950
  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
  	  .driver_data = (kernel_ulong_t)&am654_data
  	},
cfb824ddd   Lad Prabhakar   misc: pci_endpoin...
951
952
953
  	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),},
  	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
  	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
a63c5f3db   Lad Prabhakar   misc: pci_endpoin...
954
  	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
6546ae299   Kishon Vijay Abraham I   misc: pci_endpoin...
955
956
957
  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
  	  .driver_data = (kernel_ulong_t)&j721e_data,
  	},
2c156ac71   Kishon Vijay Abraham I   misc: Add host si...
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  	{ }
  };
  MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
  
  static struct pci_driver pci_endpoint_test_driver = {
  	.name		= DRV_MODULE_NAME,
  	.id_table	= pci_endpoint_test_tbl,
  	.probe		= pci_endpoint_test_probe,
  	.remove		= pci_endpoint_test_remove,
  };
  module_pci_driver(pci_endpoint_test_driver);
  
  MODULE_DESCRIPTION("PCI ENDPOINT TEST HOST DRIVER");
  MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
  MODULE_LICENSE("GPL v2");