vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / vmebridge / driver / vme_window.c
blobfb21fd5a4d4e806bf12976e7fd6d63e3d6584e0b
1 /*
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>
24 #include "vmebus.h"
25 #include "vme_bridge.h"
28 /**
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
38 * windows.
41 struct window {
42 struct mutex lock;
43 unsigned int active;
44 struct resource rsrc;
45 struct vme_mapping desc;
46 struct list_head mappings;
47 int users;
51 struct window window_table[TSI148_NUM_OUT_WINDOWS];
53 /**
54 * struct vme_taskinfo - Store information about a mapping's user
56 * @pid_nr: pid number
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
66 struct vme_taskinfo {
67 pid_t pid_nr;
68 char name[MODULE_NAME_LEN];
69 struct file *file;
72 /**
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.
81 struct mapping {
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
89 * be found.
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;
99 #ifdef CONFIG_PROC_FS
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)
124 char *p = page;
125 char *pfs;
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 - ",
135 num,
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) {
141 case VME_PREFETCH_2:
142 pfs = "PFS2";
143 break;
144 case VME_PREFETCH_4:
145 pfs = "PFS4";
146 break;
147 case VME_PREFETCH_8:
148 pfs = "PFS8";
149 break;
150 case VME_PREFETCH_16:
151 pfs = "PFS16";
152 break;
153 default:
154 pfs = "?";
155 break;
157 else
158 pfs = "NOPF";
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");
172 return p - page;
175 static int vme_window_proc_show_window(char *page, int window_num)
177 char *p = page;
178 char *pfs;
179 struct window *window = &window_table[window_num];
180 struct mapping *mapping;
181 struct vme_mapping *desc;
182 int count = 0;
185 p += sprintf(p, "Window %d: ", window_num);
187 if (!window->active)
188 p += sprintf(p, "Not Active\n");
189 else {
190 p += sprintf(p, "Active - ");
192 if (window->users == 0)
193 p += sprintf(p, "No users\n");
194 else
195 p += sprintf(p, "%2d user%c\n", window->users,
196 (window->users > 1)?'s':' ');
199 if (!window->active) {
200 p += sprintf(p, "\n");
201 return p - page;
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) {
212 case VME_PREFETCH_2:
213 pfs = "PFS2";
214 break;
215 case VME_PREFETCH_4:
216 pfs = "PFS4";
217 break;
218 case VME_PREFETCH_8:
219 pfs = "PFS8";
220 break;
221 case VME_PREFETCH_16:
222 pfs = "PFS16";
223 break;
224 default:
225 pfs = "?";
226 break;
228 else
229 pfs = "NOPF";
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");
236 return p - page;
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);
243 count++;
246 p += sprintf(p, "\n");
248 return p - page;
251 int vme_window_proc_show(char *page, char **start, off_t off, int count,
252 int *eof, void *data)
254 char *p = page;
255 int i;
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);
266 *eof = 1;
267 return p - page;
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)
282 int i;
283 struct window *window;
284 struct mapping *mapping;
285 struct mapping *tmp;
287 for (i = 0; i < TSI148_NUM_OUT_WINDOWS; i++) {
288 window = &window_table[i];
290 if (mutex_lock_interruptible(&window->lock))
291 return -ERESTARTSYS;
293 if ((!window->active) || (list_empty(&window->mappings)))
294 goto try_next;
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
302 * release it.
304 list_del(&mapping->list);
305 kfree(mapping);
306 window->users--;
310 try_next:
311 mutex_unlock(&window->lock);
314 return 0;
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.
325 static int
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__);
334 return -ENOMEM;
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 */
341 if (file) {
342 mapping->client.file = file;
343 mapping->client.pid_nr = task_pid_nr(current);
344 strcpy(mapping->client.name, current->comm);
345 } else {
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 */
353 window->users++;
355 return 0;
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.
369 static int
370 remove_mapping(struct window *window, struct vme_mapping *desc, struct file *file)
372 struct mapping *mapping;
373 struct mapping *tmp;
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);
385 kfree(mapping);
386 window->users--;
388 return 0;
392 return -EINVAL;
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)
407 int cntr;
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))
414 return NULL;
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
437 * of this one.
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))
446 return -EINVAL;
448 if (mutex_lock_interruptible(&window_table[window_num].lock))
449 return -ERESTARTSYS;
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);
458 return 0;
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
467 * parameter.
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
471 * of this one.
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;
479 int rc = 0;
481 /* A little bit of checking */
482 if ((window_num < 0) || (window_num >= TSI148_NUM_OUT_WINDOWS))
483 return -EINVAL;
485 if (desc->sizel == 0)
486 return -EINVAL;
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
512 * window.
514 window = &window_table[window_num];
516 if (mutex_lock_interruptible(&window->lock))
517 return -ERESTARTSYS;
519 if (window->active) {
520 rc = -EBUSY;
521 goto out_unlock;
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__);
531 else
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);
546 if (rc) {
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,
551 desc->sizel);
553 goto out_free;
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,
562 desc->sizel);
564 rc = -ENOMEM;
565 goto out_release;
568 desc->pci_addrl = window->rsrc.start;
570 /* Now setup the chip for that window */
571 rc = tsi148_create_window(desc);
573 if (rc)
574 goto out_unmap;
576 /* Copy the descriptor */
577 memcpy(&window->desc, desc, sizeof(struct vme_mapping));
579 /* Mark the window as active now */
580 window->active = 1;
582 mutex_unlock(&window->lock);
584 return 0;
586 out_unmap:
587 iounmap(desc->kernel_va);
589 out_release:
590 release_resource(&window->rsrc);
592 out_free:
593 if (window->rsrc.name)
594 kfree(window->rsrc.name);
595 memset(&window->rsrc, 0, sizeof(struct resource));
597 out_unlock:
598 mutex_unlock(&window->lock);
600 return rc;
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
613 * of this one.
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;
624 struct mapping *tmp;
625 int rc = 0;
627 if ((window_num < 0) || (window_num >= TSI148_NUM_OUT_WINDOWS))
628 return -EINVAL;
631 * Prevent somebody else from changing our window from under us
633 window = &window_table[window_num];
635 if (mutex_lock_interruptible(&window->lock))
636 return -ERESTARTSYS;
639 * Maybe we should silently ignore trying to destroy an unused
640 * window.
642 if (!window->active) {
643 rc = -EINVAL;
644 goto out_unlock;
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);
652 kfree(mapping);
653 window->users--;
657 if (window->users)
658 printk(KERN_ERR "%s: %d mappings still alive "
659 "on window %d\n",
660 __func__, window->users, window_num);
662 /* Mark the window as unused */
663 window->active = 0;
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));
679 out_unlock:
680 mutex_unlock(&window->lock);
682 return rc;
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;
695 switch (desc->am) {
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:
704 resize = 0x1000000;
705 break;
706 case VME_A16_USER:
707 case VME_A16_LCK:
708 case VME_A16_SUP:
709 resize = 0x10000;
710 break;
711 default:
712 break;
715 if (!resize)
716 return;
718 printk(KERN_INFO PFX "window %d: optimizing size to 0x%08x\n",
719 desc->window_num, resize);
720 desc->sizeu = 0;
721 desc->sizel = resize;
722 desc->vme_addru = 0;
723 desc->vme_addrl = 0;
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) {
733 case VME_A16_USER:
734 case VME_A16_LCK:
735 case VME_A16_SUP:
736 if (vme_addru || vme_addrl & ~0xffff)
737 err = 16;
738 break;
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)
748 err = 24;
749 break;
750 case VME_A32_LCK:
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:
759 if (vme_addru)
760 err = 32;
761 break;
762 case VME_A40_SCT:
763 case VME_A40_LCK:
764 case VME_A40_BLT:
765 if (vme_addru & ~0xff)
766 err = 40;
767 break;
768 default:
769 break;
772 if (err) {
773 printk(KERN_ERR PFX "Error: 0x%08x %08x out of A%d range\n",
774 vme_addru, vme_addrl, err);
775 return -EINVAL;
778 return 0;
781 static int
782 __vme_find_mapping(struct vme_mapping *match, int force, struct file *file)
784 int i;
785 int rc = 0;
786 struct window *window;
787 unsigned int offset;
788 struct vme_mapping wnd;
790 rc = vme_mapping_sanity_check(match);
791 if (rc)
792 return rc;
794 for (i = 0; i < TSI148_NUM_OUT_WINDOWS; i++) {
795 window = &window_table[i];
797 if (mutex_lock_interruptible(&window->lock))
798 return -ERESTARTSYS;
800 /* First check if window is in use */
801 if (!window->active)
802 goto try_next;
805 * Check if the window matches what we're looking for.
807 * Right now we only deal with 32-bit (or lower) address space
808 * windows,
811 /* Check that the window is enabled in the hardware */
812 if (!window->desc.window_enabled)
813 goto try_next;
815 /* Check that the window has a <= 32-bit address space */
816 if ((window->desc.vme_addru != 0) || (window->desc.sizeu != 0))
817 goto try_next;
819 /* Check the address modifier and data width */
820 if ((window->desc.am != match->am) ||
821 (window->desc.data_width != match->data_width))
822 goto try_next;
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)))
828 goto try_next;
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))
833 goto try_next;
836 * Good, we found one mapping
837 * NOTE: we're exiting the loop with window->lock still held
839 break;
841 try_next:
842 mutex_unlock(&window->lock);
845 /* Window found */
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);
861 return rc;
865 * Bad luck, no matching window found - create a new one if
866 * force is set.
868 if (!force)
869 return -EBUSY;
871 /* Get the first unused window */
872 for (i = 0; i < TSI148_NUM_OUT_WINDOWS; i++) {
873 window = &window_table[i];
875 if (!window->active)
876 break;
879 if (i >= TSI148_NUM_OUT_WINDOWS)
880 /* No more window available - bail out */
881 return -EBUSY;
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));
890 wnd.window_num = i;
891 vme_optimize_window_size(&wnd);
893 rc = vme_create_window(&wnd);
895 if (rc)
896 return rc;
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);
910 return rc;
913 static int
914 __vme_release_mapping(struct vme_mapping *desc, int force, struct file *file)
916 int window_num = desc->window_num;
917 struct window *window;
918 int rc = 0;
920 if ((window_num < 0) || (window_num >= TSI148_NUM_OUT_WINDOWS))
921 return -EINVAL;
923 window = &window_table[window_num];
925 if (mutex_lock_interruptible(&window->lock))
926 return -ERESTARTSYS;
928 if (!window->active) {
929 rc = -EINVAL;
930 goto out_unlock;
933 /* Remove the mapping */
934 rc = remove_mapping(window, desc, file);
936 if (rc)
937 goto out_unlock;
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);
945 out_unlock:
946 mutex_unlock(&window->lock);
948 return rc;
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
964 * of this one.
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
985 * of this one.
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)
998 int window_num;
1000 if (get_user(window_num, argp))
1001 return -EFAULT;
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)))
1011 return -EFAULT;
1013 desc.valid = vme_bus_error_check_clear(&desc.error);
1015 if (copy_to_user(argp, &desc, sizeof(struct vme_bus_error_desc)))
1016 return -EFAULT;
1018 return 0;
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)
1041 int rc;
1042 struct vme_mapping desc;
1043 void __user *argp = (void __user *)arg;
1045 switch (cmd) {
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)))
1055 return -EFAULT;
1057 rc = vme_get_window_attr(&desc);
1059 if (rc)
1060 return rc;
1062 if (copy_to_user((void *)argp, &desc,
1063 sizeof(struct vme_mapping)))
1064 return -EFAULT;
1066 break;
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))) {
1076 return -EFAULT;
1079 rc = vme_create_window(&desc);
1081 if (rc)
1082 return rc;
1084 if (copy_to_user((void *)argp, &desc,
1085 sizeof(struct vme_mapping)))
1086 return -EFAULT;
1088 break;
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)))
1110 return -EFAULT;
1112 rc = __vme_find_mapping(&desc, vme_create_on_find_fail, file);
1114 if (rc)
1115 return rc;
1117 if (copy_to_user((void *)argp, &desc,
1118 sizeof(struct vme_mapping)))
1119 return -EFAULT;
1121 break;
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
1130 * destroyed.
1132 if (copy_from_user(&desc, (void *)argp,
1133 sizeof(struct vme_mapping)))
1134 return -EFAULT;
1136 rc = __vme_release_mapping(&desc, vme_destroy_on_remove, file);
1138 break;
1140 case VME_IOCTL_GET_CREATE_ON_FIND_FAIL:
1141 rc = put_user(vme_create_on_find_fail,
1142 (unsigned int __user *)argp);
1143 break;
1145 case VME_IOCTL_SET_CREATE_ON_FIND_FAIL:
1146 rc = get_user(vme_create_on_find_fail,
1147 (unsigned int __user *)argp);
1148 break;
1150 case VME_IOCTL_GET_DESTROY_ON_REMOVE:
1151 rc = put_user(vme_destroy_on_remove,
1152 (unsigned int __user *)argp);
1153 break;
1155 case VME_IOCTL_SET_DESTROY_ON_REMOVE:
1156 rc = get_user(vme_destroy_on_remove,
1157 (unsigned int __user *)argp);
1158 break;
1159 case VME_IOCTL_GET_BUS_ERROR:
1160 rc = put_user(vme_bus_error_check(1),
1161 (unsigned int __user *)argp);
1162 break;
1163 case VME_IOCTL_CHECK_CLEAR_BUS_ERROR:
1164 return vme_bus_error_check_clear_ioctl(argp);
1166 default:
1167 rc = -ENOIOCTLCMD;
1170 return rc;
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,
1195 vma->vm_start,
1196 vma->vm_pgoff,
1197 vma->vm_end - vma->vm_start,
1198 vma->vm_page_prot);
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;
1213 unsigned int 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) {
1218 return 0;
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;
1226 else
1227 aligned_end = end;
1229 /* and compare these boundaries to those of the requested region */
1230 if (aligned_start == addr && aligned_end == addr + size)
1231 return 1;
1233 return 0;
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)
1247 int i;
1248 int rc = -EINVAL;
1249 struct window *window;
1250 struct mapping *mapping;
1251 unsigned int addr;
1252 unsigned int size;
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)))
1263 goto try_next;
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);
1274 return rc;
1279 try_next:
1280 mutex_unlock(&window->lock);
1283 return rc;
1287 * vme_window_init() - Initialize VME windows handling
1289 * Not much to do here aside from initializing the windows mutexes and
1290 * mapping lists.
1292 void __devinit vme_window_init(void)
1294 int i;
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)
1310 int i;
1312 for (i = 0; i < TSI148_NUM_OUT_WINDOWS; i++) {
1313 if (window_table[i].active)
1314 vme_destroy_window(i);