xref: /openbmc/linux/drivers/pci/syscall.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1 /*
2  *	pci_syscall.c
3  *
4  * For architectures where we want to allow direct access
5  * to the PCI config stuff - it would probably be preferable
6  * on PCs too, but there people just do it by hand with the
7  * magic northbridge registers..
8  */
9 
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/pci.h>
13 #include <linux/smp_lock.h>
14 #include <linux/syscalls.h>
15 #include <asm/uaccess.h>
16 
17 
18 asmlinkage long
19 sys_pciconfig_read(unsigned long bus, unsigned long dfn,
20 		   unsigned long off, unsigned long len,
21 		   void __user *buf)
22 {
23 	struct pci_dev *dev;
24 	u8 byte;
25 	u16 word;
26 	u32 dword;
27 	long err, cfg_ret;
28 
29 	err = -EPERM;
30 	if (!capable(CAP_SYS_ADMIN))
31 		goto error;
32 
33 	err = -ENODEV;
34 	dev = pci_find_slot(bus, dfn);
35 	if (!dev)
36 		goto error;
37 
38 	lock_kernel();
39 	switch (len) {
40 	case 1:
41 		cfg_ret = pci_read_config_byte(dev, off, &byte);
42 		break;
43 	case 2:
44 		cfg_ret = pci_read_config_word(dev, off, &word);
45 		break;
46 	case 4:
47 		cfg_ret = pci_read_config_dword(dev, off, &dword);
48 		break;
49 	default:
50 		err = -EINVAL;
51 		unlock_kernel();
52 		goto error;
53 	};
54 	unlock_kernel();
55 
56 	err = -EIO;
57 	if (cfg_ret != PCIBIOS_SUCCESSFUL)
58 		goto error;
59 
60 	switch (len) {
61 	case 1:
62 		err = put_user(byte, (unsigned char __user *)buf);
63 		break;
64 	case 2:
65 		err = put_user(word, (unsigned short __user *)buf);
66 		break;
67 	case 4:
68 		err = put_user(dword, (unsigned int __user *)buf);
69 		break;
70 	};
71 	return err;
72 
73 error:
74 	/* ??? XFree86 doesn't even check the return value.  They
75 	   just look for 0xffffffff in the output, since that's what
76 	   they get instead of a machine check on x86.  */
77 	switch (len) {
78 	case 1:
79 		put_user(-1, (unsigned char __user *)buf);
80 		break;
81 	case 2:
82 		put_user(-1, (unsigned short __user *)buf);
83 		break;
84 	case 4:
85 		put_user(-1, (unsigned int __user *)buf);
86 		break;
87 	};
88 	return err;
89 }
90 
91 asmlinkage long
92 sys_pciconfig_write(unsigned long bus, unsigned long dfn,
93 		    unsigned long off, unsigned long len,
94 		    void __user *buf)
95 {
96 	struct pci_dev *dev;
97 	u8 byte;
98 	u16 word;
99 	u32 dword;
100 	int err = 0;
101 
102 	if (!capable(CAP_SYS_ADMIN))
103 		return -EPERM;
104 
105 	dev = pci_find_slot(bus, dfn);
106 	if (!dev)
107 		return -ENODEV;
108 
109 	lock_kernel();
110 	switch(len) {
111 	case 1:
112 		err = get_user(byte, (u8 __user *)buf);
113 		if (err)
114 			break;
115 		err = pci_write_config_byte(dev, off, byte);
116 		if (err != PCIBIOS_SUCCESSFUL)
117 			err = -EIO;
118 		break;
119 
120 	case 2:
121 		err = get_user(word, (u16 __user *)buf);
122 		if (err)
123 			break;
124 		err = pci_write_config_word(dev, off, word);
125 		if (err != PCIBIOS_SUCCESSFUL)
126 			err = -EIO;
127 		break;
128 
129 	case 4:
130 		err = get_user(dword, (u32 __user *)buf);
131 		if (err)
132 			break;
133 		err = pci_write_config_dword(dev, off, dword);
134 		if (err != PCIBIOS_SUCCESSFUL)
135 			err = -EIO;
136 		break;
137 
138 	default:
139 		err = -EINVAL;
140 		break;
141 	};
142 	unlock_kernel();
143 
144 	return err;
145 }
146