4
* @brief This file contains the functions providing the SysFS-interface.
5
* @author Guillermo Marcus
9
#include <linux/version.h>
10
#include <linux/string.h>
11
#include <linux/types.h>
12
#include <linux/list.h>
13
#include <linux/interrupt.h>
14
#include <linux/pci.h>
15
#include <linux/cdev.h>
16
#include <linux/wait.h>
18
#include <linux/pagemap.h>
19
#include <linux/kernel.h>
23
#include "pciDriver.h"
29
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry);
30
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry);
34
* Initializes the sysfs attributes for an kmem/umem-entry
37
static int _pcidriver_sysfs_initialize(pcidriver_privdata_t *privdata,
39
struct class_device_attribute *sysfs_attr,
40
const char *fmtstring,
41
SYSFS_GET_FUNCTION((*callback)))
43
/* sysfs attributes for kmem buffers don’t make sense before 2.6.13, as
44
we have no mmap support before */
45
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
48
/* allocate space for the name of the attribute */
49
snprintf(namebuffer, sizeof(namebuffer), fmtstring, id);
51
if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL)
54
sysfs_attr->attr.mode = S_IRUGO;
55
sysfs_attr->attr.owner = THIS_MODULE;
56
sysfs_attr->show = callback;
57
sysfs_attr->store = NULL;
59
/* name and add attribute */
60
if (class_device_create_file(privdata->class_dev, sysfs_attr) != 0)
61
return -ENXIO; /* Device not configured. Not the really best choice, but hm. */
67
int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
69
return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry);
72
int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
74
return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "umem%d", pcidriver_show_umem_entry);
79
* Removes the file from sysfs and frees the allocated (kstrdup()) memory.
82
void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_attribute *sysfs_attr)
84
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
85
class_device_remove_file(privdata->class_dev, sysfs_attr);
86
kfree(sysfs_attr->attr.name);
90
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry)
92
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
93
// pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data;
95
/* As we can be sure that attr.name contains a filename which we
96
* created (see _pcidriver_sysfs_initialize), we do not need to have
97
* sanity checks but can directly call simple_strtol() */
98
int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10);
100
return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id);
106
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry)
108
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
110
pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data;
112
return snprintf(buf, PAGE_SIZE, "I am in the umem_entry show function, class_device_kobj_name: %s\n", cls->kobj.name);
121
SYSFS_GET_FUNCTION(pcidriver_show_irq_count)
123
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
125
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count);
128
SYSFS_GET_FUNCTION(pcidriver_show_irq_queues)
130
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
133
/* output will be truncated to PAGE_SIZE */
134
offset = snprintf(buf, PAGE_SIZE, "Queue\tOutstanding IRQs\n");
135
for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++)
136
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%d\t%d\n", i, atomic_read(&(privdata->irq_outstanding[i])) );
138
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
142
SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode)
144
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
146
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode);
149
SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode)
151
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
154
/* Set the mmap-mode if it is either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM */
155
if (sscanf(buf, "%d", &mode) == 1 &&
156
(mode == PCIDRIVER_MMAP_PCI || mode == PCIDRIVER_MMAP_KMEM))
157
privdata->mmap_mode = mode;
162
SYSFS_GET_FUNCTION(pcidriver_show_mmap_area)
164
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
166
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area);
169
SYSFS_SET_FUNCTION(pcidriver_store_mmap_area)
171
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
174
sscanf(buf, "%d", &temp);
176
if ((temp >= PCIDRIVER_BAR0) && (temp <= PCIDRIVER_BAR5))
177
privdata->mmap_area = temp;
182
SYSFS_GET_FUNCTION(pcidriver_show_kmem_count)
184
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
186
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count)));
189
SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc)
191
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
192
kmem_handle_t kmem_handle;
194
/* FIXME: guillermo: is validation of parsing an unsigned int enough? */
195
if (sscanf(buf, "%lu", &kmem_handle.size) == 1)
196
pcidriver_kmem_alloc(privdata, &kmem_handle);
201
SYSFS_SET_FUNCTION(pcidriver_store_kmem_free)
203
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
205
pcidriver_kmem_entry_t *kmem_entry;
207
/* Parse the ID of the kernel memory to be freed, check bounds */
208
if (sscanf(buf, "%u", &id) != 1 ||
209
(id >= atomic_read(&(privdata->kmem_count))))
212
if ((kmem_entry = pcidriver_kmem_find_entry_id(privdata,id)) == NULL)
215
pcidriver_kmem_free_entry(privdata, kmem_entry );
220
SYSFS_GET_FUNCTION(pcidriver_show_kbuffers)
222
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
224
struct list_head *ptr;
225
pcidriver_kmem_entry_t *entry;
227
/* print the header */
228
offset += snprintf(buf, PAGE_SIZE, "kbuf#\tcpu addr\tsize\n");
230
spin_lock(&(privdata->kmemlist_lock));
231
list_for_each(ptr, &(privdata->kmem_list)) {
232
entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
234
/* print entry info */
235
if (offset > PAGE_SIZE) {
236
spin_unlock( &(privdata->kmemlist_lock) );
240
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%08lx\t%lu\n", entry->id, (unsigned long)(entry->dma_handle), entry->size );
243
spin_unlock(&(privdata->kmemlist_lock));
245
/* output will be truncated to PAGE_SIZE */
246
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
249
SYSFS_GET_FUNCTION(pcidriver_show_umappings)
252
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
253
struct list_head *ptr;
254
pcidriver_umem_entry_t *entry;
256
/* print the header */
257
offset += snprintf(buf, PAGE_SIZE, "umap#\tn_pages\tsg_ents\n");
259
spin_lock( &(privdata->umemlist_lock) );
260
list_for_each( ptr, &(privdata->umem_list) ) {
261
entry = list_entry(ptr, pcidriver_umem_entry_t, list );
263
/* print entry info */
264
if (offset > PAGE_SIZE) {
265
spin_unlock( &(privdata->umemlist_lock) );
269
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%lu\t%lu\n", entry->id,
270
(unsigned long)(entry->nr_pages), (unsigned long)(entry->nents));
273
spin_unlock( &(privdata->umemlist_lock) );
275
/* output will be truncated to PAGE_SIZE */
276
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
279
SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap)
281
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
282
pcidriver_umem_entry_t *umem_entry;
285
if (sscanf(buf, "%u", &id) != 1 ||
286
(id >= atomic_read(&(privdata->umem_count))))
289
if ((umem_entry = pcidriver_umem_find_entry_id(privdata, id)) == NULL)
292
pcidriver_umem_sgunmap(privdata, umem_entry);