1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#include <linux/config.h>
43#include <linux/module.h>
44#include <asm/sn/sgi.h>
45#include <asm/sn/iograph.h>
46#include <asm/sn/invent.h>
47#include <asm/sn/hcl.h>
48#include <asm/sn/labelcl.h>
49#include <linux/pci.h>
50#include <linux/list.h>
51
52#include <linux/mm.h>
53#include <linux/slab.h>
54#include <linux/vmalloc.h>
55#include <linux/mman.h>
56#include <linux/init.h>
57#include <linux/raw.h>
58#include <linux/capability.h>
59
60#include <asm/uaccess.h>
61#include <asm/sn/sgi.h>
62#include <asm/io.h>
63#include <asm/pgalloc.h>
64#include <asm/page.h>
65#include <asm/system.h>
66
67#include <asm/sn/pci/pciba.h>
68
69
70MODULE_DESCRIPTION("User mode PCI interface");
71MODULE_AUTHOR("Chad Talbott");
72
73
74#undef DEBUG_PCIBA
75
76
77#undef TRACE_PCIBA
78
79
80#if defined(DEBUG_PCIBA)
81# define DPRINTF(x...) printk(KERN_DEBUG x)
82#else
83# define DPRINTF(x...)
84#endif
85
86#if defined(TRACE_PCIBA)
87# if defined(__GNUC__)
88# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \
89 __FILE__, __LINE__, __FUNCTION__)
90# else
91# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__)
92# endif
93#else
94# define TRACE()
95#endif
96
97
98typedef enum { failure, success } status;
99typedef enum { false, true } boolean;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140struct node_data {
141
142
143 struct list_head global_node_list;
144 vertex_hdl_t devfs_handle;
145
146 void (* cleanup)(struct node_data *);
147
148 union {
149 struct {
150 struct pci_dev * dev;
151 struct list_head dma_allocs;
152 boolean mmapped;
153 } dma;
154 struct {
155 struct pci_dev * dev;
156 u32 saved_rom_base_reg;
157 boolean mmapped;
158 } rom;
159 struct {
160 struct resource * res;
161 } base;
162 struct {
163 struct pci_dev * dev;
164 } config;
165 } u;
166};
167
168struct dma_allocation {
169 struct list_head list;
170
171 dma_addr_t handle;
172 void * va;
173 size_t size;
174};
175
176
177static LIST_HEAD(global_node_list);
178static LIST_HEAD(global_dma_list);
179
180
181
182int __init pciba_init(void);
183void __exit pciba_exit(void);
184
185static status __init register_with_devfs(void);
186static void __exit unregister_with_devfs(void);
187
188static status __init register_pci_device(vertex_hdl_t device_dir_handle,
189 struct pci_dev * dev);
190
191
192static int generic_open(struct inode * inode, struct file * file);
193static int rom_mmap(struct file * file, struct vm_area_struct * vma);
194static int rom_release(struct inode * inode, struct file * file);
195static int base_mmap(struct file * file, struct vm_area_struct * vma);
196static int config_ioctl(struct inode * inode, struct file * file,
197 unsigned int cmd,
198 unsigned long arg);
199static int dma_ioctl(struct inode * inode, struct file * file,
200 unsigned int cmd,
201 unsigned long arg);
202static int dma_mmap(struct file * file, struct vm_area_struct * vma);
203
204
205static int mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va);
206static int mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va);
207
208#ifdef DEBUG_PCIBA
209static void dump_nodes(struct list_head * nodes);
210static void dump_allocations(struct list_head * dalp);
211#endif
212
213
214static struct file_operations rom_fops = {
215 owner: THIS_MODULE,
216 mmap: rom_mmap,
217 open: generic_open,
218 release: rom_release
219};
220
221
222static struct file_operations base_fops = {
223 owner: THIS_MODULE,
224 mmap: base_mmap,
225 open: generic_open
226};
227
228
229static struct file_operations config_fops = {
230 owner: THIS_MODULE,
231 ioctl: config_ioctl,
232 open: generic_open
233};
234
235static struct file_operations dma_fops = {
236 owner: THIS_MODULE,
237 ioctl: dma_ioctl,
238 mmap: dma_mmap,
239 open: generic_open
240};
241
242
243module_init(pciba_init);
244module_exit(pciba_exit);
245
246
247int __init
248pciba_init(void)
249{
250 if (!ia64_platform_is("sn2"))
251 return -ENODEV;
252
253 TRACE();
254
255 if (register_with_devfs() == failure)
256 return 1;
257
258 printk("PCIBA (a user mode PCI interface) initialized.\n");
259
260 return 0;
261}
262
263
264void __exit
265pciba_exit(void)
266{
267 TRACE();
268
269
270
271 unregister_with_devfs();
272}
273
274
275# if 0
276static void __exit
277free_nodes(void)
278{
279 struct node_data * nd;
280
281 TRACE();
282
283 list_for_each(nd, &node_list) {
284 kfree(list_entry(nd, struct nd, node_list));
285 }
286}
287#endif
288
289
290static vertex_hdl_t pciba_devfs_handle;
291
292
293extern vertex_hdl_t
294devfn_to_vertex(unsigned char busnum, unsigned int devfn);
295
296static status __init
297register_with_devfs(void)
298{
299 struct pci_dev * dev;
300 vertex_hdl_t device_dir_handle;
301
302 TRACE();
303
304
305
306 pci_for_each_dev(dev) {
307 device_dir_handle = devfn_to_vertex(dev->bus->number,
308 dev->devfn);
309 if (device_dir_handle == NULL)
310 return failure;
311
312 if (register_pci_device(device_dir_handle, dev) == failure) {
313 hwgraph_vertex_destroy(pciba_devfs_handle);
314 return failure;
315 }
316 }
317
318 return success;
319}
320
321static void __exit
322unregister_with_devfs(void)
323{
324 struct list_head * lhp;
325 struct node_data * nd;
326
327 TRACE();
328
329 list_for_each(lhp, &global_node_list) {
330 nd = list_entry(lhp, struct node_data, global_node_list);
331 hwgraph_vertex_destroy(nd->devfs_handle);
332 }
333
334}
335
336
337struct node_data * new_node(void)
338{
339 struct node_data * node;
340
341 TRACE();
342
343 node = kmalloc(sizeof(struct node_data), GFP_KERNEL);
344 if (node <= 0)
345 return node;
346 list_add(&node->global_node_list, &global_node_list);
347 return node;
348}
349
350
351void dma_cleanup(struct node_data * dma_node)
352{
353 TRACE();
354
355
356#ifdef DEBUG_PCIBA
357 dump_allocations(&dma_node->u.dma.dma_allocs);
358#endif
359 hwgraph_vertex_destroy(dma_node->devfs_handle);
360}
361
362
363void init_dma_node(struct node_data * node,
364 struct pci_dev * dev, vertex_hdl_t dh)
365{
366 TRACE();
367
368 node->devfs_handle = dh;
369 node->u.dma.dev = dev;
370 node->cleanup = dma_cleanup;
371 INIT_LIST_HEAD(&node->u.dma.dma_allocs);
372}
373
374
375void rom_cleanup(struct node_data * rom_node)
376{
377 TRACE();
378
379 if (rom_node->u.rom.mmapped)
380 pci_write_config_dword(rom_node->u.rom.dev,
381 PCI_ROM_ADDRESS,
382 rom_node->u.rom.saved_rom_base_reg);
383 hwgraph_vertex_destroy(rom_node->devfs_handle);
384}
385
386
387void init_rom_node(struct node_data * node,
388 struct pci_dev * dev, vertex_hdl_t dh)
389{
390 TRACE();
391
392 node->devfs_handle = dh;
393 node->u.rom.dev = dev;
394 node->cleanup = rom_cleanup;
395 node->u.rom.mmapped = false;
396}
397
398
399static status __init
400register_pci_device(vertex_hdl_t device_dir_handle, struct pci_dev * dev)
401{
402 struct node_data * nd;
403 char devfs_path[20];
404 vertex_hdl_t node_devfs_handle;
405 int ri;
406
407 TRACE();
408
409
410
411 for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
412 if (pci_resource_len(dev, ri) != 0) {
413 sprintf(devfs_path, "base/%d", ri);
414 if (hwgraph_register(device_dir_handle, devfs_path,
415 0, DEVFS_FL_NONE,
416 0, 0,
417 S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
418 &base_fops,
419 &dev->resource[ri]) == NULL)
420 return failure;
421 }
422 }
423
424
425
426 for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
427 if (dev->resource[ri].flags & IORESOURCE_MEM &&
428 pci_resource_len(dev, ri) != 0) {
429 if (hwgraph_register(device_dir_handle, "mem",
430 0, DEVFS_FL_NONE, 0, 0,
431 S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
432 &base_fops,
433 &dev->resource[ri]) == NULL)
434 return failure;
435 break;
436 }
437 }
438
439
440
441 for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
442 if (dev->resource[ri].flags & IORESOURCE_IO &&
443 pci_resource_len(dev, ri) != 0) {
444 if (hwgraph_register(device_dir_handle, "io",
445 0, DEVFS_FL_NONE, 0, 0,
446 S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
447 &base_fops,
448 &dev->resource[ri]) == NULL)
449 return failure;
450 break;
451 }
452 }
453
454
455
456 if (pci_resource_len(dev, PCI_ROM_RESOURCE) != 0) {
457 nd = new_node();
458 if (nd <= 0)
459 return failure;
460 node_devfs_handle = hwgraph_register(device_dir_handle, "rom",
461 0, DEVFS_FL_NONE, 0, 0,
462 S_IFCHR | S_IRUSR, 0, 0,
463 &rom_fops, nd);
464 if (node_devfs_handle == NULL)
465 return failure;
466 init_rom_node(nd, dev, node_devfs_handle);
467 }
468
469
470
471 if (hwgraph_register(device_dir_handle, "config", 0, DEVFS_FL_NONE,
472 0, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
473 &config_fops, dev) == NULL)
474 return failure;
475
476
477
478
479
480 nd = new_node();
481 if (nd <= 0)
482 return failure;
483 node_devfs_handle =
484 hwgraph_register(device_dir_handle, "dma", 0, DEVFS_FL_NONE,
485 0, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
486 &dma_fops, nd);
487 if (node_devfs_handle == NULL)
488 return failure;
489 init_dma_node(nd, dev, node_devfs_handle);
490
491#ifdef DEBUG_PCIBA
492 dump_nodes(&global_node_list);
493#endif
494
495 return success;
496}
497
498
499static int
500generic_open(struct inode * inode, struct file * file)
501{
502 TRACE();
503
504
505
506
507 return 0;
508}
509
510
511static int
512rom_mmap(struct file * file, struct vm_area_struct * vma)
513{
514 unsigned long pci_pa;
515 struct node_data * nd;
516
517 TRACE();
518
519#ifdef CONFIG_HWGFS_FS
520 nd = (struct node_data * )file->f_dentry->d_fsdata;
521#else
522 nd = (struct node_data * )file->private_data;
523#endif
524
525 pci_pa = pci_resource_start(nd->u.rom.dev, PCI_ROM_RESOURCE);
526
527 if (!nd->u.rom.mmapped) {
528 nd->u.rom.mmapped = true;
529 DPRINTF("Enabling ROM address decoder.\n");
530 DPRINTF(
531"rom_mmap: FIXME: some cards do not allow both ROM and memory addresses to\n"
532"rom_mmap: FIXME: be enabled simultaneously, as they share a decoder.\n");
533 pci_read_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
534 &nd->u.rom.saved_rom_base_reg);
535 DPRINTF("ROM base address contains %x\n",
536 nd->u.rom.saved_rom_base_reg);
537 pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
538 nd->u.rom.saved_rom_base_reg |
539 PCI_ROM_ADDRESS_ENABLE);
540 }
541
542 return mmap_pci_address(vma, pci_pa);
543}
544
545
546static int
547rom_release(struct inode * inode, struct file * file)
548{
549 struct node_data * nd;
550
551 TRACE();
552
553#ifdef CONFIG_HWGFS_FS
554 nd = (struct node_data * )file->f_dentry->d_fsdata;
555#else
556 nd = (struct node_data * )file->private_data;
557#endif
558
559 if (nd->u.rom.mmapped) {
560 nd->u.rom.mmapped = false;
561 DPRINTF("Disabling ROM address decoder.\n");
562 pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
563 nd->u.rom.saved_rom_base_reg);
564 }
565 return 0;
566}
567
568
569static int
570base_mmap(struct file * file, struct vm_area_struct * vma)
571{
572 struct resource * resource;
573
574 TRACE();
575
576#ifdef CONFIG_HWGFS_FS
577 resource = (struct resource *)file->f_dentry->d_fsdata;
578#else
579 resource = (struct resource *)file->private_data;
580#endif
581
582 return mmap_pci_address(vma, resource->start);
583}
584
585
586static int
587config_ioctl(struct inode * inode, struct file * file,
588 unsigned int cmd,
589 unsigned long arg)
590{
591 struct pci_dev * dev;
592
593 union cfg_data {
594 uint8_t byte;
595 uint16_t word;
596 uint32_t dword;
597 } read_data, write_data;
598
599 int dir, size, offset;
600
601 TRACE();
602
603 DPRINTF("cmd = %x (DIR = %x, TYPE = %x, NR = %x, SIZE = %x)\n",
604 cmd,
605 _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
606 DPRINTF("arg = %lx\n", arg);
607
608#ifdef CONFIG_HWGFS_FS
609 dev = (struct pci_dev *)file->f_dentry->d_fsdata;
610#else
611 dev = (struct pci_dev *)file->private_data;
612#endif
613
614
615
616
617
618
619 dir = _IOC_DIR(cmd);
620
621#define do_swap(suffix, type) \
622 do { \
623 if (dir & _IOC_READ) { \
624 pci_read_config_##suffix(dev, _IOC_NR(cmd), \
625 &read_data.suffix); \
626 } \
627 if (dir & _IOC_WRITE) { \
628 get_user(write_data.suffix, (type)arg); \
629 pci_write_config_##suffix(dev, _IOC_NR(cmd), \
630 write_data.suffix); \
631 } \
632 if (dir & _IOC_READ) { \
633 put_user(read_data.suffix, (type)arg); \
634 } \
635 } while (0)
636
637 size = _IOC_SIZE(cmd);
638 offset = _IOC_NR(cmd);
639
640 DPRINTF("sanity check\n");
641 if (((size > 0) || (size <= 4)) &&
642 ((offset + size) <= 256) &&
643 (dir & (_IOC_READ | _IOC_WRITE))) {
644
645 switch (size)
646 {
647 case 1:
648 do_swap(byte, uint8_t *);
649 break;
650 case 2:
651 do_swap(word, uint16_t *);
652 break;
653 case 4:
654 do_swap(dword, uint32_t *);
655 break;
656 default:
657 DPRINTF("invalid ioctl\n");
658 return -EINVAL;
659 }
660 } else
661 return -EINVAL;
662
663 return 0;
664}
665
666
667#ifdef DEBUG_PCIBA
668static void
669dump_allocations(struct list_head * dalp)
670{
671 struct dma_allocation * dap;
672 struct list_head * p;
673
674 printk("{\n");
675 list_for_each(p, dalp) {
676 dap = list_entry(p, struct dma_allocation,
677 list);
678 printk(" handle = %lx, va = %p\n",
679 dap->handle, dap->va);
680 }
681 printk("}\n");
682}
683
684static void
685dump_nodes(struct list_head * nodes)
686{
687 struct node_data * ndp;
688 struct list_head * p;
689
690 printk("{\n");
691 list_for_each(p, nodes) {
692 ndp = list_entry(p, struct node_data,
693 global_node_list);
694 printk(" %p\n", (void *)ndp);
695 }
696 printk("}\n");
697}
698
699
700#if 0
701#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
702
703static void
704test_list(void)
705{
706 u64 i;
707 LIST_HEAD(the_list);
708
709 for (i = 0; i < 5; i++) {
710 struct dma_allocation * new_alloc;
711 NEW(new_alloc);
712 new_alloc->va = (void *)i;
713 new_alloc->handle = 5*i;
714 printk("%d - the_list->next = %lx\n", i, the_list.next);
715 list_add(&new_alloc->list, &the_list);
716 }
717 dump_allocations(&the_list);
718}
719#endif
720#endif
721
722
723static LIST_HEAD(dma_buffer_list);
724
725
726static int
727dma_ioctl(struct inode * inode, struct file * file,
728 unsigned int cmd,
729 unsigned long arg)
730{
731 struct node_data * nd;
732 uint64_t argv;
733 int result;
734 struct dma_allocation * dma_alloc;
735 struct list_head * iterp;
736
737 TRACE();
738
739 DPRINTF("cmd = %x\n", cmd);
740 DPRINTF("arg = %lx\n", arg);
741
742#ifdef CONFIG_HWGFS_FS
743 nd = (struct node_data *)file->f_dentry->d_fsdata;
744#else
745 nd = (struct node_data *)file->private_data;
746#endif
747
748#ifdef DEBUG_PCIBA
749 DPRINTF("at dma_ioctl entry\n");
750 dump_allocations(&nd->u.dma.dma_allocs);
751#endif
752
753 switch (cmd) {
754 case PCIIOCDMAALLOC:
755
756
757
758 DPRINTF("case PCIIOCDMAALLOC (%lx)\n", PCIIOCDMAALLOC);
759
760 if ( (result = get_user(argv, (uint64_t *)arg)) )
761 return result;
762 DPRINTF("argv (size of buffer) = %lx\n", argv);
763
764 dma_alloc = (struct dma_allocation *)
765 kmalloc(sizeof(struct dma_allocation), GFP_KERNEL);
766 if (dma_alloc <= 0)
767 return -ENOMEM;
768
769 dma_alloc->size = (size_t)argv;
770 dma_alloc->va = pci_alloc_consistent(nd->u.dma.dev,
771 dma_alloc->size,
772 &dma_alloc->handle);
773 DPRINTF("dma_alloc->va = %p, dma_alloc->handle = %lx\n",
774 dma_alloc->va, dma_alloc->handle);
775 if (dma_alloc->va == NULL) {
776 kfree(dma_alloc);
777 return -ENOMEM;
778 }
779
780 list_add(&dma_alloc->list, &nd->u.dma.dma_allocs);
781 if ( (result = put_user((uint64_t)dma_alloc->handle,
782 (uint64_t *)arg)) ) {
783 DPRINTF("put_user failed\n");
784 pci_free_consistent(nd->u.dma.dev, (size_t)argv,
785 dma_alloc->va, dma_alloc->handle);
786 kfree(dma_alloc);
787 return result;
788 }
789
790#ifdef DEBUG_PCIBA
791 DPRINTF("after insertion\n");
792 dump_allocations(&nd->u.dma.dma_allocs);
793#endif
794 break;
795
796 case PCIIOCDMAFREE:
797 DPRINTF("case PCIIOCDMAFREE (%lx)\n", PCIIOCDMAFREE);
798
799 if ( (result = get_user(argv, (uint64_t *)arg)) ) {
800 DPRINTF("get_user failed\n");
801 return result;
802 }
803
804 DPRINTF("argv (physical address of DMA buffer) = %lx\n", argv);
805 list_for_each(iterp, &nd->u.dma.dma_allocs) {
806 struct dma_allocation * da =
807 list_entry(iterp, struct dma_allocation, list);
808 if (da->handle == argv) {
809 pci_free_consistent(nd->u.dma.dev, da->size,
810 da->va, da->handle);
811 list_del(&da->list);
812 kfree(da);
813#ifdef DEBUG_PCIBA
814 DPRINTF("after deletion\n");
815 dump_allocations(&nd->u.dma.dma_allocs);
816#endif
817 return 0;
818 }
819 }
820
821 DPRINTF("attempt to free invalid dma handle\n");
822 return -EINVAL;
823
824 default:
825 DPRINTF("undefined ioctl\n");
826 return -EINVAL;
827 }
828
829 DPRINTF("success\n");
830 return 0;
831}
832
833
834static int
835dma_mmap(struct file * file, struct vm_area_struct * vma)
836{
837 struct node_data * nd;
838 struct list_head * iterp;
839 int result;
840
841 TRACE();
842
843#ifdef CONFIG_HWGFS_FS
844 nd = (struct node_data *)file->f_dentry->d_fsdata;
845#else
846 nd = (struct node_data *)file->private_data;
847#endif
848
849 DPRINTF("vma->vm_start is %lx\n", vma->vm_start);
850 DPRINTF("vma->vm_end is %lx\n", vma->vm_end);
851 DPRINTF("offset = %lx\n", vma->vm_pgoff);
852
853
854
855 list_for_each(iterp, &nd->u.dma.dma_allocs) {
856 struct dma_allocation * da =
857 list_entry(iterp, struct dma_allocation, list);
858
859 if (da->handle == vma->vm_pgoff << PAGE_SHIFT) {
860 DPRINTF("found dma handle\n");
861 if ( (result = mmap_kernel_address(vma,
862 da->va)) ) {
863 return result;
864 } else {
865
866
867
868 *(char *)da->va = 0xaa;
869 strncpy(da->va, " Toastie!", da->size);
870 if (put_user(0x18badbeeful,
871 (u64 *)vma->vm_start))
872 DPRINTF("put_user failed?!\n");
873 return 0;
874 }
875
876 }
877 }
878 DPRINTF("attempt to mmap an invalid dma handle\n");
879 return -EINVAL;
880}
881
882
883static int
884mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va)
885{
886 unsigned long pci_pa;
887
888 TRACE();
889
890 DPRINTF("vma->vm_start is %lx\n", vma->vm_start);
891 DPRINTF("vma->vm_end is %lx\n", vma->vm_end);
892
893
894
895
896
897
898 DPRINTF("PCI base at virtual address %lx\n", pci_va);
899
900
901
902
903
904 pci_pa = pci_va & ~0xe000000000000000ul;
905 DPRINTF("PCI base at physical address %lx\n", pci_pa);
906
907
908
909
910
911 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
912
913 vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO;
914
915 return io_remap_page_range(vma->vm_start, pci_pa,
916 vma->vm_end-vma->vm_start,
917 vma->vm_page_prot);
918}
919
920
921static int
922mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va)
923{
924 unsigned long kernel_pa;
925
926 TRACE();
927
928 DPRINTF("vma->vm_start is %lx\n", vma->vm_start);
929 DPRINTF("vma->vm_end is %lx\n", vma->vm_end);
930
931
932
933
934
935
936 DPRINTF("mapping virtual address %p\n", kernel_va);
937 kernel_pa = __pa(kernel_va);
938 DPRINTF("mapping physical address %lx\n", kernel_pa);
939
940 vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO;
941
942 return remap_page_range(vma->vm_start, kernel_pa,
943 vma->vm_end-vma->vm_start,
944 vma->vm_page_prot);
945}
946