/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool

« back to all changes in this revision

Viewing changes to driver/dev.c

  • Committer: Suren A. Chilingaryan
  • Date: 2016-03-02 18:37:30 UTC
  • Revision ID: csa@suren.me-20160302183730-nlrgi7h3yuizcizc
Restructure driver headers

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <linux/string.h>
 
2
#include <linux/slab.h>
 
3
#include <linux/types.h>
 
4
#include <linux/init.h>
 
5
#include <linux/module.h>
 
6
#include <linux/pci.h>
 
7
#include <linux/kernel.h>
 
8
#include <linux/errno.h>
 
9
#include <linux/fs.h>
 
10
#include <linux/cdev.h>
 
11
#include <linux/sysfs.h>
 
12
#include <asm/atomic.h>
 
13
#include <linux/pagemap.h>
 
14
#include <linux/spinlock.h>
 
15
#include <linux/list.h>
 
16
#include <asm/scatterlist.h>
 
17
#include <linux/vmalloc.h>
 
18
#include <linux/stat.h>
 
19
#include <linux/interrupt.h>
 
20
#include <linux/wait.h>
 
21
 
 
22
#include "base.h"
 
23
 
 
24
 
 
25
/**
 
26
 *
 
27
 * Called when an application open()s a /dev/fpga*, attaches the private data
 
28
 * with the file pointer.
 
29
 *
 
30
 */
 
31
static int pcidriver_open(struct inode *inode, struct file *filp)
 
32
{
 
33
    pcidriver_privdata_t *privdata;
 
34
 
 
35
    /* Set the private data area for the file */
 
36
    privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev);
 
37
    filp->private_data = privdata;
 
38
 
 
39
    pcidriver_module_get(privdata);
 
40
 
 
41
    return 0;
 
42
}
 
43
 
 
44
/**
 
45
 *
 
46
 * Called when the application close()s the file descriptor. Does nothing at
 
47
 * the moment.
 
48
 *
 
49
 */
 
50
static int pcidriver_release(struct inode *inode, struct file *filp)
 
51
{
 
52
    pcidriver_privdata_t *privdata;
 
53
 
 
54
    /* Get the private data area */
 
55
    privdata = filp->private_data;
 
56
 
 
57
    pcidriver_module_put(privdata);
 
58
 
 
59
    return 0;
 
60
}
 
61
 
 
62
 
 
63
/*************************************************************************/
 
64
/* Internal driver functions */
 
65
static int pcidriver_mmap_bar(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar)
 
66
{
 
67
#ifdef PCIDRIVER_DUMMY_DEVICE
 
68
    return -ENXIO;
 
69
#else /* PCIDRIVER_DUMMY_DEVICE */
 
70
    int ret = 0;
 
71
    unsigned long bar_addr;
 
72
    unsigned long bar_length, vma_size;
 
73
    unsigned long bar_flags;
 
74
 
 
75
    mod_info_dbg("Entering mmap_pci\n");
 
76
 
 
77
 
 
78
    /* Get info of the BAR to be mapped */
 
79
    bar_addr = pci_resource_start(privdata->pdev, bar);
 
80
    bar_length = pci_resource_len(privdata->pdev, bar);
 
81
    bar_flags = pci_resource_flags(privdata->pdev, bar);
 
82
 
 
83
    /* Check sizes */
 
84
    vma_size = (vmap->vm_end - vmap->vm_start);
 
85
 
 
86
    if ((vma_size != bar_length) &&
 
87
            ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
 
88
        mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size );
 
89
        return -EINVAL;
 
90
    }
 
