bzr branch
http://suren.me/webbzr/alps/pcitool
1
by Suren A. Chilingaryan
Initial import |
1 |
/**
|
2 |
*
|
|
3 |
* @file ioctl.c
|
|
4 |
* @author Guillermo Marcus
|
|
5 |
* @date 2009-04-05
|
|
6 |
* @brief Contains the functions handling the different ioctl calls.
|
|
7 |
*
|
|
8 |
*/
|
|
9 |
#include <linux/version.h> |
|
10 |
#include <linux/string.h> |
|
11 |
#include <linux/slab.h> |
|
12 |
#include <linux/types.h> |
|
13 |
#include <linux/init.h> |
|
14 |
#include <linux/module.h> |
|
15 |
#include <linux/pci.h> |
|
16 |
#include <linux/kernel.h> |
|
17 |
#include <linux/errno.h> |
|
18 |
#include <linux/fs.h> |
|
19 |
#include <linux/cdev.h> |
|
20 |
#include <linux/sysfs.h> |
|
21 |
#include <asm/atomic.h> |
|
22 |
#include <linux/pagemap.h> |
|
23 |
#include <linux/spinlock.h> |
|
24 |
#include <linux/list.h> |
|
395
by Suren A. Chilingaryan
Use linux/scatterlist.h instead of asm/scatterlist.h |
25 |
#include <linux/scatterlist.h> |
1
by Suren A. Chilingaryan
Initial import |
26 |
#include <linux/vmalloc.h> |
27 |
#include <linux/stat.h> |
|
28 |
#include <linux/interrupt.h> |
|
29 |
#include <linux/wait.h> |
|
30 |
#include <linux/sched.h> |
|
337
by Suren A. Chilingaryan
Driver versioning |
31 |
#include <linux/iommu.h> |
32 |
||
400
by Suren A. Chilingaryan
Further fixes for out-of-source compilation |
33 |
#include "pcilib/version.h" |
1
by Suren A. Chilingaryan
Initial import |
34 |
|
365
by Suren A. Chilingaryan
Restructure driver headers |
35 |
#include "base.h" |
1
by Suren A. Chilingaryan
Initial import |
36 |
|
37 |
/** Declares a variable of the given type with the given name and copies it from userspace */
|
|
38 |
#define READ_FROM_USER(type, name) \
|
|
39 |
type name; \
|
|
40 |
if ((ret = copy_from_user(&name, (type*)arg, sizeof(name))) != 0) \
|
|
41 |
return -EFAULT;
|
|
42 |
||
43 |
/** Writes back the given variable with the given type to userspace */
|
|
44 |
#define WRITE_TO_USER(type, name) \
|
|
45 |
if ((ret = copy_to_user((type*)arg, &name, sizeof(name))) != 0) \
|
|
46 |
return -EFAULT;
|
|
47 |
||
48 |
/**
|
|
49 |
*
|
|
50 |
* Sets the mmap mode for following mmap() calls.
|
|
51 |
*
|
|
52 |
* @param arg Not a pointer, but either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM
|
|
53 |
*
|
|
54 |
*/
|
|
55 |
static int ioctl_mmap_mode(pcidriver_privdata_t *privdata, unsigned long arg) |
|
56 |
{
|
|
403
by Suren A. Chilingaryan
Allow mapping of arbitrary memory areas |
57 |
if ((arg != PCIDRIVER_MMAP_PCI) && (arg != PCIDRIVER_MMAP_KMEM) && (arg != PCIDRIVER_MMAP_AREA)) |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
58 |
return -EINVAL; |
59 |
||
60 |
/* change the mode */
|
|
61 |
privdata->mmap_mode = arg; |
|
62 |
||
63 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
64 |
}
|
65 |
||
66 |
/**
|
|
67 |
*
|
|
68 |
* Sets the mmap area (BAR) for following mmap() calls.
|
|
69 |
*
|
|
70 |
*/
|
|
71 |
static int ioctl_mmap_area(pcidriver_privdata_t *privdata, unsigned long arg) |
|
72 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
73 |
/* validate input */
|
74 |
if ((arg < PCIDRIVER_BAR0) || (arg > PCIDRIVER_BAR5)) |
|
75 |
return -EINVAL; |
|
76 |
||
77 |
/* change the PCI area to mmap */
|
|
78 |
privdata->mmap_area = arg; |
|
79 |
||
80 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
81 |
}
|
82 |
||
83 |
/**
|
|
84 |
* Reads/writes a byte/word/dword of the device's PCI config.
|
|
85 |
*/
|
|
86 |
static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned int cmd, unsigned long arg) |
|
87 |
{
|
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
88 |
#ifdef PCIDRIVER_DUMMY_DEVICE
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
89 |
return -ENXIO; |
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
90 |
#else /* PCIDRIVER_DUMMY_DEVICE */ |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
91 |
int ret; |
92 |
READ_FROM_USER(pci_cfg_cmd, pci_cmd); |
|
93 |
||
94 |
if (cmd == PCIDRIVER_IOC_PCI_CFG_RD) { |
|
365
by Suren A. Chilingaryan
Restructure driver headers |
95 |
switch (pci_cmd.size) { |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
96 |
case PCIDRIVER_PCI_CFG_SZ_BYTE: |
97 |
ret = pci_read_config_byte( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.byte) ); |
|
98 |
break; |
|
99 |
case PCIDRIVER_PCI_CFG_SZ_WORD: |
|
100 |
ret = pci_read_config_word( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.word) ); |
|
101 |
break; |
|
102 |
case PCIDRIVER_PCI_CFG_SZ_DWORD: |
|
103 |
ret = pci_read_config_dword( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.dword) ); |
|
104 |
break; |
|
105 |
default: |
|
106 |
return -EINVAL; /* Wrong size setting */ |
|
365
by Suren A. Chilingaryan
Restructure driver headers |
107 |
}
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
108 |
} else { |
365
by Suren A. Chilingaryan
Restructure driver headers |
109 |
switch (pci_cmd.size) { |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
110 |
case PCIDRIVER_PCI_CFG_SZ_BYTE: |
111 |
ret = pci_write_config_byte( privdata->pdev, pci_cmd.addr, pci_cmd.val.byte ); |
|
112 |
break; |
|
113 |
case PCIDRIVER_PCI_CFG_SZ_WORD: |
|
114 |
ret = pci_write_config_word( privdata->pdev, pci_cmd.addr, pci_cmd.val.word ); |
|
115 |
break; |
|
116 |
case PCIDRIVER_PCI_CFG_SZ_DWORD: |
|
117 |
ret = pci_write_config_dword( privdata->pdev, pci_cmd.addr, pci_cmd.val.dword ); |
|
118 |
break; |
|
119 |
default: |
|
120 |
return -EINVAL; /* Wrong size setting */ |
|
121 |
break; |
|
365
by Suren A. Chilingaryan
Restructure driver headers |
122 |
}
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
123 |
}
|
124 |
||
125 |
WRITE_TO_USER(pci_cfg_cmd, pci_cmd); |
|
126 |
||
127 |
return 0; |
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
128 |
#endif /* PCIDRIVER_DUMMY_DEVICE */ |
1
by Suren A. Chilingaryan
Initial import |
129 |
}
|
130 |
||
131 |
/**
|
|
132 |
* Gets the PCI information for the device.
|
|
133 |
*/
|
|
134 |
static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg) |
|
135 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
136 |
int ret; |
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
137 |
|
138 |
#ifdef PCIDRIVER_DUMMY_DEVICE
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
139 |
READ_FROM_USER(pcilib_board_info_t, pci_info); |
140 |
memset(&pci_info, 0, sizeof(pci_info)); |
|
141 |
WRITE_TO_USER(pcilib_board_info_t, pci_info); |
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
142 |
#else /* PCIDRIVER_DUMMY_DEVICE */ |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
143 |
int bar; |
144 |
||
145 |
READ_FROM_USER(pcilib_board_info_t, pci_info); |
|
146 |
||
147 |
pci_info.vendor_id = privdata->pdev->vendor; |
|
148 |
pci_info.device_id = privdata->pdev->device; |
|
149 |
pci_info.bus = privdata->pdev->bus->number; |
|
150 |
pci_info.slot = PCI_SLOT(privdata->pdev->devfn); |
|
151 |
pci_info.devfn = privdata->pdev->devfn; |
|
152 |
pci_info.func = PCI_FUNC(privdata->pdev->devfn); |
|
153 |
||
154 |
if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &(pci_info.interrupt_pin))) != 0) |
|
155 |
return ret; |
|
156 |
||
157 |
if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &(pci_info.interrupt_line))) != 0) |
|
158 |
return ret; |
|
159 |
||
160 |
for (bar = 0; bar < 6; bar++) { |
|
161 |
pci_info.bar_start[bar] = pci_resource_start(privdata->pdev, bar); |
|
162 |
pci_info.bar_length[bar] = pci_resource_len(privdata->pdev, bar); |
|
163 |
pci_info.bar_flags[bar] = pci_resource_flags(privdata->pdev, bar); |
|
164 |
}
|
|
165 |
||
166 |
WRITE_TO_USER(pcilib_board_info_t, pci_info); |
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
167 |
#endif /* PCIDRIVER_DUMMY_DEVICE */ |
1
by Suren A. Chilingaryan
Initial import |
168 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
169 |
return 0; |
1
by Suren A. Chilingaryan
Initial import |
170 |
}
|
171 |
||
172 |
/**
|
|
173 |
*
|
|
174 |
* Allocates kernel memory.
|
|
175 |
*
|
|
176 |
* @see pcidriver_kmem_alloc
|
|
177 |
*
|
|
178 |
*/
|
|
179 |
static int ioctl_kmem_alloc(pcidriver_privdata_t *privdata, unsigned long arg) |
|
180 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
181 |
int err, ret; |
182 |
||
183 |
READ_FROM_USER(kmem_handle_t, khandle); |
|
184 |
err = pcidriver_kmem_alloc(privdata, &khandle); |
|
185 |
WRITE_TO_USER(kmem_handle_t, khandle); |
|
186 |
||
187 |
return err; |
|
1
by Suren A. Chilingaryan
Initial import |
188 |
}
|
189 |
||
190 |
/**
|
|
191 |
*
|
|
192 |
* Frees kernel memory.
|
|
193 |
*
|
|
194 |
* @see pcidriver_kmem_free
|
|
195 |
*
|
|
196 |
*/
|
|
197 |
static int ioctl_kmem_free(pcidriver_privdata_t *privdata, unsigned long arg) |
|
198 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
199 |
int ret; |
200 |
READ_FROM_USER(kmem_handle_t, khandle); |
|
201 |
||
202 |
if ((ret = pcidriver_kmem_free(privdata, &khandle)) != 0) |
|
203 |
return ret; |
|
204 |
||
205 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
206 |
}
|
207 |
||
208 |
/**
|
|
209 |
*
|
|
210 |
* Syncs kernel memory.
|
|
211 |
*
|
|
212 |
* @see pcidriver_kmem_sync
|
|
213 |
*
|
|
214 |
*/
|
|
215 |
static int ioctl_kmem_sync(pcidriver_privdata_t *privdata, unsigned long arg) |
|
216 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
217 |
int ret; |
218 |
READ_FROM_USER(kmem_sync_t, ksync); |
|
219 |
||
220 |
if ((ret = pcidriver_kmem_sync(privdata, &ksync)) != 0) |
|
221 |
return ret; |
|
222 |
||
223 |
WRITE_TO_USER(kmem_sync_t, ksync); |
|
224 |
||
225 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
226 |
}
|
227 |
||
228 |
/*
|
|
229 |
*
|
|
230 |
* Maps the given scatter/gather list from memory to PCI bus addresses.
|
|
231 |
*
|
|
232 |
* @see pcidriver_umem_sgmap
|
|
233 |
*
|
|
234 |
*/
|
|
235 |
static int ioctl_umem_sgmap(pcidriver_privdata_t *privdata, unsigned long arg) |
|
236 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
237 |
int ret; |
238 |
READ_FROM_USER(umem_handle_t, uhandle); |
|
239 |
||
240 |
if ((ret = pcidriver_umem_sgmap(privdata, &uhandle)) != 0) |
|
241 |
return ret; |
|
242 |
||
243 |
WRITE_TO_USER(umem_handle_t, uhandle); |
|
244 |
||
245 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
246 |
}
|
247 |
||
248 |
/**
|
|
249 |
*
|
|
250 |
* Unmaps the given scatter/gather list.
|
|
251 |
*
|
|
252 |
* @see pcidriver_umem_sgunmap
|
|
253 |
*
|
|
254 |
*/
|
|
255 |
static int ioctl_umem_sgunmap(pcidriver_privdata_t *privdata, unsigned long arg) |
|
256 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
257 |
int ret; |
258 |
pcidriver_umem_entry_t *umem_entry; |
|
259 |
READ_FROM_USER(umem_handle_t, uhandle); |
|
260 |
||
261 |
/* Find the associated umem_entry for this buffer,
|
|
262 |
* return -EINVAL if the specified handle id is invalid */
|
|
263 |
if ((umem_entry = pcidriver_umem_find_entry_id(privdata, uhandle.handle_id)) == NULL) |
|
264 |
return -EINVAL; |
|
265 |
||
266 |
if ((ret = pcidriver_umem_sgunmap(privdata, umem_entry)) != 0) |
|
267 |
return ret; |
|
268 |
||
269 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
270 |
}
|
271 |
||
272 |
/**
|
|
273 |
*
|
|
274 |
* Copies the scatter/gather list from kernelspace to userspace.
|
|
275 |
*
|
|
276 |
* @see pcidriver_umem_sgget
|
|
277 |
*
|
|
278 |
*/
|
|
279 |
static int ioctl_umem_sgget(pcidriver_privdata_t *privdata, unsigned long arg) |
|
280 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
281 |
int ret; |
282 |
READ_FROM_USER(umem_sglist_t, usglist); |
|
283 |
||
284 |
/* The umem_sglist_t has a pointer to the scatter/gather list itself which
|
|
285 |
* needs to be copied separately. The number of elements is stored in ->nents.
|
|
286 |
* As the list can get very big, we need to use vmalloc. */
|
|
287 |
if ((usglist.sg = vmalloc(usglist.nents * sizeof(umem_sgentry_t))) == NULL) |
|
288 |
return -ENOMEM; |
|
289 |
||
290 |
/* copy array to kernel structure */
|
|
291 |
ret = copy_from_user(usglist.sg, ((umem_sglist_t *)arg)->sg, (usglist.nents)*sizeof(umem_sgentry_t)); |
|
292 |
if (ret) return -EFAULT; |
|
293 |
||
294 |
if ((ret = pcidriver_umem_sgget(privdata, &usglist)) != 0) |
|
295 |
return ret; |
|
296 |
||
297 |
/* write data to user space */
|
|
298 |
ret = copy_to_user(((umem_sglist_t *)arg)->sg, usglist.sg, (usglist.nents)*sizeof(umem_sgentry_t)); |
|
299 |
if (ret) return -EFAULT; |
|
300 |
||
301 |
/* free array memory */
|
|
302 |
vfree(usglist.sg); |
|
303 |
||
304 |
/* restore sg pointer to vma address in user space before copying */
|
|
305 |
usglist.sg = ((umem_sglist_t *)arg)->sg; |
|
306 |
||
307 |
WRITE_TO_USER(umem_sglist_t, usglist); |
|
308 |
||
309 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
310 |
}
|
311 |
||
312 |
/**
|
|
313 |
*
|
|
314 |
* Syncs user memory.
|
|
315 |
*
|
|
316 |
* @see pcidriver_umem_sync
|
|
317 |
*
|
|
318 |
*/
|
|
319 |
static int ioctl_umem_sync(pcidriver_privdata_t *privdata, unsigned long arg) |
|
320 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
321 |
int ret; |
322 |
READ_FROM_USER(umem_handle_t, uhandle); |
|
1
by Suren A. Chilingaryan
Initial import |
323 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
324 |
return pcidriver_umem_sync( privdata, &uhandle ); |
1
by Suren A. Chilingaryan
Initial import |
325 |
}
|
326 |
||
327 |
/**
|
|
328 |
*
|
|
329 |
* Waits for an interrupt
|
|
330 |
*
|
|
331 |
* @param arg Not a pointer, but the irq source to wait for (unsigned int)
|
|
332 |
*
|
|
333 |
*/
|
|
334 |
static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long arg) |
|
335 |
{
|
|
336 |
#ifdef ENABLE_IRQ
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
337 |
int ret; |
338 |
unsigned long timeout; |
|
339 |
unsigned int irq_source; |
|
340 |
unsigned long temp = 0; |
|
341 |
||
342 |
READ_FROM_USER(interrupt_wait_t, irq_handle); |
|
343 |
||
344 |
irq_source = irq_handle.source; |
|
345 |
||
346 |
if (irq_source >= PCIDRIVER_INT_MAXSOURCES) |
|
347 |
return -EFAULT; /* User tried to overrun the IRQ_SOURCES array */ |
|
348 |
||
349 |
timeout = jiffies + (irq_handle.timeout * HZ / 1000000); |
|
350 |
||
351 |
/* Thanks to Joern for the correction and tips! */
|
|
352 |
/* done this way to avoid wrong behaviour (endless loop) of the compiler in AMD platforms */
|
|
353 |
do { |
|
354 |
/* We wait here with an interruptible timeout. This will be interrupted
|
|
1
by Suren A. Chilingaryan
Initial import |
355 |
* by int.c:check_acknowledge_channel() as soon as in interrupt for
|
356 |
* the specified source arrives. */
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
357 |
wait_event_interruptible_timeout( (privdata->irq_queues[irq_source]), (atomic_read(&(privdata->irq_outstanding[irq_source])) > 0), (10*HZ/1000) ); |
358 |
||
359 |
if (atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source])) ) |
|
360 |
atomic_inc( &(privdata->irq_outstanding[irq_source]) ); |
|
361 |
else
|
|
362 |
temp = 1; |
|
363 |
} while ((!temp)&&(jiffies < timeout)); |
|
364 |
||
365 |
if ((temp)&&(irq_handle.count)) { |
|
366 |
while (!atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source]))) temp++; |
|
367 |
atomic_inc( &(privdata->irq_outstanding[irq_source]) ); |
|
368 |
}
|
|
369 |
||
370 |
irq_handle.count = temp; |
|
371 |
||
372 |
WRITE_TO_USER(interrupt_wait_t, irq_handle); |
|
373 |
||
374 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
375 |
#else
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
376 |
mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n"); |
377 |
return -EFAULT; |
|
1
by Suren A. Chilingaryan
Initial import |
378 |
#endif
|
379 |
}
|
|
380 |
||
381 |
/**
|
|
382 |
*
|
|
383 |
* Clears the interrupt wait queue.
|
|
384 |
*
|
|
385 |
* @param arg Not a pointer, but the irq source (unsigned int)
|
|
386 |
* @returns -EFAULT if the user specified an irq source out of range
|
|
387 |
*
|
|
388 |
*/
|
|
389 |
static int ioctl_clear_ioq(pcidriver_privdata_t *privdata, unsigned long arg) |
|
390 |
{
|
|
391 |
#ifdef ENABLE_IRQ
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
392 |
unsigned int irq_source; |
393 |
||
394 |
if (arg >= PCIDRIVER_INT_MAXSOURCES) |
|
395 |
return -EFAULT; |
|
396 |
||
397 |
irq_source = arg; |
|
398 |
atomic_set(&(privdata->irq_outstanding[irq_source]), 0); |
|
399 |
||
400 |
return 0; |
|
1
by Suren A. Chilingaryan
Initial import |
401 |
#else
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
402 |
mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n"); |
403 |
return -EFAULT; |
|
1
by Suren A. Chilingaryan
Initial import |
404 |
#endif
|
405 |
}
|
|
406 |
||
335
by Suren A. Chilingaryan
Enforce 64-bit dma mask from IPEDMA if supported |
407 |
|
408 |
/**
|
|
409 |
*
|
|
337
by Suren A. Chilingaryan
Driver versioning |
410 |
* Gets the device and API versions.
|
411 |
*
|
|
412 |
* @see pcilib_driver_version_t
|
|
413 |
*
|
|
414 |
*/
|
|
415 |
static int ioctl_version(pcidriver_privdata_t *privdata, unsigned long arg) |
|
416 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
417 |
int ret; |
418 |
pcilib_driver_version_t info; |
|
419 |
||
420 |
info = (pcilib_driver_version_t) { |
|
421 |
.version = PCILIB_VERSION, |
|
422 |
.interface = PCIDRIVER_INTERFACE_VERSION, |
|
423 |
.ioctls = PCIDRIVER_IOC_MAX + 1 |
|
424 |
};
|
|
425 |
||
426 |
WRITE_TO_USER(pcilib_driver_version_t, info); |
|
427 |
||
428 |
return 0; |
|
337
by Suren A. Chilingaryan
Driver versioning |
429 |
}
|
430 |
||
431 |
/**
|
|
432 |
*
|
|
433 |
* Gets current device and driver configuration
|
|
434 |
*
|
|
435 |
* @see pcilib_device_state_t
|
|
436 |
*
|
|
437 |
*/
|
|
438 |
static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg) |
|
439 |
{
|
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
440 |
int ret; |
441 |
pcilib_device_state_t info; |
|
337
by Suren A. Chilingaryan
Driver versioning |
442 |
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
443 |
#ifdef PCIDRIVER_DUMMY_DEVICE
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
444 |
memset(&info, 0, sizeof(info)); |
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
445 |
#else /* PCIDRIVER_DUMMY_DEVICE */ |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
446 |
info = (pcilib_device_state_t) { |
447 |
.iommu = iommu_present(privdata->pdev->dev.bus), |
|
448 |
.mps = pcidriver_pcie_get_mps(privdata->pdev), |
|
449 |
.readrq = pcie_get_readrq(privdata->pdev), |
|
450 |
.dma_mask = privdata->pdev->dma_mask |
|
451 |
};
|
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
452 |
#endif /* PCIDRIVER_DUMMY_DEVICE */ |
337
by Suren A. Chilingaryan
Driver versioning |
453 |
|
340
by Suren A. Chilingaryan
Inform user-space about read request size as well |
454 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
455 |
WRITE_TO_USER(pcilib_device_state_t, info); |
337
by Suren A. Chilingaryan
Driver versioning |
456 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
457 |
return 0; |
337
by Suren A. Chilingaryan
Driver versioning |
458 |
}
|
459 |
||
460 |
||
461 |
/**
|
|
462 |
*
|
|
335
by Suren A. Chilingaryan
Enforce 64-bit dma mask from IPEDMA if supported |
463 |
* Sets DMA mask for the following DMA mappings.
|
464 |
*
|
|
465 |
* @param arg Not a pointer, but a number of bits
|
|
466 |
*
|
|
467 |
*/
|
|
468 |
static int ioctl_set_dma_mask(pcidriver_privdata_t *privdata, unsigned long arg) |
|
469 |
{
|
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
470 |
#ifndef PCIDRIVER_DUMMY_DEVICE
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
471 |
int err; |
472 |
||
473 |
if ((arg < 24) || (arg > 64)) |
|
474 |
return -EINVAL; |
|
475 |
||
476 |
err = pci_set_dma_mask(privdata->pdev, DMA_BIT_MASK(arg)); |
|
477 |
if (err < 0) { |
|
478 |
printk(KERN_ERR "pci_set_dma_mask(%lu) failed\n", arg); |
|
479 |
return err; |
|
480 |
}
|
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
481 |
#endif /* ! PCIDRIVER_DUMMY_DEVICE */ |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
482 |
|
483 |
return 0; |
|
338
by Suren A. Chilingaryan
Support setting payload size |
484 |
}
|
485 |
||
486 |
/**
|
|
487 |
*
|
|
488 |
* Sets Max Payload Size.
|
|
489 |
*
|
|
490 |
* @param arg Not a pointer, but payload size in bits
|
|
491 |
*
|
|
492 |
*/
|
|
493 |
static int ioctl_set_mps(pcidriver_privdata_t *privdata, unsigned long arg) |
|
494 |
{
|
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
495 |
#ifndef PCIDRIVER_DUMMY_DEVICE
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
496 |
int err; |
497 |
||
498 |
if ((arg != 128) && (arg != 256) && (arg != 512)) |
|
499 |
return -EINVAL; |
|
500 |
||
501 |
err = pcidriver_pcie_set_mps(privdata->pdev, arg); |
|
502 |
if (err < 0) { |
|
503 |
printk(KERN_ERR "pcie_set_mps(%lu) failed\n", arg); |
|
504 |
return err; |
|
505 |
}
|
|
358
by Suren A. Chilingaryan
Support emulation mode without real hardware |
506 |
#endif /* ! PCIDRIVER_DUMMY_DEVICE */ |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
507 |
|
508 |
return 0; |
|
335
by Suren A. Chilingaryan
Enforce 64-bit dma mask from IPEDMA if supported |
509 |
}
|
510 |
||
511 |
||
1
by Suren A. Chilingaryan
Initial import |
512 |
/**
|
513 |
*
|
|
514 |
* This function handles all ioctl file operations.
|
|
515 |
* Generally, the data of the ioctl is copied from userspace to kernelspace, a separate
|
|
516 |
* function is called to handle the ioctl itself, then the data is copied back to userspace.
|
|
517 |
*
|
|
518 |
* @returns -EFAULT when an invalid memory pointer is passed
|
|
519 |
*
|
|
520 |
*/
|
|
91
by root
Fix few compilation issues with recent kernels |
521 |
long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1
by Suren A. Chilingaryan
Initial import |
522 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
523 |
pcidriver_privdata_t *privdata = filp->private_data; |
524 |
||
525 |
/* Select the appropiate command */
|
|
526 |
switch (cmd) { |
|
527 |
case PCIDRIVER_IOC_MMAP_MODE: |
|
528 |
return ioctl_mmap_mode(privdata, arg); |
|
529 |
||
530 |
case PCIDRIVER_IOC_MMAP_AREA: |
|
531 |
return ioctl_mmap_area(privdata, arg); |
|
532 |
||
533 |
case PCIDRIVER_IOC_PCI_CFG_RD: |
|
534 |
case PCIDRIVER_IOC_PCI_CFG_WR: |
|
535 |
return ioctl_pci_config_read_write(privdata, cmd, arg); |
|
536 |
||
537 |
case PCIDRIVER_IOC_PCI_INFO: |
|
538 |
return ioctl_pci_info(privdata, arg); |
|
539 |
||
540 |
case PCIDRIVER_IOC_KMEM_ALLOC: |
|
541 |
return ioctl_kmem_alloc(privdata, arg); |
|
542 |
||
543 |
case PCIDRIVER_IOC_KMEM_FREE: |
|
544 |
return ioctl_kmem_free(privdata, arg); |
|
545 |
||
546 |
case PCIDRIVER_IOC_KMEM_SYNC: |
|
547 |
return ioctl_kmem_sync(privdata, arg); |
|
548 |
||
549 |
case PCIDRIVER_IOC_UMEM_SGMAP: |
|
550 |
return ioctl_umem_sgmap(privdata, arg); |
|
551 |
||
552 |
case PCIDRIVER_IOC_UMEM_SGUNMAP: |
|
553 |
return ioctl_umem_sgunmap(privdata, arg); |
|
554 |
||
555 |
case PCIDRIVER_IOC_UMEM_SGGET: |
|
556 |
return ioctl_umem_sgget(privdata, arg); |
|
557 |
||
558 |
case PCIDRIVER_IOC_UMEM_SYNC: |
|
559 |
return ioctl_umem_sync(privdata, arg); |
|
560 |
||
561 |
case PCIDRIVER_IOC_WAITI: |
|
562 |
return ioctl_wait_interrupt(privdata, arg); |
|
563 |
||
564 |
case PCIDRIVER_IOC_CLEAR_IOQ: |
|
565 |
return ioctl_clear_ioq(privdata, arg); |
|
566 |
||
567 |
case PCIDRIVER_IOC_VERSION: |
|
568 |
return ioctl_version(privdata, arg); |
|
569 |
||
570 |
case PCIDRIVER_IOC_DEVICE_STATE: |
|
571 |
return ioctl_device_state(privdata, arg); |
|
572 |
||
573 |
case PCIDRIVER_IOC_DMA_MASK: |
|
574 |
return ioctl_set_dma_mask(privdata, arg); |
|
575 |
||
576 |
case PCIDRIVER_IOC_MPS: |
|
577 |
return ioctl_set_mps(privdata, arg); |
|
578 |
||
579 |
default: |
|
580 |
return -EINVAL; |
|
581 |
}
|
|
1
by Suren A. Chilingaryan
Initial import |
582 |
}
|