/alps/pcitool

To get this branch, use:
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
}