91
 
 
92
    if (bar_flags & IORESOURCE_IO) {
 
93
        /* Unlikely case, we will mmap a IO region */
 
94
 
 
95
        /* IO regions are never cacheable */
 
96
        vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
 
97
 
 
98
        /* Map the BAR */
 
99
        ret = io_remap_pfn_range(vmap, vmap->vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vmap->vm_page_prot);
 
100
    } else {
 
101
        /* Normal case, mmap a memory region */
 
102
 
 
103
        /* Ensure this VMA is non-cached, if it is not flaged as prefetchable.
 
104
         * If it is prefetchable, caching is allowed and will give better performance.
 
105
         * This should be set properly by the BIOS, but we want to be sure. */
 
106
        /* adapted from drivers/char/mem.c, mmap function. */
 
107
 
 
108
        /* Setting noncached disables MTRR registers, and we want to use them.
 
109
         * So we take this code out. This can lead to caching problems if and only if
 
110
         * the System BIOS set something wrong. Check LDDv3, page 425.
 
111
         */
 
112
 
 
113
//                if (!(bar_flags & IORESOURCE_PREFETCH))
 
114
//                      vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
 
115
 
 
116
 
 
117
        /* Map the BAR */
 
118
        ret = remap_pfn_range(vmap, vmap->vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vmap->vm_page_prot);
 
119
    }
 
120
 
 
121
    if (ret) {
 
122
        mod_info("remap_pfn_range failed\n");
 
123
        return -EAGAIN;
 
124
    }
 
125
 
 
126
    return 0;   /* success */
 
127
#endif /* PCIDRIVER_DUMMY_DEVICE */
 
128
}
 
129
 
 
130
/**
 
131
 *
 
132
 * This function is the entry point for mmap() and calls either pcidriver_mmap_bar
 
133
 * or pcidriver_mmap_kmem
 
134
 *
 
135
 * @see pcidriver_mmap_bar
 
136
 * @see pcidriver_mmap_kmem
 
137
 *
 
138
 */
 
139
static int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma)
 
140
{
 
141
    pcidriver_privdata_t *privdata;
 
142
    int ret = 0, bar;
 
143
 
 
144
    mod_info_dbg("Entering mmap\n");
 
145
 
 
146
    /* Get the private data area */
 
147
    privdata = filp->private_data;
 
148
 
 
149
    /* Check the current mmap mode */
 
150
    switch (privdata->mmap_mode) {
 
151
     case PCIDRIVER_MMAP_PCI:
 
152
        bar = privdata->mmap_area;
 
153
        if ((bar < 0)||(bar > 5)) {
 
154
            mod_info("Attempted to mmap a PCI area with the wrong mmap_area value: %d\n",privdata->mmap_area);
 
155
            return -EINVAL;
 
156
        }
 
157
        ret = pcidriver_mmap_bar(privdata, vma, bar);
 
158
        break;
 
159
    case PCIDRIVER_MMAP_KMEM:
 
160
        ret = pcidriver_mmap_kmem(privdata, vma);
 
161
        break;
 
162
    default:
 
163
        mod_info( "Invalid mmap_mode value (%d)\n",privdata->mmap_mode );
 
164
        return -EINVAL;                 /* Invalid parameter (mode) */
 
165
    }
 
166
 
 
167
    return ret;
 
168
}
 
169
 
 
170
static struct file_operations pcidriver_fops = {
 
171
    .owner = THIS_MODULE,
 
172
    .unlocked_ioctl = pcidriver_ioctl,
 
173
    .mmap = pcidriver_mmap,
 
174
    .open = pcidriver_open,
 
175
    .release = pcidriver_release,
 
176
};
 
177
 
 
178
const struct file_operations *pcidriver_get_fops(void)
 
179
{
 
180
    return &pcidriver_fops;
 
181
}
 
182
 
 
183
 
 
184
void pcidriver_module_get(pcidriver_privdata_t *privdata) {
 
185
    atomic_inc(&(privdata->refs));
 
186
//    mod_info("Ref: %i\n", atomic_read(&(privdata->refs)));
 
187
}
 
188
 
 
189
void pcidriver_module_put(pcidriver_privdata_t *privdata) {
 
190
    if (atomic_add_negative(-1, &(privdata->refs))) {
 
191
        atomic_inc(&(privdata->refs));
 
192
        mod_info("Reference counting error...");
 
193
    } else {
 
194
//      mod_info("Unref: %i\n", atomic_read(&(privdata->refs)));
 
195
    }
 
196
}