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