2 * vme_window.c - PCI-VME window management
4 * Copyright (c) 2009 Sebastien Dugue
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
13 * This file provides the PCI-VME bridge window management support:
15 * - Window creation and deletion
16 * - Mapping creation and removal
17 * - Procfs interface to windows and mappings information
20 #include <linux/list.h>
21 #include <linux/pci.h>
22 #include <asm/uaccess.h>
25 #include "vme_bridge.h"
29 * struct window - Hardware window descriptor.
30 * @lock: Mutex protecting the descriptor
31 * @active: Flag indicating whether the window is in use
32 * @rsrc: PCI bus resource of the window
33 * @desc: This physical window descriptor
34 * @mappings: List of mappings using this window
35 * @users: Number of users of this window
37 * This structure holds the information concerning hardware
45 struct vme_mapping desc
;
46 struct list_head mappings
;
51 struct window window_table
[TSI148_NUM_OUT_WINDOWS
];
54 * struct vme_taskinfo - Store information about a mapping's user
57 * @name: name of the process
58 * @file: struct file to identify the owner of the mapping. Set it to
59 * NULL when the request comes from the kernel. In that case
60 * @pid_nr and @name won't be filled in.
62 * @note on the name length.
63 * As it's not only the process name that is stored here, but also
64 * module name -- lengths should be MAX allowed for the module name
68 char name
[MODULE_NAME_LEN
];
73 * struct mapping - Logical mapping descriptor
74 * @list: List of the mappings
75 * @mapping: The mapping descriptor
76 * @client: The user of this mapping
78 * This structure holds the information concerning logical mappings
79 * made on top a hardware windows.
82 struct list_head list
;
83 struct vme_mapping desc
;
84 struct vme_taskinfo client
;
88 * Flag controlling whether to create a new window if a mapping cannot
91 unsigned int vme_create_on_find_fail
;
93 * Flag controlling whether removing the last mapping on a window should
94 * also destroys the window.
96 unsigned int vme_destroy_on_remove
;
101 /* VME address modifiers names */
102 static char *amod
[] = {
103 "A64MBLT", "A64", "Invalid 0x02", "A64BLT",
104 "A64LCK", "A32LCK", "Invalid 0x06", "Invalid 0x07",
105 "A32MBLT USER", "A32 USER DATA", "A32 USER PROG", "A32BLT USER",
106 "A32MBLT SUP", "A32 SUP DATA", "A32 SUP PROG", "A32BLT SUP",
107 "Invalid 0x10", "Invalid 0x11", "Invalid 0x12", "Invalid 0x13",
108 "Invalid 0x14", "Invalid 0x15", "Invalid 0x16", "Invalid 0x17",
109 "Invalid 0x18", "Invalid 0x19", "Invalid 0x1a", "Invalid 0x1b",
110 "Invalid 0x1c", "Invalid 0x1d", "Invalid 0x1e", "Invalid 0x1f",
111 "2e6U", "2e3U", "Invalid 0x22", "Invalid 0x23",
112 "Invalid 0x24", "Invalid 0x25", "Invalid 0x26", "Invalid 0x27",
113 "Invalid 0x28", "A16 USER", "Invalid 0x2a", "Invalid 0x2b",
114 "A16LCK", "A16 SUP", "Invalid 0x2e", "CR/CSR",
115 "Invalid 0x30", "Invalid 0x31", "Invalid 0x32", "Invalid 0x33",
116 "A40", "A40LCK", "Invalid 0x36", "A40BLT",
117 "A24MBLT USER", "A24 USER DATA", "A24 USER PROG", "A24BLT USER",
118 "A24MBLT SUP", "A24 SUP DATA", "A24 SUP PROG", "A24BLT SUP"
121 static int vme_window_proc_show_mapping(char *page
, int num
,
122 struct mapping
*mapping
)
126 struct vme_mapping
*desc
= &mapping
->desc
;
129 va PCI VME Size Address Modifier Data Prefetch
130 Description Width Size
131 dd: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - ssssssssssssssss / sss sssss
132 client: ddddd ssssssssssssssss
134 p
+= sprintf(p
, " %2d: %p %.8x %.8x %.8x - ",
136 desc
->kernel_va
, desc
->pci_addrl
,
137 desc
->vme_addrl
, desc
->sizel
);
139 if (desc
->read_prefetch_enabled
)
140 switch (desc
->read_prefetch_size
) {
150 case VME_PREFETCH_16
:
160 p
+= sprintf(p
, "(0x%02x)%s / D%2d %5s\n",
161 desc
->am
, amod
[desc
->am
], desc
->data_width
, pfs
);
162 p
+= sprintf(p
, " client: ");
164 if (mapping
->client
.pid_nr
)
165 p
+= sprintf(p
, "%d ", (unsigned int)mapping
->client
.pid_nr
);
167 if (mapping
->client
.name
[0])
168 p
+= sprintf(p
, "%s", mapping
->client
.name
);
170 p
+= sprintf(p
, "\n");
175 static int vme_window_proc_show_window(char *page
, int window_num
)
179 struct window
*window
= &window_table
[window_num
];
180 struct mapping
*mapping
;
181 struct vme_mapping
*desc
;
185 p
+= sprintf(p
, "Window %d: ", window_num
);
188 p
+= sprintf(p
, "Not Active\n");
190 p
+= sprintf(p
, "Active - ");
192 if (window
->users
== 0)
193 p
+= sprintf(p
, "No users\n");
195 p
+= sprintf(p
, "%2d user%c\n", window
->users
,
196 (window
->users
> 1)?'s':' ');
199 if (!window
->active
) {
200 p
+= sprintf(p
, "\n");
204 desc
= &window
->desc
;
206 p
+= sprintf(p
, " %p %.8x %.8x %.8x - ",
207 desc
->kernel_va
, desc
->pci_addrl
,
208 desc
->vme_addrl
, desc
->sizel
);
210 if (desc
->read_prefetch_enabled
)
211 switch (desc
->read_prefetch_size
) {
221 case VME_PREFETCH_16
:
231 p
+= sprintf(p
, "(0x%02x)%s / D%2d %5s\n",
232 desc
->am
, amod
[desc
->am
], desc
->data_width
, pfs
);
234 if (list_empty(&window
->mappings
)) {
235 p
+= sprintf(p
, "\n");
239 p
+= sprintf(p
, "\n Mappings:\n");
241 list_for_each_entry(mapping
, &window
->mappings
, list
) {
242 p
+= vme_window_proc_show_mapping(p
, count
, mapping
);
246 p
+= sprintf(p
, "\n");
251 int vme_window_proc_show(char *page
, char **start
, off_t off
, int count
,
252 int *eof
, void *data
)
257 p
+= sprintf(p
, "\nPCI-VME Windows\n");
258 p
+= sprintf(p
, "===============\n\n");
259 p
+= sprintf(p
, " va PCI VME Size Address Modifier Data Prefetch\n");
260 p
+= sprintf(p
, " and Description Width Size\n");
261 p
+= sprintf(p
, "----------------------------------------------------------------------------\n\n");
263 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++)
264 p
+= vme_window_proc_show_window(p
, i
);
270 #endif /* CONFIG_PROC_FS */
273 * vme_window_release() - release file method for the VME window device
274 * @inode: Device inode
275 * @file: Device file descriptor
277 * The release method is in charge of releasing all the mappings made by
278 * the process closing the device file.
280 int vme_window_release(struct inode
*inode
, struct file
*file
)
283 struct window
*window
;
284 struct mapping
*mapping
;
287 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++) {
288 window
= &window_table
[i
];
290 if (mutex_lock_interruptible(&window
->lock
))
293 if ((!window
->active
) || (list_empty(&window
->mappings
)))
296 list_for_each_entry_safe(mapping
, tmp
,
297 &window
->mappings
, list
) {
299 if (mapping
->client
.file
== file
) {
301 * OK, that mapping is held by the process
304 list_del(&mapping
->list
);
311 mutex_unlock(&window
->lock
);
318 * add_mapping() - Helper function to add a mapping to a window
319 * @window: Window to add the mapping to
320 * @desc: Mapping descriptor
321 * @file: owner of the mapping (NULL if it comes from the kernel)
323 * It is assumed that the window mutex is held on entry to this function.
326 add_mapping(struct window
*window
, struct vme_mapping
*desc
, struct file
*file
)
328 struct mapping
*mapping
;
330 /* Create a logical mapping for this hardware window */
331 if ((mapping
= kzalloc(sizeof(struct mapping
), GFP_KERNEL
)) == NULL
) {
332 printk(KERN_ERR PFX
"%s - "
333 "Failed to allocate mapping\n", __func__
);
337 /* Save the window descriptor for this window. */
338 memcpy(&mapping
->desc
, desc
, sizeof(struct vme_mapping
));
340 /* Store the task's info only if the request comes from user-space */
342 mapping
->client
.file
= file
;
343 mapping
->client
.pid_nr
= task_pid_nr(current
);
344 strcpy(mapping
->client
.name
, current
->comm
);
346 strcpy(mapping
->client
.name
, "kernel");
349 /* Insert mapping at end of window mappings list */
350 list_add_tail(&mapping
->list
, &window
->mappings
);
352 /* Increment user count */
359 * remove_mapping() - Helper function to remove a mapping from a window
360 * @window: Window to remove the mapping from
361 * @desc: Mapping descriptor
362 * @file: struct file of the owner of the mapping (NULL if the kernel owns it)
364 * The specified descriptor is searched into the window mapping list by
365 * only matching the VME address, the size and the virtual address.
367 * It is assumed that the window mutex is held on entry to this function.
370 remove_mapping(struct window
*window
, struct vme_mapping
*desc
, struct file
*file
)
372 struct mapping
*mapping
;
375 list_for_each_entry_safe(mapping
, tmp
, &window
->mappings
, list
) {
377 if ((mapping
->desc
.vme_addru
== desc
->vme_addru
) &&
378 (mapping
->desc
.vme_addrl
== desc
->vme_addrl
) &&
379 (mapping
->desc
.sizeu
== desc
->sizeu
) &&
380 (mapping
->desc
.sizel
== desc
->sizel
) &&
381 (mapping
->desc
.kernel_va
== desc
->kernel_va
) &&
382 (!file
|| mapping
->client
.file
== file
)) {
383 /* Found the matching mapping */
384 list_del(&mapping
->list
);
396 * find_vme_mapping_from_addr - Find corresponding vme_mapping structure from
397 * logical address, returned by find_controller()
399 * @param logaddr - address to search for.
402 * @return vme_mapping pointer - if found.
403 * @return NULL - not found.
405 struct vme_mapping
* find_vme_mapping_from_addr(unsigned logaddr
)
408 struct window
*window
;
409 struct mapping
*mapping
;
411 for (cntr
= 0; cntr
< TSI148_NUM_OUT_WINDOWS
; cntr
++) {
412 window
= &window_table
[cntr
];
413 if (mutex_lock_interruptible(&window
->lock
))
415 list_for_each_entry(mapping
, &window
->mappings
, list
) {
416 if ((unsigned)mapping
->desc
.kernel_va
== logaddr
) {
417 mutex_unlock(&window
->lock
);
418 return &mapping
->desc
; /* bingo */
421 mutex_unlock(&window
->lock
);
424 return NULL
; /* not found */
426 EXPORT_SYMBOL_GPL(find_vme_mapping_from_addr
);
430 * vme_get_window_attr() - Get a PCI-VME hardware window attributes
431 * @desc: Contains the window number we're interested in
433 * Get the specified window attributes.
435 * This function is used by the VME_IOCTL_GET_WINDOW_ATTR ioctl from
436 * user applications but can also be used by drivers stacked on top
439 * Return 0 on success, or %EINVAL if the window number is out of bounds.
441 int vme_get_window_attr(struct vme_mapping
*desc
)
443 int window_num
= desc
->window_num
;
445 if ((window_num
< 0) || (window_num
>= TSI148_NUM_OUT_WINDOWS
))
448 if (mutex_lock_interruptible(&window_table
[window_num
].lock
))
451 memcpy(desc
, &window_table
[window_num
].desc
,
452 sizeof(struct vme_mapping
));
454 tsi148_get_window_attr(desc
);
456 mutex_unlock(&window_table
[window_num
].lock
);
460 EXPORT_SYMBOL_GPL(vme_get_window_attr
);
463 * vme_create_window() - Create and map a PCI-VME window
464 * @desc: Descriptor of the window to create
466 * Create and map a PCI-VME window according to the &struct vme_mapping
469 * This function is used by the VME_IOCTL_CREATE_WINDOW ioctl from
470 * user applications but can also be used by drivers stacked on top
473 * Return 0 on success, or a standard kernel error code on failure.
475 int vme_create_window(struct vme_mapping
*desc
)
477 int window_num
= desc
->window_num
;
478 struct window
*window
;
481 /* A little bit of checking */
482 if ((window_num
< 0) || (window_num
>= TSI148_NUM_OUT_WINDOWS
))
485 if (desc
->sizel
== 0)
488 /* Round down the initial VME address to a 64K boundary */
489 if (desc
->vme_addrl
& 0xffff) {
490 unsigned int lowaddr
= desc
->vme_addrl
& ~0xffff;
492 printk(KERN_INFO PFX
"%s - aligning VME address %08x to 64K "
493 "boundary %08x.\n", __func__
, desc
->vme_addrl
, lowaddr
);
494 desc
->vme_addrl
= lowaddr
;
495 desc
->sizel
+= desc
->vme_addrl
- lowaddr
;
499 * Round up the mapping size to a 64K boundary
500 * Note that vme_addrl is already aligned
502 if (desc
->sizel
& 0xffff) {
503 unsigned int newsize
= (desc
->sizel
+ 0x10000) & ~0xffff;
505 printk(KERN_INFO PFX
"%s - rounding up size %08x to 64K "
506 "boundary %08x.\n", __func__
, desc
->sizel
, newsize
);
507 desc
->sizel
= newsize
;
511 * OK from now on we don't want someone else mucking with our
514 window
= &window_table
[window_num
];
516 if (mutex_lock_interruptible(&window
->lock
))
519 if (window
->active
) {
524 /* Allocate and map a PCI address space for the window */
525 window
->rsrc
.name
= kmalloc(32, GFP_KERNEL
);
527 if (!window
->rsrc
.name
)
528 /* Not fatal, we can live with a nameless resource */
529 printk(KERN_WARNING PFX
"%s - "
530 "failed to allocate resource name\n", __func__
);
532 sprintf((char *)window
->rsrc
.name
, "VME Window %d", window_num
);
534 window
->rsrc
.start
= 0;
535 window
->rsrc
.end
= desc
->sizel
;
536 window
->rsrc
.flags
= IORESOURCE_MEM
;
539 * Allocate a PCI region for our window. Align the region to a 64K
540 * boundary for the TSI148 chip.
542 rc
= pci_bus_alloc_resource(vme_bridge
->pdev
->bus
, &window
->rsrc
,
543 desc
->sizel
, 0x10000,
544 PCIBIOS_MIN_MEM
, 0, NULL
, NULL
);
547 printk(KERN_ERR PFX
"%s - "
548 "Failed to allocate bus resource for window %d "
549 "start 0x%lx size 0x%.8x\n",
550 __func__
, window_num
, (unsigned long)window
->rsrc
.start
,
556 desc
->kernel_va
= ioremap(window
->rsrc
.start
, desc
->sizel
);
558 if (desc
->kernel_va
== NULL
) {
559 printk(KERN_ERR PFX
"%s - "
560 "failed to map window %d start 0x%lx size 0x%.8x\n",
561 __func__
, window_num
, (unsigned long)window
->rsrc
.start
,
568 desc
->pci_addrl
= window
->rsrc
.start
;
570 /* Now setup the chip for that window */
571 rc
= tsi148_create_window(desc
);
576 /* Copy the descriptor */
577 memcpy(&window
->desc
, desc
, sizeof(struct vme_mapping
));
579 /* Mark the window as active now */
582 mutex_unlock(&window
->lock
);
587 iounmap(desc
->kernel_va
);
590 release_resource(&window
->rsrc
);
593 if (window
->rsrc
.name
)
594 kfree(window
->rsrc
.name
);
595 memset(&window
->rsrc
, 0, sizeof(struct resource
));
598 mutex_unlock(&window
->lock
);
602 EXPORT_SYMBOL_GPL(vme_create_window
);
605 * vme_destroy_window() - Unmap and remove a PCI-VME window
606 * @window_num: Window Number of the window to be destroyed
608 * Unmap and remove the PCI-VME window specified in the &struct vme_mapping
609 * parameter also release all the mappings on top of that window.
611 * This function is used by the VME_IOCTL_DESTROY_WINDOW ioctl from
612 * user applications but can also be used by drivers stacked on top
615 * NOTE: destroying a window also forcibly remove all the mappings
616 * ont top of that window.
618 * Return 0 on success, or a standard kernel error code on failure.
620 int vme_destroy_window(int window_num
)
622 struct window
*window
;
623 struct mapping
*mapping
;
627 if ((window_num
< 0) || (window_num
>= TSI148_NUM_OUT_WINDOWS
))
631 * Prevent somebody else from changing our window from under us
633 window
= &window_table
[window_num
];
635 if (mutex_lock_interruptible(&window
->lock
))
639 * Maybe we should silently ignore trying to destroy an unused
642 if (!window
->active
) {
647 /* Remove all mappings */
648 if (window
->users
> 0) {
649 list_for_each_entry_safe(mapping
, tmp
,
650 &window
->mappings
, list
) {
651 list_del(&mapping
->list
);
658 printk(KERN_ERR
"%s: %d mappings still alive "
660 __func__
, window
->users
, window_num
);
662 /* Mark the window as unused */
665 /* Unmap the window */
666 iounmap(window
->desc
.kernel_va
);
667 window
->desc
.kernel_va
= NULL
;
669 tsi148_remove_window(&window
->desc
);
671 /* Release the PCI bus resource */
672 release_resource(&window
->rsrc
);
674 if (window
->rsrc
.name
)
675 kfree(window
->rsrc
.name
);
677 memset(&window
->rsrc
, 0, sizeof(struct resource
));
680 mutex_unlock(&window
->lock
);
684 EXPORT_SYMBOL_GPL(vme_destroy_window
);
687 * In order to save windows in the bridge, we map the whole address space
688 * onto a single window, so that subsequent mappings of the same kind will
689 * all be attached to it.
691 static void vme_optimize_window_size(struct vme_mapping
*desc
)
693 unsigned int resize
= 0;
696 case VME_A24_USER_MBLT
:
697 case VME_A24_USER_DATA_SCT
:
698 case VME_A24_USER_PRG_SCT
:
699 case VME_A24_USER_BLT
:
700 case VME_A24_SUP_MBLT
:
701 case VME_A24_SUP_DATA_SCT
:
702 case VME_A24_SUP_PRG_SCT
:
703 case VME_A24_SUP_BLT
:
718 printk(KERN_INFO PFX
"window %d: optimizing size to 0x%08x\n",
719 desc
->window_num
, resize
);
721 desc
->sizel
= resize
;
726 static int vme_mapping_sanity_check(const struct vme_mapping
*mapping
)
728 unsigned int vme_addru
= mapping
->vme_addru
;
729 unsigned int vme_addrl
= mapping
->vme_addrl
;
730 unsigned int err
= 0;
732 switch (mapping
->am
) {
736 if (vme_addru
|| vme_addrl
& ~0xffff)
739 case VME_A24_USER_MBLT
:
740 case VME_A24_USER_DATA_SCT
:
741 case VME_A24_USER_PRG_SCT
:
742 case VME_A24_USER_BLT
:
743 case VME_A24_SUP_MBLT
:
744 case VME_A24_SUP_DATA_SCT
:
745 case VME_A24_SUP_PRG_SCT
:
746 case VME_A24_SUP_BLT
:
747 if (vme_addru
|| vme_addrl
& ~0xffffff)
751 case VME_A32_USER_MBLT
:
752 case VME_A32_USER_DATA_SCT
:
753 case VME_A32_USER_PRG_SCT
:
754 case VME_A32_USER_BLT
:
755 case VME_A32_SUP_MBLT
:
756 case VME_A32_SUP_DATA_SCT
:
757 case VME_A32_SUP_PRG_SCT
:
758 case VME_A32_SUP_BLT
:
765 if (vme_addru
& ~0xff)
773 printk(KERN_ERR PFX
"Error: 0x%08x %08x out of A%d range\n",
774 vme_addru
, vme_addrl
, err
);
782 __vme_find_mapping(struct vme_mapping
*match
, int force
, struct file
*file
)
786 struct window
*window
;
788 struct vme_mapping wnd
;
790 rc
= vme_mapping_sanity_check(match
);
794 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++) {
795 window
= &window_table
[i
];
797 if (mutex_lock_interruptible(&window
->lock
))
800 /* First check if window is in use */
805 * Check if the window matches what we're looking for.
807 * Right now we only deal with 32-bit (or lower) address space
811 /* Check that the window is enabled in the hardware */
812 if (!window
->desc
.window_enabled
)
815 /* Check that the window has a <= 32-bit address space */
816 if ((window
->desc
.vme_addru
!= 0) || (window
->desc
.sizeu
!= 0))
819 /* Check the address modifier and data width */
820 if ((window
->desc
.am
!= match
->am
) ||
821 (window
->desc
.data_width
!= match
->data_width
))
824 /* Check the boundaries */
825 if ((window
->desc
.vme_addrl
> match
->vme_addrl
) ||
826 ((window
->desc
.vme_addrl
+ window
->desc
.sizel
) <
827 (match
->vme_addrl
+ match
->sizel
)))
830 /* Check the 2eSST transfer speed if 2eSST is enabled */
831 if ((window
->desc
.am
== VME_2e6U
) &&
832 (window
->desc
.v2esst_mode
!= match
->v2esst_mode
))
836 * Good, we found one mapping
837 * NOTE: we're exiting the loop with window->lock still held
842 mutex_unlock(&window
->lock
);
846 if (i
< TSI148_NUM_OUT_WINDOWS
) {
847 offset
= match
->vme_addrl
- window
->desc
.vme_addrl
;
849 /* Now set the virtual address of the mapping */
850 match
->kernel_va
= window
->desc
.kernel_va
+ offset
;
851 match
->pci_addrl
= window
->desc
.pci_addrl
+ offset
;
853 /* Assign window number */
854 match
->window_num
= i
;
856 /* Add the new mapping to the window */
857 rc
= add_mapping(window
, match
, file
);
859 mutex_unlock(&window
->lock
);
865 * Bad luck, no matching window found - create a new one if
871 /* Get the first unused window */
872 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++) {
873 window
= &window_table
[i
];
879 if (i
>= TSI148_NUM_OUT_WINDOWS
)
880 /* No more window available - bail out */
884 * Setup the physical window descriptor that can hold the requested
885 * mapping. The VME address and size may be realigned by the low level
886 * code in the descriptor, so make a private copy for window creation.
888 memcpy(&wnd
, match
, sizeof(struct vme_mapping
));
891 vme_optimize_window_size(&wnd
);
893 rc
= vme_create_window(&wnd
);
898 /* Now set the virtual address of the mapping */
899 window
= &window_table
[wnd
.window_num
];
901 offset
= match
->vme_addrl
- window
->desc
.vme_addrl
;
902 match
->kernel_va
= window
->desc
.kernel_va
+ offset
;
903 match
->pci_addrl
= window
->desc
.pci_addrl
+ offset
;
904 match
->window_num
= wnd
.window_num
;
907 /* And add that mapping to it */
908 rc
= add_mapping(window
, match
, file
);
914 __vme_release_mapping(struct vme_mapping
*desc
, int force
, struct file
*file
)
916 int window_num
= desc
->window_num
;
917 struct window
*window
;
920 if ((window_num
< 0) || (window_num
>= TSI148_NUM_OUT_WINDOWS
))
923 window
= &window_table
[window_num
];
925 if (mutex_lock_interruptible(&window
->lock
))
928 if (!window
->active
) {
933 /* Remove the mapping */
934 rc
= remove_mapping(window
, desc
, file
);
939 /* Check if there are no more users of this window */
940 if ((window
->users
== 0) && force
) {
941 mutex_unlock(&window
->lock
);
942 return vme_destroy_window(window_num
);
946 mutex_unlock(&window
->lock
);
952 * vme_find_mapping() - Find a window matching the specified descriptor
953 * @match: Descriptor of the window to look for
954 * @force: Force window creation if no match was found.
956 * Try to find a window matching the specified descriptor. If a window is
957 * found, then its number is returned in the &struct vme_mapping parameter.
959 * If no window match and force is set, then a new window is created
960 * to hold that mapping.
962 * This function is used by the VME_IOCTL_FIND_MAPPING ioctl from
963 * user applications but can also be used by drivers stacked on top
966 * Returns 0 on success, or a standard kernel error code.
968 int vme_find_mapping(struct vme_mapping
*match
, int force
)
970 return __vme_find_mapping(match
, force
, NULL
);
972 EXPORT_SYMBOL_GPL(vme_find_mapping
);
975 * vme_release_mapping() - Release a mapping allocated with vme_find_mapping
977 * @desc: Descriptor of the mapping to release
978 * @force: force window destruction
980 * Release a VME mapping. If the mapping is the last one on that window and
981 * force is set then the window is also destroyed.
983 * This function is used by the VME_IOCTL_RELEASE_MAPPING ioctl from
984 * user applications but can also be used by drivers stacked on top
987 * @return 0 - on success.
988 * @return standard kernel error code - if failed.
990 int vme_release_mapping(struct vme_mapping
*desc
, int force
)
992 return __vme_release_mapping(desc
, force
, NULL
);
994 EXPORT_SYMBOL_GPL(vme_release_mapping
);
996 static int vme_destroy_window_ioctl(int __user
*argp
)
1000 if (get_user(window_num
, argp
))
1003 return vme_destroy_window(window_num
);
1006 static int vme_bus_error_check_clear_ioctl(struct vme_bus_error __user
*argp
)
1008 struct vme_bus_error_desc desc
;
1010 if (copy_from_user(&desc
, argp
, sizeof(struct vme_bus_error_desc
)))
1013 desc
.valid
= vme_bus_error_check_clear(&desc
.error
);
1015 if (copy_to_user(argp
, &desc
, sizeof(struct vme_bus_error_desc
)))
1022 * vme_window_ioctl() - ioctl file method for the VME window device
1023 * @file: Device file descriptor
1024 * @cmd: ioctl number
1025 * @arg: ioctl argument
1027 * Currently the VME window device supports the following ioctls:
1029 * VME_IOCTL_GET_WINDOW_ATTR
1030 * VME_IOCTL_CREATE_WINDOW
1031 * VME_IOCTL_DESTROY_WINDOW
1032 * VME_IOCTL_FIND_MAPPING
1033 * VME_IOCTL_RELEASE_MAPPING
1034 * VME_IOCTL_GET_CREATE_ON_FIND_FAIL
1035 * VME_IOCTL_SET_CREATE_ON_FIND_FAIL
1036 * VME_IOCTL_GET_DESTROY_ON_REMOVE
1037 * VME_IOCTL_SET_DESTROY_ON_REMOVE
1039 long vme_window_ioctl(struct file
*file
, unsigned int cmd
, unsigned long arg
)
1042 struct vme_mapping desc
;
1043 void __user
*argp
= (void __user
*)arg
;
1046 case VME_IOCTL_GET_WINDOW_ATTR
:
1048 * Get a window attributes.
1050 * arg is a pointer to a struct vme_mapping with only
1051 * the window number specified.
1053 if (copy_from_user(&desc
, (void *)argp
,
1054 sizeof(struct vme_mapping
)))
1057 rc
= vme_get_window_attr(&desc
);
1062 if (copy_to_user((void *)argp
, &desc
,
1063 sizeof(struct vme_mapping
)))
1068 case VME_IOCTL_CREATE_WINDOW
:
1069 /* Create and map a window.
1071 * arg is a pointer to a struct vme_mapping specifying
1072 * the window number as well as its attributes.
1074 if (copy_from_user(&desc
, (void *)argp
,
1075 sizeof(struct vme_mapping
))) {
1079 rc
= vme_create_window(&desc
);
1084 if (copy_to_user((void *)argp
, &desc
,
1085 sizeof(struct vme_mapping
)))
1090 case VME_IOCTL_DESTROY_WINDOW
:
1091 /* Unmap and destroy a window.
1093 * arg is a pointer to the window number
1095 return vme_destroy_window_ioctl((int __user
*)argp
);
1097 case VME_IOCTL_FIND_MAPPING
:
1099 * Find a window suitable for this mapping.
1101 * arg is a pointer to a struct vme_mapping specifying
1102 * the attributes of the window to look for. If a match is
1103 * found then the virtual address for the requested mapping
1104 * is set in the window descriptor otherwise if
1105 * vme_create_on_find_fail is set then create a new window to
1106 * hold that mapping.
1108 if (copy_from_user(&desc
, (void *)argp
,
1109 sizeof(struct vme_mapping
)))
1112 rc
= __vme_find_mapping(&desc
, vme_create_on_find_fail
, file
);
1117 if (copy_to_user((void *)argp
, &desc
,
1118 sizeof(struct vme_mapping
)))
1123 case VME_IOCTL_RELEASE_MAPPING
:
1124 /* remove a mapping.
1126 * arg is a pointer to a struct vme_mapping specifying
1127 * the attributes of the mapping to be removed.
1128 * If the mapping is the last on that window and if
1129 * vme_destroy_on_remove is set then the window is also
1132 if (copy_from_user(&desc
, (void *)argp
,
1133 sizeof(struct vme_mapping
)))
1136 rc
= __vme_release_mapping(&desc
, vme_destroy_on_remove
, file
);
1140 case VME_IOCTL_GET_CREATE_ON_FIND_FAIL
:
1141 rc
= put_user(vme_create_on_find_fail
,
1142 (unsigned int __user
*)argp
);
1145 case VME_IOCTL_SET_CREATE_ON_FIND_FAIL
:
1146 rc
= get_user(vme_create_on_find_fail
,
1147 (unsigned int __user
*)argp
);
1150 case VME_IOCTL_GET_DESTROY_ON_REMOVE
:
1151 rc
= put_user(vme_destroy_on_remove
,
1152 (unsigned int __user
*)argp
);
1155 case VME_IOCTL_SET_DESTROY_ON_REMOVE
:
1156 rc
= get_user(vme_destroy_on_remove
,
1157 (unsigned int __user
*)argp
);
1159 case VME_IOCTL_GET_BUS_ERROR
:
1160 rc
= put_user(vme_bus_error_check(1),
1161 (unsigned int __user
*)argp
);
1163 case VME_IOCTL_CHECK_CLEAR_BUS_ERROR
:
1164 return vme_bus_error_check_clear_ioctl(argp
);
1174 * vme_remap_pfn_range() - Small wrapper for io_remap_pfn_range
1175 * @vma: User vma to map to
1177 * This is a small helper function which sets the approriate vma flags
1178 * and protection before calling io_remap_pfn_range().
1180 * The following flags are added to vm_flags:
1181 * - VM_IO This is an iomem region
1182 * - VM_RESERVED Do not swap that mapping
1183 * - VM_DONTCOPY Don't copy that mapping on fork
1184 * - VM_DONTEXPAND Prevent resizing with mremap()
1186 * The mapping is also set non-cacheable via the vm_page_prot field.
1188 static int vme_remap_pfn_range(struct vm_area_struct
*vma
)
1191 vma
->vm_flags
|= VM_IO
| VM_RESERVED
| VM_DONTCOPY
| VM_DONTEXPAND
;
1192 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
1194 return io_remap_pfn_range(vma
,
1197 vma
->vm_end
- vma
->vm_start
,
1202 * Check that a particular VME mapping corresponds to a region to be mmapped.
1204 * mmap() works with whole pages. Thus we need to see VME mappings as blocks
1205 * of pages, even if that means we see them bigger than they really are.
1207 static int vme_check_mmap_region(int windownr
, struct vme_mapping
*mapping
,
1208 unsigned int addr
, unsigned int size
)
1210 struct vme_mapping
*window
= &window_table
[windownr
].desc
;
1211 unsigned int aligned_start
;
1212 unsigned int aligned_end
;
1215 /* check that the requested region doesn't stick out of the window */
1216 if (addr
< window
->pci_addrl
||
1217 addr
+ size
> window
->pci_addrl
+ window
->sizel
) {
1221 /* compute the page-aligned boundaries of the VME mapping */
1222 aligned_start
= mapping
->pci_addrl
& PAGE_MASK
;
1223 end
= mapping
->pci_addrl
+ mapping
->sizel
;
1224 if (end
& (~PAGE_MASK
))
1225 aligned_end
= (end
& PAGE_MASK
) + PAGE_SIZE
;
1229 /* and compare these boundaries to those of the requested region */
1230 if (aligned_start
== addr
&& aligned_end
== addr
+ size
)
1237 * vme_window_mmap() - Map to userspace a VME address mapping
1238 * @file: Device file descriptor
1239 * @vma: User vma to map to
1241 * The PCI physical address is in vma->vm_pgoff and is guaranteed to be unique
1242 * among all mappings. The range size is given by (vma->vm_end - vma->vm_start)
1245 int vme_window_mmap(struct file
*file
, struct vm_area_struct
*vma
)
1249 struct window
*window
;
1250 struct mapping
*mapping
;
1254 /* Find the mapping this mmap call refers to */
1255 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++) {
1256 window
= &window_table
[i
];
1258 if (mutex_lock_interruptible(&window
->lock
))
1259 return -ERESTARTSYS
;
1261 /* Check the window is active and contains mappings */
1262 if ((!window
->active
) || (list_empty(&window
->mappings
)))
1265 list_for_each_entry(mapping
, &window
->mappings
, list
) {
1266 addr
= vma
->vm_pgoff
<< PAGE_SHIFT
;
1267 size
= vma
->vm_end
- vma
->vm_start
;
1269 if (mapping
->client
.file
== file
&&
1270 vme_check_mmap_region(i
, &mapping
->desc
, addr
, size
)) {
1271 rc
= vme_remap_pfn_range(vma
);
1272 mutex_unlock(&window
->lock
);
1280 mutex_unlock(&window
->lock
);
1287 * vme_window_init() - Initialize VME windows handling
1289 * Not much to do here aside from initializing the windows mutexes and
1292 void __devinit
vme_window_init(void)
1296 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++) {
1297 INIT_LIST_HEAD(&window_table
[i
].mappings
);
1298 mutex_init(&window_table
[i
].lock
);
1299 window_table
[i
].active
= 0;
1304 * vme_window_exit() - Cleanup for module unload
1306 * Unmap all the windows that were mapped.
1308 void __devexit
vme_window_exit(void)
1312 for (i
= 0; i
< TSI148_NUM_OUT_WINDOWS
; i
++) {
1313 if (window_table
[i
].active
)
1314 vme_destroy_window(i
);