Commit 911e1c9b05a8e3559a7aa89083930700a0b9e7ee
Committed by
Jesse Barnes
1 parent
8633328be2
Exists in
master
and in
7 other branches
PCI: export SMBIOS provided firmware instance and label to sysfs
This patch exports SMBIOS provided firmware instance and label of onboard PCI devices to sysfs. New files are: /sys/bus/pci/devices/.../label which contains the firmware name for the device in question, and /sys/bus/pci/devices/.../index which contains the firmware device type instance for the given device. Signed-off-by: Jordan Hargrave <jordan_hargrave@dell.com> Signed-off-by: Narendra K <narendra_k@dell.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Showing 7 changed files with 221 additions and 0 deletions Inline Diff
Documentation/ABI/testing/sysfs-bus-pci
1 | What: /sys/bus/pci/drivers/.../bind | 1 | What: /sys/bus/pci/drivers/.../bind |
2 | Date: December 2003 | 2 | Date: December 2003 |
3 | Contact: linux-pci@vger.kernel.org | 3 | Contact: linux-pci@vger.kernel.org |
4 | Description: | 4 | Description: |
5 | Writing a device location to this file will cause | 5 | Writing a device location to this file will cause |
6 | the driver to attempt to bind to the device found at | 6 | the driver to attempt to bind to the device found at |
7 | this location. This is useful for overriding default | 7 | this location. This is useful for overriding default |
8 | bindings. The format for the location is: DDDD:BB:DD.F. | 8 | bindings. The format for the location is: DDDD:BB:DD.F. |
9 | That is Domain:Bus:Device.Function and is the same as | 9 | That is Domain:Bus:Device.Function and is the same as |
10 | found in /sys/bus/pci/devices/. For example: | 10 | found in /sys/bus/pci/devices/. For example: |
11 | # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/bind | 11 | # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/bind |
12 | (Note: kernels before 2.6.28 may require echo -n). | 12 | (Note: kernels before 2.6.28 may require echo -n). |
13 | 13 | ||
14 | What: /sys/bus/pci/drivers/.../unbind | 14 | What: /sys/bus/pci/drivers/.../unbind |
15 | Date: December 2003 | 15 | Date: December 2003 |
16 | Contact: linux-pci@vger.kernel.org | 16 | Contact: linux-pci@vger.kernel.org |
17 | Description: | 17 | Description: |
18 | Writing a device location to this file will cause the | 18 | Writing a device location to this file will cause the |
19 | driver to attempt to unbind from the device found at | 19 | driver to attempt to unbind from the device found at |
20 | this location. This may be useful when overriding default | 20 | this location. This may be useful when overriding default |
21 | bindings. The format for the location is: DDDD:BB:DD.F. | 21 | bindings. The format for the location is: DDDD:BB:DD.F. |
22 | That is Domain:Bus:Device.Function and is the same as | 22 | That is Domain:Bus:Device.Function and is the same as |
23 | found in /sys/bus/pci/devices/. For example: | 23 | found in /sys/bus/pci/devices/. For example: |
24 | # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/unbind | 24 | # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/unbind |
25 | (Note: kernels before 2.6.28 may require echo -n). | 25 | (Note: kernels before 2.6.28 may require echo -n). |
26 | 26 | ||
27 | What: /sys/bus/pci/drivers/.../new_id | 27 | What: /sys/bus/pci/drivers/.../new_id |
28 | Date: December 2003 | 28 | Date: December 2003 |
29 | Contact: linux-pci@vger.kernel.org | 29 | Contact: linux-pci@vger.kernel.org |
30 | Description: | 30 | Description: |
31 | Writing a device ID to this file will attempt to | 31 | Writing a device ID to this file will attempt to |
32 | dynamically add a new device ID to a PCI device driver. | 32 | dynamically add a new device ID to a PCI device driver. |
33 | This may allow the driver to support more hardware than | 33 | This may allow the driver to support more hardware than |
34 | was included in the driver's static device ID support | 34 | was included in the driver's static device ID support |
35 | table at compile time. The format for the device ID is: | 35 | table at compile time. The format for the device ID is: |
36 | VVVV DDDD SVVV SDDD CCCC MMMM PPPP. That is Vendor ID, | 36 | VVVV DDDD SVVV SDDD CCCC MMMM PPPP. That is Vendor ID, |
37 | Device ID, Subsystem Vendor ID, Subsystem Device ID, | 37 | Device ID, Subsystem Vendor ID, Subsystem Device ID, |
38 | Class, Class Mask, and Private Driver Data. The Vendor ID | 38 | Class, Class Mask, and Private Driver Data. The Vendor ID |
39 | and Device ID fields are required, the rest are optional. | 39 | and Device ID fields are required, the rest are optional. |
40 | Upon successfully adding an ID, the driver will probe | 40 | Upon successfully adding an ID, the driver will probe |
41 | for the device and attempt to bind to it. For example: | 41 | for the device and attempt to bind to it. For example: |
42 | # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id | 42 | # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id |
43 | 43 | ||
44 | What: /sys/bus/pci/drivers/.../remove_id | 44 | What: /sys/bus/pci/drivers/.../remove_id |
45 | Date: February 2009 | 45 | Date: February 2009 |
46 | Contact: Chris Wright <chrisw@sous-sol.org> | 46 | Contact: Chris Wright <chrisw@sous-sol.org> |
47 | Description: | 47 | Description: |
48 | Writing a device ID to this file will remove an ID | 48 | Writing a device ID to this file will remove an ID |
49 | that was dynamically added via the new_id sysfs entry. | 49 | that was dynamically added via the new_id sysfs entry. |
50 | The format for the device ID is: | 50 | The format for the device ID is: |
51 | VVVV DDDD SVVV SDDD CCCC MMMM. That is Vendor ID, Device | 51 | VVVV DDDD SVVV SDDD CCCC MMMM. That is Vendor ID, Device |
52 | ID, Subsystem Vendor ID, Subsystem Device ID, Class, | 52 | ID, Subsystem Vendor ID, Subsystem Device ID, Class, |
53 | and Class Mask. The Vendor ID and Device ID fields are | 53 | and Class Mask. The Vendor ID and Device ID fields are |
54 | required, the rest are optional. After successfully | 54 | required, the rest are optional. After successfully |
55 | removing an ID, the driver will no longer support the | 55 | removing an ID, the driver will no longer support the |
56 | device. This is useful to ensure auto probing won't | 56 | device. This is useful to ensure auto probing won't |
57 | match the driver to the device. For example: | 57 | match the driver to the device. For example: |
58 | # echo "8086 10f5" > /sys/bus/pci/drivers/foo/remove_id | 58 | # echo "8086 10f5" > /sys/bus/pci/drivers/foo/remove_id |
59 | 59 | ||
60 | What: /sys/bus/pci/rescan | 60 | What: /sys/bus/pci/rescan |
61 | Date: January 2009 | 61 | Date: January 2009 |
62 | Contact: Linux PCI developers <linux-pci@vger.kernel.org> | 62 | Contact: Linux PCI developers <linux-pci@vger.kernel.org> |
63 | Description: | 63 | Description: |
64 | Writing a non-zero value to this attribute will | 64 | Writing a non-zero value to this attribute will |
65 | force a rescan of all PCI buses in the system, and | 65 | force a rescan of all PCI buses in the system, and |
66 | re-discover previously removed devices. | 66 | re-discover previously removed devices. |
67 | Depends on CONFIG_HOTPLUG. | 67 | Depends on CONFIG_HOTPLUG. |
68 | 68 | ||
69 | What: /sys/bus/pci/devices/.../remove | 69 | What: /sys/bus/pci/devices/.../remove |
70 | Date: January 2009 | 70 | Date: January 2009 |
71 | Contact: Linux PCI developers <linux-pci@vger.kernel.org> | 71 | Contact: Linux PCI developers <linux-pci@vger.kernel.org> |
72 | Description: | 72 | Description: |
73 | Writing a non-zero value to this attribute will | 73 | Writing a non-zero value to this attribute will |
74 | hot-remove the PCI device and any of its children. | 74 | hot-remove the PCI device and any of its children. |
75 | Depends on CONFIG_HOTPLUG. | 75 | Depends on CONFIG_HOTPLUG. |
76 | 76 | ||
77 | What: /sys/bus/pci/devices/.../rescan | 77 | What: /sys/bus/pci/devices/.../rescan |
78 | Date: January 2009 | 78 | Date: January 2009 |
79 | Contact: Linux PCI developers <linux-pci@vger.kernel.org> | 79 | Contact: Linux PCI developers <linux-pci@vger.kernel.org> |
80 | Description: | 80 | Description: |
81 | Writing a non-zero value to this attribute will | 81 | Writing a non-zero value to this attribute will |
82 | force a rescan of the device's parent bus and all | 82 | force a rescan of the device's parent bus and all |
83 | child buses, and re-discover devices removed earlier | 83 | child buses, and re-discover devices removed earlier |
84 | from this part of the device tree. | 84 | from this part of the device tree. |
85 | Depends on CONFIG_HOTPLUG. | 85 | Depends on CONFIG_HOTPLUG. |
86 | 86 | ||
87 | What: /sys/bus/pci/devices/.../reset | 87 | What: /sys/bus/pci/devices/.../reset |
88 | Date: July 2009 | 88 | Date: July 2009 |
89 | Contact: Michael S. Tsirkin <mst@redhat.com> | 89 | Contact: Michael S. Tsirkin <mst@redhat.com> |
90 | Description: | 90 | Description: |
91 | Some devices allow an individual function to be reset | 91 | Some devices allow an individual function to be reset |
92 | without affecting other functions in the same device. | 92 | without affecting other functions in the same device. |
93 | For devices that have this support, a file named reset | 93 | For devices that have this support, a file named reset |
94 | will be present in sysfs. Writing 1 to this file | 94 | will be present in sysfs. Writing 1 to this file |
95 | will perform reset. | 95 | will perform reset. |
96 | 96 | ||
97 | What: /sys/bus/pci/devices/.../vpd | 97 | What: /sys/bus/pci/devices/.../vpd |
98 | Date: February 2008 | 98 | Date: February 2008 |
99 | Contact: Ben Hutchings <bhutchings@solarflare.com> | 99 | Contact: Ben Hutchings <bhutchings@solarflare.com> |
100 | Description: | 100 | Description: |
101 | A file named vpd in a device directory will be a | 101 | A file named vpd in a device directory will be a |
102 | binary file containing the Vital Product Data for the | 102 | binary file containing the Vital Product Data for the |
103 | device. It should follow the VPD format defined in | 103 | device. It should follow the VPD format defined in |
104 | PCI Specification 2.1 or 2.2, but users should consider | 104 | PCI Specification 2.1 or 2.2, but users should consider |
105 | that some devices may have malformatted data. If the | 105 | that some devices may have malformatted data. If the |
106 | underlying VPD has a writable section then the | 106 | underlying VPD has a writable section then the |
107 | corresponding section of this file will be writable. | 107 | corresponding section of this file will be writable. |
108 | 108 | ||
109 | What: /sys/bus/pci/devices/.../virtfnN | 109 | What: /sys/bus/pci/devices/.../virtfnN |
110 | Date: March 2009 | 110 | Date: March 2009 |
111 | Contact: Yu Zhao <yu.zhao@intel.com> | 111 | Contact: Yu Zhao <yu.zhao@intel.com> |
112 | Description: | 112 | Description: |
113 | This symbolic link appears when hardware supports the SR-IOV | 113 | This symbolic link appears when hardware supports the SR-IOV |
114 | capability and the Physical Function driver has enabled it. | 114 | capability and the Physical Function driver has enabled it. |
115 | The symbolic link points to the PCI device sysfs entry of the | 115 | The symbolic link points to the PCI device sysfs entry of the |
116 | Virtual Function whose index is N (0...MaxVFs-1). | 116 | Virtual Function whose index is N (0...MaxVFs-1). |
117 | 117 | ||
118 | What: /sys/bus/pci/devices/.../dep_link | 118 | What: /sys/bus/pci/devices/.../dep_link |
119 | Date: March 2009 | 119 | Date: March 2009 |
120 | Contact: Yu Zhao <yu.zhao@intel.com> | 120 | Contact: Yu Zhao <yu.zhao@intel.com> |
121 | Description: | 121 | Description: |
122 | This symbolic link appears when hardware supports the SR-IOV | 122 | This symbolic link appears when hardware supports the SR-IOV |
123 | capability and the Physical Function driver has enabled it, | 123 | capability and the Physical Function driver has enabled it, |
124 | and this device has vendor specific dependencies with others. | 124 | and this device has vendor specific dependencies with others. |
125 | The symbolic link points to the PCI device sysfs entry of | 125 | The symbolic link points to the PCI device sysfs entry of |
126 | Physical Function this device depends on. | 126 | Physical Function this device depends on. |
127 | 127 | ||
128 | What: /sys/bus/pci/devices/.../physfn | 128 | What: /sys/bus/pci/devices/.../physfn |
129 | Date: March 2009 | 129 | Date: March 2009 |
130 | Contact: Yu Zhao <yu.zhao@intel.com> | 130 | Contact: Yu Zhao <yu.zhao@intel.com> |
131 | Description: | 131 | Description: |
132 | This symbolic link appears when a device is a Virtual Function. | 132 | This symbolic link appears when a device is a Virtual Function. |
133 | The symbolic link points to the PCI device sysfs entry of the | 133 | The symbolic link points to the PCI device sysfs entry of the |
134 | Physical Function this device associates with. | 134 | Physical Function this device associates with. |
135 | 135 | ||
136 | What: /sys/bus/pci/slots/.../module | 136 | What: /sys/bus/pci/slots/.../module |
137 | Date: June 2009 | 137 | Date: June 2009 |
138 | Contact: linux-pci@vger.kernel.org | 138 | Contact: linux-pci@vger.kernel.org |
139 | Description: | 139 | Description: |
140 | This symbolic link points to the PCI hotplug controller driver | 140 | This symbolic link points to the PCI hotplug controller driver |
141 | module that manages the hotplug slot. | 141 | module that manages the hotplug slot. |
142 | |||
143 | What: /sys/bus/pci/devices/.../label | ||
144 | Date: July 2010 | ||
145 | Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com | ||
146 | Description: | ||
147 | Reading this attribute will provide the firmware | ||
148 | given name(SMBIOS type 41 string) of the PCI device. | ||
149 | The attribute will be created only if the firmware | ||
150 | has given a name to the PCI device. | ||
151 | Users: | ||
152 | Userspace applications interested in knowing the | ||
153 | firmware assigned name of the PCI device. | ||
154 | |||
155 | What: /sys/bus/pci/devices/.../index | ||
156 | Date: July 2010 | ||
157 | Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com | ||
158 | Description: | ||
159 | Reading this attribute will provide the firmware | ||
160 | given instance(SMBIOS type 41 device type instance) | ||
161 | of the PCI device. The attribute will be created | ||
162 | only if the firmware has given a device type instance | ||
163 | to the PCI device. | ||
164 | Users: | ||
165 | Userspace applications interested in knowing the | ||
166 | firmware assigned device type instance of the PCI | ||
167 | device that can help in understanding the firmware | ||
168 | intended order of the PCI device. | ||
142 | 169 |
drivers/firmware/dmi_scan.c
1 | #include <linux/types.h> | 1 | #include <linux/types.h> |
2 | #include <linux/string.h> | 2 | #include <linux/string.h> |
3 | #include <linux/init.h> | 3 | #include <linux/init.h> |
4 | #include <linux/module.h> | 4 | #include <linux/module.h> |
5 | #include <linux/dmi.h> | 5 | #include <linux/dmi.h> |
6 | #include <linux/efi.h> | 6 | #include <linux/efi.h> |
7 | #include <linux/bootmem.h> | 7 | #include <linux/bootmem.h> |
8 | #include <asm/dmi.h> | 8 | #include <asm/dmi.h> |
9 | 9 | ||
10 | /* | 10 | /* |
11 | * DMI stands for "Desktop Management Interface". It is part | 11 | * DMI stands for "Desktop Management Interface". It is part |
12 | * of and an antecedent to, SMBIOS, which stands for System | 12 | * of and an antecedent to, SMBIOS, which stands for System |
13 | * Management BIOS. See further: http://www.dmtf.org/standards | 13 | * Management BIOS. See further: http://www.dmtf.org/standards |
14 | */ | 14 | */ |
15 | static char dmi_empty_string[] = " "; | 15 | static char dmi_empty_string[] = " "; |
16 | 16 | ||
17 | /* | 17 | /* |
18 | * Catch too early calls to dmi_check_system(): | 18 | * Catch too early calls to dmi_check_system(): |
19 | */ | 19 | */ |
20 | static int dmi_initialized; | 20 | static int dmi_initialized; |
21 | 21 | ||
22 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) | 22 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) |
23 | { | 23 | { |
24 | const u8 *bp = ((u8 *) dm) + dm->length; | 24 | const u8 *bp = ((u8 *) dm) + dm->length; |
25 | 25 | ||
26 | if (s) { | 26 | if (s) { |
27 | s--; | 27 | s--; |
28 | while (s > 0 && *bp) { | 28 | while (s > 0 && *bp) { |
29 | bp += strlen(bp) + 1; | 29 | bp += strlen(bp) + 1; |
30 | s--; | 30 | s--; |
31 | } | 31 | } |
32 | 32 | ||
33 | if (*bp != 0) { | 33 | if (*bp != 0) { |
34 | size_t len = strlen(bp)+1; | 34 | size_t len = strlen(bp)+1; |
35 | size_t cmp_len = len > 8 ? 8 : len; | 35 | size_t cmp_len = len > 8 ? 8 : len; |
36 | 36 | ||
37 | if (!memcmp(bp, dmi_empty_string, cmp_len)) | 37 | if (!memcmp(bp, dmi_empty_string, cmp_len)) |
38 | return dmi_empty_string; | 38 | return dmi_empty_string; |
39 | return bp; | 39 | return bp; |
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | return ""; | 43 | return ""; |
44 | } | 44 | } |
45 | 45 | ||
46 | static char * __init dmi_string(const struct dmi_header *dm, u8 s) | 46 | static char * __init dmi_string(const struct dmi_header *dm, u8 s) |
47 | { | 47 | { |
48 | const char *bp = dmi_string_nosave(dm, s); | 48 | const char *bp = dmi_string_nosave(dm, s); |
49 | char *str; | 49 | char *str; |
50 | size_t len; | 50 | size_t len; |
51 | 51 | ||
52 | if (bp == dmi_empty_string) | 52 | if (bp == dmi_empty_string) |
53 | return dmi_empty_string; | 53 | return dmi_empty_string; |
54 | 54 | ||
55 | len = strlen(bp) + 1; | 55 | len = strlen(bp) + 1; |
56 | str = dmi_alloc(len); | 56 | str = dmi_alloc(len); |
57 | if (str != NULL) | 57 | if (str != NULL) |
58 | strcpy(str, bp); | 58 | strcpy(str, bp); |
59 | else | 59 | else |
60 | printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len); | 60 | printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len); |
61 | 61 | ||
62 | return str; | 62 | return str; |
63 | } | 63 | } |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * We have to be cautious here. We have seen BIOSes with DMI pointers | 66 | * We have to be cautious here. We have seen BIOSes with DMI pointers |
67 | * pointing to completely the wrong place for example | 67 | * pointing to completely the wrong place for example |
68 | */ | 68 | */ |
69 | static void dmi_table(u8 *buf, int len, int num, | 69 | static void dmi_table(u8 *buf, int len, int num, |
70 | void (*decode)(const struct dmi_header *, void *), | 70 | void (*decode)(const struct dmi_header *, void *), |
71 | void *private_data) | 71 | void *private_data) |
72 | { | 72 | { |
73 | u8 *data = buf; | 73 | u8 *data = buf; |
74 | int i = 0; | 74 | int i = 0; |
75 | 75 | ||
76 | /* | 76 | /* |
77 | * Stop when we see all the items the table claimed to have | 77 | * Stop when we see all the items the table claimed to have |
78 | * OR we run off the end of the table (also happens) | 78 | * OR we run off the end of the table (also happens) |
79 | */ | 79 | */ |
80 | while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { | 80 | while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { |
81 | const struct dmi_header *dm = (const struct dmi_header *)data; | 81 | const struct dmi_header *dm = (const struct dmi_header *)data; |
82 | 82 | ||
83 | /* | 83 | /* |
84 | * We want to know the total length (formatted area and | 84 | * We want to know the total length (formatted area and |
85 | * strings) before decoding to make sure we won't run off the | 85 | * strings) before decoding to make sure we won't run off the |
86 | * table in dmi_decode or dmi_string | 86 | * table in dmi_decode or dmi_string |
87 | */ | 87 | */ |
88 | data += dm->length; | 88 | data += dm->length; |
89 | while ((data - buf < len - 1) && (data[0] || data[1])) | 89 | while ((data - buf < len - 1) && (data[0] || data[1])) |
90 | data++; | 90 | data++; |
91 | if (data - buf < len - 1) | 91 | if (data - buf < len - 1) |
92 | decode(dm, private_data); | 92 | decode(dm, private_data); |
93 | data += 2; | 93 | data += 2; |
94 | i++; | 94 | i++; |
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | static u32 dmi_base; | 98 | static u32 dmi_base; |
99 | static u16 dmi_len; | 99 | static u16 dmi_len; |
100 | static u16 dmi_num; | 100 | static u16 dmi_num; |
101 | 101 | ||
102 | static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, | 102 | static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, |
103 | void *)) | 103 | void *)) |
104 | { | 104 | { |
105 | u8 *buf; | 105 | u8 *buf; |
106 | 106 | ||
107 | buf = dmi_ioremap(dmi_base, dmi_len); | 107 | buf = dmi_ioremap(dmi_base, dmi_len); |
108 | if (buf == NULL) | 108 | if (buf == NULL) |
109 | return -1; | 109 | return -1; |
110 | 110 | ||
111 | dmi_table(buf, dmi_len, dmi_num, decode, NULL); | 111 | dmi_table(buf, dmi_len, dmi_num, decode, NULL); |
112 | 112 | ||
113 | dmi_iounmap(buf, dmi_len); | 113 | dmi_iounmap(buf, dmi_len); |
114 | return 0; | 114 | return 0; |
115 | } | 115 | } |
116 | 116 | ||
117 | static int __init dmi_checksum(const u8 *buf) | 117 | static int __init dmi_checksum(const u8 *buf) |
118 | { | 118 | { |
119 | u8 sum = 0; | 119 | u8 sum = 0; |
120 | int a; | 120 | int a; |
121 | 121 | ||
122 | for (a = 0; a < 15; a++) | 122 | for (a = 0; a < 15; a++) |
123 | sum += buf[a]; | 123 | sum += buf[a]; |
124 | 124 | ||
125 | return sum == 0; | 125 | return sum == 0; |
126 | } | 126 | } |
127 | 127 | ||
128 | static char *dmi_ident[DMI_STRING_MAX]; | 128 | static char *dmi_ident[DMI_STRING_MAX]; |
129 | static LIST_HEAD(dmi_devices); | 129 | static LIST_HEAD(dmi_devices); |
130 | int dmi_available; | 130 | int dmi_available; |
131 | 131 | ||
132 | /* | 132 | /* |
133 | * Save a DMI string | 133 | * Save a DMI string |
134 | */ | 134 | */ |
135 | static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string) | 135 | static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string) |
136 | { | 136 | { |
137 | const char *d = (const char*) dm; | 137 | const char *d = (const char*) dm; |
138 | char *p; | 138 | char *p; |
139 | 139 | ||
140 | if (dmi_ident[slot]) | 140 | if (dmi_ident[slot]) |
141 | return; | 141 | return; |
142 | 142 | ||
143 | p = dmi_string(dm, d[string]); | 143 | p = dmi_string(dm, d[string]); |
144 | if (p == NULL) | 144 | if (p == NULL) |
145 | return; | 145 | return; |
146 | 146 | ||
147 | dmi_ident[slot] = p; | 147 | dmi_ident[slot] = p; |
148 | } | 148 | } |
149 | 149 | ||
150 | static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index) | 150 | static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index) |
151 | { | 151 | { |
152 | const u8 *d = (u8*) dm + index; | 152 | const u8 *d = (u8*) dm + index; |
153 | char *s; | 153 | char *s; |
154 | int is_ff = 1, is_00 = 1, i; | 154 | int is_ff = 1, is_00 = 1, i; |
155 | 155 | ||
156 | if (dmi_ident[slot]) | 156 | if (dmi_ident[slot]) |
157 | return; | 157 | return; |
158 | 158 | ||
159 | for (i = 0; i < 16 && (is_ff || is_00); i++) { | 159 | for (i = 0; i < 16 && (is_ff || is_00); i++) { |
160 | if(d[i] != 0x00) is_ff = 0; | 160 | if(d[i] != 0x00) is_ff = 0; |
161 | if(d[i] != 0xFF) is_00 = 0; | 161 | if(d[i] != 0xFF) is_00 = 0; |
162 | } | 162 | } |
163 | 163 | ||
164 | if (is_ff || is_00) | 164 | if (is_ff || is_00) |
165 | return; | 165 | return; |
166 | 166 | ||
167 | s = dmi_alloc(16*2+4+1); | 167 | s = dmi_alloc(16*2+4+1); |
168 | if (!s) | 168 | if (!s) |
169 | return; | 169 | return; |
170 | 170 | ||
171 | sprintf(s, "%pUB", d); | 171 | sprintf(s, "%pUB", d); |
172 | 172 | ||
173 | dmi_ident[slot] = s; | 173 | dmi_ident[slot] = s; |
174 | } | 174 | } |
175 | 175 | ||
176 | static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index) | 176 | static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index) |
177 | { | 177 | { |
178 | const u8 *d = (u8*) dm + index; | 178 | const u8 *d = (u8*) dm + index; |
179 | char *s; | 179 | char *s; |
180 | 180 | ||
181 | if (dmi_ident[slot]) | 181 | if (dmi_ident[slot]) |
182 | return; | 182 | return; |
183 | 183 | ||
184 | s = dmi_alloc(4); | 184 | s = dmi_alloc(4); |
185 | if (!s) | 185 | if (!s) |
186 | return; | 186 | return; |
187 | 187 | ||
188 | sprintf(s, "%u", *d & 0x7F); | 188 | sprintf(s, "%u", *d & 0x7F); |
189 | dmi_ident[slot] = s; | 189 | dmi_ident[slot] = s; |
190 | } | 190 | } |
191 | 191 | ||
192 | static void __init dmi_save_one_device(int type, const char *name) | 192 | static void __init dmi_save_one_device(int type, const char *name) |
193 | { | 193 | { |
194 | struct dmi_device *dev; | 194 | struct dmi_device *dev; |
195 | 195 | ||
196 | /* No duplicate device */ | 196 | /* No duplicate device */ |
197 | if (dmi_find_device(type, name, NULL)) | 197 | if (dmi_find_device(type, name, NULL)) |
198 | return; | 198 | return; |
199 | 199 | ||
200 | dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1); | 200 | dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1); |
201 | if (!dev) { | 201 | if (!dev) { |
202 | printk(KERN_ERR "dmi_save_one_device: out of memory.\n"); | 202 | printk(KERN_ERR "dmi_save_one_device: out of memory.\n"); |
203 | return; | 203 | return; |
204 | } | 204 | } |
205 | 205 | ||
206 | dev->type = type; | 206 | dev->type = type; |
207 | strcpy((char *)(dev + 1), name); | 207 | strcpy((char *)(dev + 1), name); |
208 | dev->name = (char *)(dev + 1); | 208 | dev->name = (char *)(dev + 1); |
209 | dev->device_data = NULL; | 209 | dev->device_data = NULL; |
210 | list_add(&dev->list, &dmi_devices); | 210 | list_add(&dev->list, &dmi_devices); |
211 | } | 211 | } |
212 | 212 | ||
213 | static void __init dmi_save_devices(const struct dmi_header *dm) | 213 | static void __init dmi_save_devices(const struct dmi_header *dm) |
214 | { | 214 | { |
215 | int i, count = (dm->length - sizeof(struct dmi_header)) / 2; | 215 | int i, count = (dm->length - sizeof(struct dmi_header)) / 2; |
216 | 216 | ||
217 | for (i = 0; i < count; i++) { | 217 | for (i = 0; i < count; i++) { |
218 | const char *d = (char *)(dm + 1) + (i * 2); | 218 | const char *d = (char *)(dm + 1) + (i * 2); |
219 | 219 | ||
220 | /* Skip disabled device */ | 220 | /* Skip disabled device */ |
221 | if ((*d & 0x80) == 0) | 221 | if ((*d & 0x80) == 0) |
222 | continue; | 222 | continue; |
223 | 223 | ||
224 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d + 1))); | 224 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d + 1))); |
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) | 228 | static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) |
229 | { | 229 | { |
230 | int i, count = *(u8 *)(dm + 1); | 230 | int i, count = *(u8 *)(dm + 1); |
231 | struct dmi_device *dev; | 231 | struct dmi_device *dev; |
232 | 232 | ||
233 | for (i = 1; i <= count; i++) { | 233 | for (i = 1; i <= count; i++) { |
234 | char *devname = dmi_string(dm, i); | 234 | char *devname = dmi_string(dm, i); |
235 | 235 | ||
236 | if (devname == dmi_empty_string) | 236 | if (devname == dmi_empty_string) |
237 | continue; | 237 | continue; |
238 | 238 | ||
239 | dev = dmi_alloc(sizeof(*dev)); | 239 | dev = dmi_alloc(sizeof(*dev)); |
240 | if (!dev) { | 240 | if (!dev) { |
241 | printk(KERN_ERR | 241 | printk(KERN_ERR |
242 | "dmi_save_oem_strings_devices: out of memory.\n"); | 242 | "dmi_save_oem_strings_devices: out of memory.\n"); |
243 | break; | 243 | break; |
244 | } | 244 | } |
245 | 245 | ||
246 | dev->type = DMI_DEV_TYPE_OEM_STRING; | 246 | dev->type = DMI_DEV_TYPE_OEM_STRING; |
247 | dev->name = devname; | 247 | dev->name = devname; |
248 | dev->device_data = NULL; | 248 | dev->device_data = NULL; |
249 | 249 | ||
250 | list_add(&dev->list, &dmi_devices); | 250 | list_add(&dev->list, &dmi_devices); |
251 | } | 251 | } |
252 | } | 252 | } |
253 | 253 | ||
254 | static void __init dmi_save_ipmi_device(const struct dmi_header *dm) | 254 | static void __init dmi_save_ipmi_device(const struct dmi_header *dm) |
255 | { | 255 | { |
256 | struct dmi_device *dev; | 256 | struct dmi_device *dev; |
257 | void * data; | 257 | void * data; |
258 | 258 | ||
259 | data = dmi_alloc(dm->length); | 259 | data = dmi_alloc(dm->length); |
260 | if (data == NULL) { | 260 | if (data == NULL) { |
261 | printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); | 261 | printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); |
262 | return; | 262 | return; |
263 | } | 263 | } |
264 | 264 | ||
265 | memcpy(data, dm, dm->length); | 265 | memcpy(data, dm, dm->length); |
266 | 266 | ||
267 | dev = dmi_alloc(sizeof(*dev)); | 267 | dev = dmi_alloc(sizeof(*dev)); |
268 | if (!dev) { | 268 | if (!dev) { |
269 | printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); | 269 | printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); |
270 | return; | 270 | return; |
271 | } | 271 | } |
272 | 272 | ||
273 | dev->type = DMI_DEV_TYPE_IPMI; | 273 | dev->type = DMI_DEV_TYPE_IPMI; |
274 | dev->name = "IPMI controller"; | 274 | dev->name = "IPMI controller"; |
275 | dev->device_data = data; | 275 | dev->device_data = data; |
276 | 276 | ||
277 | list_add_tail(&dev->list, &dmi_devices); | 277 | list_add_tail(&dev->list, &dmi_devices); |
278 | } | 278 | } |
279 | 279 | ||
280 | static void __init dmi_save_dev_onboard(int instance, int segment, int bus, | ||
281 | int devfn, const char *name) | ||
282 | { | ||
283 | struct dmi_dev_onboard *onboard_dev; | ||
284 | |||
285 | onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1); | ||
286 | if (!onboard_dev) { | ||
287 | printk(KERN_ERR "dmi_save_dev_onboard: out of memory.\n"); | ||
288 | return; | ||
289 | } | ||
290 | onboard_dev->instance = instance; | ||
291 | onboard_dev->segment = segment; | ||
292 | onboard_dev->bus = bus; | ||
293 | onboard_dev->devfn = devfn; | ||
294 | |||
295 | strcpy((char *)&onboard_dev[1], name); | ||
296 | onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD; | ||
297 | onboard_dev->dev.name = (char *)&onboard_dev[1]; | ||
298 | onboard_dev->dev.device_data = onboard_dev; | ||
299 | |||
300 | list_add(&onboard_dev->dev.list, &dmi_devices); | ||
301 | } | ||
302 | |||
280 | static void __init dmi_save_extended_devices(const struct dmi_header *dm) | 303 | static void __init dmi_save_extended_devices(const struct dmi_header *dm) |
281 | { | 304 | { |
282 | const u8 *d = (u8*) dm + 5; | 305 | const u8 *d = (u8*) dm + 5; |
283 | 306 | ||
284 | /* Skip disabled device */ | 307 | /* Skip disabled device */ |
285 | if ((*d & 0x80) == 0) | 308 | if ((*d & 0x80) == 0) |
286 | return; | 309 | return; |
287 | 310 | ||
311 | dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5), | ||
312 | dmi_string_nosave(dm, *(d-1))); | ||
288 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); | 313 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); |
289 | } | 314 | } |
290 | 315 | ||
291 | /* | 316 | /* |
292 | * Process a DMI table entry. Right now all we care about are the BIOS | 317 | * Process a DMI table entry. Right now all we care about are the BIOS |
293 | * and machine entries. For 2.5 we should pull the smbus controller info | 318 | * and machine entries. For 2.5 we should pull the smbus controller info |
294 | * out of here. | 319 | * out of here. |
295 | */ | 320 | */ |
296 | static void __init dmi_decode(const struct dmi_header *dm, void *dummy) | 321 | static void __init dmi_decode(const struct dmi_header *dm, void *dummy) |
297 | { | 322 | { |
298 | switch(dm->type) { | 323 | switch(dm->type) { |
299 | case 0: /* BIOS Information */ | 324 | case 0: /* BIOS Information */ |
300 | dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); | 325 | dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); |
301 | dmi_save_ident(dm, DMI_BIOS_VERSION, 5); | 326 | dmi_save_ident(dm, DMI_BIOS_VERSION, 5); |
302 | dmi_save_ident(dm, DMI_BIOS_DATE, 8); | 327 | dmi_save_ident(dm, DMI_BIOS_DATE, 8); |
303 | break; | 328 | break; |
304 | case 1: /* System Information */ | 329 | case 1: /* System Information */ |
305 | dmi_save_ident(dm, DMI_SYS_VENDOR, 4); | 330 | dmi_save_ident(dm, DMI_SYS_VENDOR, 4); |
306 | dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); | 331 | dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); |
307 | dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); | 332 | dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); |
308 | dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); | 333 | dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); |
309 | dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8); | 334 | dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8); |
310 | break; | 335 | break; |
311 | case 2: /* Base Board Information */ | 336 | case 2: /* Base Board Information */ |
312 | dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); | 337 | dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); |
313 | dmi_save_ident(dm, DMI_BOARD_NAME, 5); | 338 | dmi_save_ident(dm, DMI_BOARD_NAME, 5); |
314 | dmi_save_ident(dm, DMI_BOARD_VERSION, 6); | 339 | dmi_save_ident(dm, DMI_BOARD_VERSION, 6); |
315 | dmi_save_ident(dm, DMI_BOARD_SERIAL, 7); | 340 | dmi_save_ident(dm, DMI_BOARD_SERIAL, 7); |
316 | dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8); | 341 | dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8); |
317 | break; | 342 | break; |
318 | case 3: /* Chassis Information */ | 343 | case 3: /* Chassis Information */ |
319 | dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4); | 344 | dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4); |
320 | dmi_save_type(dm, DMI_CHASSIS_TYPE, 5); | 345 | dmi_save_type(dm, DMI_CHASSIS_TYPE, 5); |
321 | dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6); | 346 | dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6); |
322 | dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7); | 347 | dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7); |
323 | dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8); | 348 | dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8); |
324 | break; | 349 | break; |
325 | case 10: /* Onboard Devices Information */ | 350 | case 10: /* Onboard Devices Information */ |
326 | dmi_save_devices(dm); | 351 | dmi_save_devices(dm); |
327 | break; | 352 | break; |
328 | case 11: /* OEM Strings */ | 353 | case 11: /* OEM Strings */ |
329 | dmi_save_oem_strings_devices(dm); | 354 | dmi_save_oem_strings_devices(dm); |
330 | break; | 355 | break; |
331 | case 38: /* IPMI Device Information */ | 356 | case 38: /* IPMI Device Information */ |
332 | dmi_save_ipmi_device(dm); | 357 | dmi_save_ipmi_device(dm); |
333 | break; | 358 | break; |
334 | case 41: /* Onboard Devices Extended Information */ | 359 | case 41: /* Onboard Devices Extended Information */ |
335 | dmi_save_extended_devices(dm); | 360 | dmi_save_extended_devices(dm); |
336 | } | 361 | } |
337 | } | 362 | } |
338 | 363 | ||
339 | static int __init dmi_present(const char __iomem *p) | 364 | static int __init dmi_present(const char __iomem *p) |
340 | { | 365 | { |
341 | u8 buf[15]; | 366 | u8 buf[15]; |
342 | 367 | ||
343 | memcpy_fromio(buf, p, 15); | 368 | memcpy_fromio(buf, p, 15); |
344 | if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { | 369 | if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { |
345 | dmi_num = (buf[13] << 8) | buf[12]; | 370 | dmi_num = (buf[13] << 8) | buf[12]; |
346 | dmi_len = (buf[7] << 8) | buf[6]; | 371 | dmi_len = (buf[7] << 8) | buf[6]; |
347 | dmi_base = (buf[11] << 24) | (buf[10] << 16) | | 372 | dmi_base = (buf[11] << 24) | (buf[10] << 16) | |
348 | (buf[9] << 8) | buf[8]; | 373 | (buf[9] << 8) | buf[8]; |
349 | 374 | ||
350 | /* | 375 | /* |
351 | * DMI version 0.0 means that the real version is taken from | 376 | * DMI version 0.0 means that the real version is taken from |
352 | * the SMBIOS version, which we don't know at this point. | 377 | * the SMBIOS version, which we don't know at this point. |
353 | */ | 378 | */ |
354 | if (buf[14] != 0) | 379 | if (buf[14] != 0) |
355 | printk(KERN_INFO "DMI %d.%d present.\n", | 380 | printk(KERN_INFO "DMI %d.%d present.\n", |
356 | buf[14] >> 4, buf[14] & 0xF); | 381 | buf[14] >> 4, buf[14] & 0xF); |
357 | else | 382 | else |
358 | printk(KERN_INFO "DMI present.\n"); | 383 | printk(KERN_INFO "DMI present.\n"); |
359 | if (dmi_walk_early(dmi_decode) == 0) | 384 | if (dmi_walk_early(dmi_decode) == 0) |
360 | return 0; | 385 | return 0; |
361 | } | 386 | } |
362 | return 1; | 387 | return 1; |
363 | } | 388 | } |
364 | 389 | ||
365 | void __init dmi_scan_machine(void) | 390 | void __init dmi_scan_machine(void) |
366 | { | 391 | { |
367 | char __iomem *p, *q; | 392 | char __iomem *p, *q; |
368 | int rc; | 393 | int rc; |
369 | 394 | ||
370 | if (efi_enabled) { | 395 | if (efi_enabled) { |
371 | if (efi.smbios == EFI_INVALID_TABLE_ADDR) | 396 | if (efi.smbios == EFI_INVALID_TABLE_ADDR) |
372 | goto error; | 397 | goto error; |
373 | 398 | ||
374 | /* This is called as a core_initcall() because it isn't | 399 | /* This is called as a core_initcall() because it isn't |
375 | * needed during early boot. This also means we can | 400 | * needed during early boot. This also means we can |
376 | * iounmap the space when we're done with it. | 401 | * iounmap the space when we're done with it. |
377 | */ | 402 | */ |
378 | p = dmi_ioremap(efi.smbios, 32); | 403 | p = dmi_ioremap(efi.smbios, 32); |
379 | if (p == NULL) | 404 | if (p == NULL) |
380 | goto error; | 405 | goto error; |
381 | 406 | ||
382 | rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ | 407 | rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ |
383 | dmi_iounmap(p, 32); | 408 | dmi_iounmap(p, 32); |
384 | if (!rc) { | 409 | if (!rc) { |
385 | dmi_available = 1; | 410 | dmi_available = 1; |
386 | goto out; | 411 | goto out; |
387 | } | 412 | } |
388 | } | 413 | } |
389 | else { | 414 | else { |
390 | /* | 415 | /* |
391 | * no iounmap() for that ioremap(); it would be a no-op, but | 416 | * no iounmap() for that ioremap(); it would be a no-op, but |
392 | * it's so early in setup that sucker gets confused into doing | 417 | * it's so early in setup that sucker gets confused into doing |
393 | * what it shouldn't if we actually call it. | 418 | * what it shouldn't if we actually call it. |
394 | */ | 419 | */ |
395 | p = dmi_ioremap(0xF0000, 0x10000); | 420 | p = dmi_ioremap(0xF0000, 0x10000); |
396 | if (p == NULL) | 421 | if (p == NULL) |
397 | goto error; | 422 | goto error; |
398 | 423 | ||
399 | for (q = p; q < p + 0x10000; q += 16) { | 424 | for (q = p; q < p + 0x10000; q += 16) { |
400 | rc = dmi_present(q); | 425 | rc = dmi_present(q); |
401 | if (!rc) { | 426 | if (!rc) { |
402 | dmi_available = 1; | 427 | dmi_available = 1; |
403 | dmi_iounmap(p, 0x10000); | 428 | dmi_iounmap(p, 0x10000); |
404 | goto out; | 429 | goto out; |
405 | } | 430 | } |
406 | } | 431 | } |
407 | dmi_iounmap(p, 0x10000); | 432 | dmi_iounmap(p, 0x10000); |
408 | } | 433 | } |
409 | error: | 434 | error: |
410 | printk(KERN_INFO "DMI not present or invalid.\n"); | 435 | printk(KERN_INFO "DMI not present or invalid.\n"); |
411 | out: | 436 | out: |
412 | dmi_initialized = 1; | 437 | dmi_initialized = 1; |
413 | } | 438 | } |
414 | 439 | ||
415 | /** | 440 | /** |
416 | * dmi_matches - check if dmi_system_id structure matches system DMI data | 441 | * dmi_matches - check if dmi_system_id structure matches system DMI data |
417 | * @dmi: pointer to the dmi_system_id structure to check | 442 | * @dmi: pointer to the dmi_system_id structure to check |
418 | */ | 443 | */ |
419 | static bool dmi_matches(const struct dmi_system_id *dmi) | 444 | static bool dmi_matches(const struct dmi_system_id *dmi) |
420 | { | 445 | { |
421 | int i; | 446 | int i; |
422 | 447 | ||
423 | WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); | 448 | WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); |
424 | 449 | ||
425 | for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { | 450 | for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { |
426 | int s = dmi->matches[i].slot; | 451 | int s = dmi->matches[i].slot; |
427 | if (s == DMI_NONE) | 452 | if (s == DMI_NONE) |
428 | break; | 453 | break; |
429 | if (dmi_ident[s] | 454 | if (dmi_ident[s] |
430 | && strstr(dmi_ident[s], dmi->matches[i].substr)) | 455 | && strstr(dmi_ident[s], dmi->matches[i].substr)) |
431 | continue; | 456 | continue; |
432 | /* No match */ | 457 | /* No match */ |
433 | return false; | 458 | return false; |
434 | } | 459 | } |
435 | return true; | 460 | return true; |
436 | } | 461 | } |
437 | 462 | ||
438 | /** | 463 | /** |
439 | * dmi_is_end_of_table - check for end-of-table marker | 464 | * dmi_is_end_of_table - check for end-of-table marker |
440 | * @dmi: pointer to the dmi_system_id structure to check | 465 | * @dmi: pointer to the dmi_system_id structure to check |
441 | */ | 466 | */ |
442 | static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) | 467 | static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) |
443 | { | 468 | { |
444 | return dmi->matches[0].slot == DMI_NONE; | 469 | return dmi->matches[0].slot == DMI_NONE; |
445 | } | 470 | } |
446 | 471 | ||
447 | /** | 472 | /** |
448 | * dmi_check_system - check system DMI data | 473 | * dmi_check_system - check system DMI data |
449 | * @list: array of dmi_system_id structures to match against | 474 | * @list: array of dmi_system_id structures to match against |
450 | * All non-null elements of the list must match | 475 | * All non-null elements of the list must match |
451 | * their slot's (field index's) data (i.e., each | 476 | * their slot's (field index's) data (i.e., each |
452 | * list string must be a substring of the specified | 477 | * list string must be a substring of the specified |
453 | * DMI slot's string data) to be considered a | 478 | * DMI slot's string data) to be considered a |
454 | * successful match. | 479 | * successful match. |
455 | * | 480 | * |
456 | * Walk the blacklist table running matching functions until someone | 481 | * Walk the blacklist table running matching functions until someone |
457 | * returns non zero or we hit the end. Callback function is called for | 482 | * returns non zero or we hit the end. Callback function is called for |
458 | * each successful match. Returns the number of matches. | 483 | * each successful match. Returns the number of matches. |
459 | */ | 484 | */ |
460 | int dmi_check_system(const struct dmi_system_id *list) | 485 | int dmi_check_system(const struct dmi_system_id *list) |
461 | { | 486 | { |
462 | int count = 0; | 487 | int count = 0; |
463 | const struct dmi_system_id *d; | 488 | const struct dmi_system_id *d; |
464 | 489 | ||
465 | for (d = list; !dmi_is_end_of_table(d); d++) | 490 | for (d = list; !dmi_is_end_of_table(d); d++) |
466 | if (dmi_matches(d)) { | 491 | if (dmi_matches(d)) { |
467 | count++; | 492 | count++; |
468 | if (d->callback && d->callback(d)) | 493 | if (d->callback && d->callback(d)) |
469 | break; | 494 | break; |
470 | } | 495 | } |
471 | 496 | ||
472 | return count; | 497 | return count; |
473 | } | 498 | } |
474 | EXPORT_SYMBOL(dmi_check_system); | 499 | EXPORT_SYMBOL(dmi_check_system); |
475 | 500 | ||
476 | /** | 501 | /** |
477 | * dmi_first_match - find dmi_system_id structure matching system DMI data | 502 | * dmi_first_match - find dmi_system_id structure matching system DMI data |
478 | * @list: array of dmi_system_id structures to match against | 503 | * @list: array of dmi_system_id structures to match against |
479 | * All non-null elements of the list must match | 504 | * All non-null elements of the list must match |
480 | * their slot's (field index's) data (i.e., each | 505 | * their slot's (field index's) data (i.e., each |
481 | * list string must be a substring of the specified | 506 | * list string must be a substring of the specified |
482 | * DMI slot's string data) to be considered a | 507 | * DMI slot's string data) to be considered a |
483 | * successful match. | 508 | * successful match. |
484 | * | 509 | * |
485 | * Walk the blacklist table until the first match is found. Return the | 510 | * Walk the blacklist table until the first match is found. Return the |
486 | * pointer to the matching entry or NULL if there's no match. | 511 | * pointer to the matching entry or NULL if there's no match. |
487 | */ | 512 | */ |
488 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) | 513 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) |
489 | { | 514 | { |
490 | const struct dmi_system_id *d; | 515 | const struct dmi_system_id *d; |
491 | 516 | ||
492 | for (d = list; !dmi_is_end_of_table(d); d++) | 517 | for (d = list; !dmi_is_end_of_table(d); d++) |
493 | if (dmi_matches(d)) | 518 | if (dmi_matches(d)) |
494 | return d; | 519 | return d; |
495 | 520 | ||
496 | return NULL; | 521 | return NULL; |
497 | } | 522 | } |
498 | EXPORT_SYMBOL(dmi_first_match); | 523 | EXPORT_SYMBOL(dmi_first_match); |
499 | 524 | ||
500 | /** | 525 | /** |
501 | * dmi_get_system_info - return DMI data value | 526 | * dmi_get_system_info - return DMI data value |
502 | * @field: data index (see enum dmi_field) | 527 | * @field: data index (see enum dmi_field) |
503 | * | 528 | * |
504 | * Returns one DMI data value, can be used to perform | 529 | * Returns one DMI data value, can be used to perform |
505 | * complex DMI data checks. | 530 | * complex DMI data checks. |
506 | */ | 531 | */ |
507 | const char *dmi_get_system_info(int field) | 532 | const char *dmi_get_system_info(int field) |
508 | { | 533 | { |
509 | return dmi_ident[field]; | 534 | return dmi_ident[field]; |
510 | } | 535 | } |
511 | EXPORT_SYMBOL(dmi_get_system_info); | 536 | EXPORT_SYMBOL(dmi_get_system_info); |
512 | 537 | ||
513 | /** | 538 | /** |
514 | * dmi_name_in_serial - Check if string is in the DMI product serial information | 539 | * dmi_name_in_serial - Check if string is in the DMI product serial information |
515 | * @str: string to check for | 540 | * @str: string to check for |
516 | */ | 541 | */ |
517 | int dmi_name_in_serial(const char *str) | 542 | int dmi_name_in_serial(const char *str) |
518 | { | 543 | { |
519 | int f = DMI_PRODUCT_SERIAL; | 544 | int f = DMI_PRODUCT_SERIAL; |
520 | if (dmi_ident[f] && strstr(dmi_ident[f], str)) | 545 | if (dmi_ident[f] && strstr(dmi_ident[f], str)) |
521 | return 1; | 546 | return 1; |
522 | return 0; | 547 | return 0; |
523 | } | 548 | } |
524 | 549 | ||
525 | /** | 550 | /** |
526 | * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. | 551 | * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. |
527 | * @str: Case sensitive Name | 552 | * @str: Case sensitive Name |
528 | */ | 553 | */ |
529 | int dmi_name_in_vendors(const char *str) | 554 | int dmi_name_in_vendors(const char *str) |
530 | { | 555 | { |
531 | static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, | 556 | static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, |
532 | DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, | 557 | DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, |
533 | DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; | 558 | DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; |
534 | int i; | 559 | int i; |
535 | for (i = 0; fields[i] != DMI_NONE; i++) { | 560 | for (i = 0; fields[i] != DMI_NONE; i++) { |
536 | int f = fields[i]; | 561 | int f = fields[i]; |
537 | if (dmi_ident[f] && strstr(dmi_ident[f], str)) | 562 | if (dmi_ident[f] && strstr(dmi_ident[f], str)) |
538 | return 1; | 563 | return 1; |
539 | } | 564 | } |
540 | return 0; | 565 | return 0; |
541 | } | 566 | } |
542 | EXPORT_SYMBOL(dmi_name_in_vendors); | 567 | EXPORT_SYMBOL(dmi_name_in_vendors); |
543 | 568 | ||
544 | /** | 569 | /** |
545 | * dmi_find_device - find onboard device by type/name | 570 | * dmi_find_device - find onboard device by type/name |
546 | * @type: device type or %DMI_DEV_TYPE_ANY to match all device types | 571 | * @type: device type or %DMI_DEV_TYPE_ANY to match all device types |
547 | * @name: device name string or %NULL to match all | 572 | * @name: device name string or %NULL to match all |
548 | * @from: previous device found in search, or %NULL for new search. | 573 | * @from: previous device found in search, or %NULL for new search. |
549 | * | 574 | * |
550 | * Iterates through the list of known onboard devices. If a device is | 575 | * Iterates through the list of known onboard devices. If a device is |
551 | * found with a matching @vendor and @device, a pointer to its device | 576 | * found with a matching @vendor and @device, a pointer to its device |
552 | * structure is returned. Otherwise, %NULL is returned. | 577 | * structure is returned. Otherwise, %NULL is returned. |
553 | * A new search is initiated by passing %NULL as the @from argument. | 578 | * A new search is initiated by passing %NULL as the @from argument. |
554 | * If @from is not %NULL, searches continue from next device. | 579 | * If @from is not %NULL, searches continue from next device. |
555 | */ | 580 | */ |
556 | const struct dmi_device * dmi_find_device(int type, const char *name, | 581 | const struct dmi_device * dmi_find_device(int type, const char *name, |
557 | const struct dmi_device *from) | 582 | const struct dmi_device *from) |
558 | { | 583 | { |
559 | const struct list_head *head = from ? &from->list : &dmi_devices; | 584 | const struct list_head *head = from ? &from->list : &dmi_devices; |
560 | struct list_head *d; | 585 | struct list_head *d; |
561 | 586 | ||
562 | for(d = head->next; d != &dmi_devices; d = d->next) { | 587 | for(d = head->next; d != &dmi_devices; d = d->next) { |
563 | const struct dmi_device *dev = | 588 | const struct dmi_device *dev = |
564 | list_entry(d, struct dmi_device, list); | 589 | list_entry(d, struct dmi_device, list); |
565 | 590 | ||
566 | if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && | 591 | if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && |
567 | ((name == NULL) || (strcmp(dev->name, name) == 0))) | 592 | ((name == NULL) || (strcmp(dev->name, name) == 0))) |
568 | return dev; | 593 | return dev; |
569 | } | 594 | } |
570 | 595 | ||
571 | return NULL; | 596 | return NULL; |
572 | } | 597 | } |
573 | EXPORT_SYMBOL(dmi_find_device); | 598 | EXPORT_SYMBOL(dmi_find_device); |
574 | 599 | ||
575 | /** | 600 | /** |
576 | * dmi_get_date - parse a DMI date | 601 | * dmi_get_date - parse a DMI date |
577 | * @field: data index (see enum dmi_field) | 602 | * @field: data index (see enum dmi_field) |
578 | * @yearp: optional out parameter for the year | 603 | * @yearp: optional out parameter for the year |
579 | * @monthp: optional out parameter for the month | 604 | * @monthp: optional out parameter for the month |
580 | * @dayp: optional out parameter for the day | 605 | * @dayp: optional out parameter for the day |
581 | * | 606 | * |
582 | * The date field is assumed to be in the form resembling | 607 | * The date field is assumed to be in the form resembling |
583 | * [mm[/dd]]/yy[yy] and the result is stored in the out | 608 | * [mm[/dd]]/yy[yy] and the result is stored in the out |
584 | * parameters any or all of which can be omitted. | 609 | * parameters any or all of which can be omitted. |
585 | * | 610 | * |
586 | * If the field doesn't exist, all out parameters are set to zero | 611 | * If the field doesn't exist, all out parameters are set to zero |
587 | * and false is returned. Otherwise, true is returned with any | 612 | * and false is returned. Otherwise, true is returned with any |
588 | * invalid part of date set to zero. | 613 | * invalid part of date set to zero. |
589 | * | 614 | * |
590 | * On return, year, month and day are guaranteed to be in the | 615 | * On return, year, month and day are guaranteed to be in the |
591 | * range of [0,9999], [0,12] and [0,31] respectively. | 616 | * range of [0,9999], [0,12] and [0,31] respectively. |
592 | */ | 617 | */ |
593 | bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) | 618 | bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) |
594 | { | 619 | { |
595 | int year = 0, month = 0, day = 0; | 620 | int year = 0, month = 0, day = 0; |
596 | bool exists; | 621 | bool exists; |
597 | const char *s, *y; | 622 | const char *s, *y; |
598 | char *e; | 623 | char *e; |
599 | 624 | ||
600 | s = dmi_get_system_info(field); | 625 | s = dmi_get_system_info(field); |
601 | exists = s; | 626 | exists = s; |
602 | if (!exists) | 627 | if (!exists) |
603 | goto out; | 628 | goto out; |
604 | 629 | ||
605 | /* | 630 | /* |
606 | * Determine year first. We assume the date string resembles | 631 | * Determine year first. We assume the date string resembles |
607 | * mm/dd/yy[yy] but the original code extracted only the year | 632 | * mm/dd/yy[yy] but the original code extracted only the year |
608 | * from the end. Keep the behavior in the spirit of no | 633 | * from the end. Keep the behavior in the spirit of no |
609 | * surprises. | 634 | * surprises. |
610 | */ | 635 | */ |
611 | y = strrchr(s, '/'); | 636 | y = strrchr(s, '/'); |
612 | if (!y) | 637 | if (!y) |
613 | goto out; | 638 | goto out; |
614 | 639 | ||
615 | y++; | 640 | y++; |
616 | year = simple_strtoul(y, &e, 10); | 641 | year = simple_strtoul(y, &e, 10); |
617 | if (y != e && year < 100) { /* 2-digit year */ | 642 | if (y != e && year < 100) { /* 2-digit year */ |
618 | year += 1900; | 643 | year += 1900; |
619 | if (year < 1996) /* no dates < spec 1.0 */ | 644 | if (year < 1996) /* no dates < spec 1.0 */ |
620 | year += 100; | 645 | year += 100; |
621 | } | 646 | } |
622 | if (year > 9999) /* year should fit in %04d */ | 647 | if (year > 9999) /* year should fit in %04d */ |
623 | year = 0; | 648 | year = 0; |
624 | 649 | ||
625 | /* parse the mm and dd */ | 650 | /* parse the mm and dd */ |
626 | month = simple_strtoul(s, &e, 10); | 651 | month = simple_strtoul(s, &e, 10); |
627 | if (s == e || *e != '/' || !month || month > 12) { | 652 | if (s == e || *e != '/' || !month || month > 12) { |
628 | month = 0; | 653 | month = 0; |
629 | goto out; | 654 | goto out; |
630 | } | 655 | } |
631 | 656 | ||
632 | s = e + 1; | 657 | s = e + 1; |
633 | day = simple_strtoul(s, &e, 10); | 658 | day = simple_strtoul(s, &e, 10); |
634 | if (s == y || s == e || *e != '/' || day > 31) | 659 | if (s == y || s == e || *e != '/' || day > 31) |
635 | day = 0; | 660 | day = 0; |
636 | out: | 661 | out: |
637 | if (yearp) | 662 | if (yearp) |
638 | *yearp = year; | 663 | *yearp = year; |
639 | if (monthp) | 664 | if (monthp) |
640 | *monthp = month; | 665 | *monthp = month; |
641 | if (dayp) | 666 | if (dayp) |
642 | *dayp = day; | 667 | *dayp = day; |
643 | return exists; | 668 | return exists; |
644 | } | 669 | } |
645 | EXPORT_SYMBOL(dmi_get_date); | 670 | EXPORT_SYMBOL(dmi_get_date); |
646 | 671 | ||
647 | /** | 672 | /** |
648 | * dmi_walk - Walk the DMI table and get called back for every record | 673 | * dmi_walk - Walk the DMI table and get called back for every record |
649 | * @decode: Callback function | 674 | * @decode: Callback function |
650 | * @private_data: Private data to be passed to the callback function | 675 | * @private_data: Private data to be passed to the callback function |
651 | * | 676 | * |
652 | * Returns -1 when the DMI table can't be reached, 0 on success. | 677 | * Returns -1 when the DMI table can't be reached, 0 on success. |
653 | */ | 678 | */ |
654 | int dmi_walk(void (*decode)(const struct dmi_header *, void *), | 679 | int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
655 | void *private_data) | 680 | void *private_data) |
656 | { | 681 | { |
657 | u8 *buf; | 682 | u8 *buf; |
658 | 683 | ||
659 | if (!dmi_available) | 684 | if (!dmi_available) |
660 | return -1; | 685 | return -1; |
661 | 686 | ||
662 | buf = ioremap(dmi_base, dmi_len); | 687 | buf = ioremap(dmi_base, dmi_len); |
663 | if (buf == NULL) | 688 | if (buf == NULL) |
664 | return -1; | 689 | return -1; |
665 | 690 | ||
666 | dmi_table(buf, dmi_len, dmi_num, decode, private_data); | 691 | dmi_table(buf, dmi_len, dmi_num, decode, private_data); |
667 | 692 | ||
668 | iounmap(buf); | 693 | iounmap(buf); |
669 | return 0; | 694 | return 0; |
670 | } | 695 | } |
671 | EXPORT_SYMBOL_GPL(dmi_walk); | 696 | EXPORT_SYMBOL_GPL(dmi_walk); |
672 | 697 | ||
673 | /** | 698 | /** |
674 | * dmi_match - compare a string to the dmi field (if exists) | 699 | * dmi_match - compare a string to the dmi field (if exists) |
675 | * @f: DMI field identifier | 700 | * @f: DMI field identifier |
676 | * @str: string to compare the DMI field to | 701 | * @str: string to compare the DMI field to |
677 | * | 702 | * |
678 | * Returns true if the requested field equals to the str (including NULL). | 703 | * Returns true if the requested field equals to the str (including NULL). |
679 | */ | 704 | */ |
680 | bool dmi_match(enum dmi_field f, const char *str) | 705 | bool dmi_match(enum dmi_field f, const char *str) |
681 | { | 706 | { |
682 | const char *info = dmi_get_system_info(f); | 707 | const char *info = dmi_get_system_info(f); |
683 | 708 | ||
684 | if (info == NULL || str == NULL) | 709 | if (info == NULL || str == NULL) |
685 | return info == str; | 710 | return info == str; |
686 | 711 | ||
687 | return !strcmp(info, str); | 712 | return !strcmp(info, str); |
688 | } | 713 | } |
689 | EXPORT_SYMBOL_GPL(dmi_match); | 714 | EXPORT_SYMBOL_GPL(dmi_match); |
690 | 715 |
drivers/pci/Makefile
1 | # | 1 | # |
2 | # Makefile for the PCI bus specific drivers. | 2 | # Makefile for the PCI bus specific drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += access.o bus.o probe.o remove.o pci.o \ | 5 | obj-y += access.o bus.o probe.o remove.o pci.o \ |
6 | pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ | 6 | pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ |
7 | irq.o vpd.o | 7 | irq.o vpd.o |
8 | obj-$(CONFIG_PROC_FS) += proc.o | 8 | obj-$(CONFIG_PROC_FS) += proc.o |
9 | obj-$(CONFIG_SYSFS) += slot.o | 9 | obj-$(CONFIG_SYSFS) += slot.o |
10 | 10 | ||
11 | obj-$(CONFIG_PCI_QUIRKS) += quirks.o | 11 | obj-$(CONFIG_PCI_QUIRKS) += quirks.o |
12 | 12 | ||
13 | # Build PCI Express stuff if needed | 13 | # Build PCI Express stuff if needed |
14 | obj-$(CONFIG_PCIEPORTBUS) += pcie/ | 14 | obj-$(CONFIG_PCIEPORTBUS) += pcie/ |
15 | 15 | ||
16 | obj-$(CONFIG_PCI_IOAPIC) += ioapic.o | 16 | obj-$(CONFIG_PCI_IOAPIC) += ioapic.o |
17 | 17 | ||
18 | obj-$(CONFIG_HOTPLUG) += hotplug.o | 18 | obj-$(CONFIG_HOTPLUG) += hotplug.o |
19 | 19 | ||
20 | # Build the PCI Hotplug drivers if we were asked to | 20 | # Build the PCI Hotplug drivers if we were asked to |
21 | obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ | 21 | obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ |
22 | ifdef CONFIG_HOTPLUG_PCI | 22 | ifdef CONFIG_HOTPLUG_PCI |
23 | obj-y += hotplug-pci.o | 23 | obj-y += hotplug-pci.o |
24 | endif | 24 | endif |
25 | 25 | ||
26 | # Build the PCI MSI interrupt support | 26 | # Build the PCI MSI interrupt support |
27 | obj-$(CONFIG_PCI_MSI) += msi.o | 27 | obj-$(CONFIG_PCI_MSI) += msi.o |
28 | 28 | ||
29 | # Build the Hypertransport interrupt support | 29 | # Build the Hypertransport interrupt support |
30 | obj-$(CONFIG_HT_IRQ) += htirq.o | 30 | obj-$(CONFIG_HT_IRQ) += htirq.o |
31 | 31 | ||
32 | # Build Intel IOMMU support | 32 | # Build Intel IOMMU support |
33 | obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o | 33 | obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o |
34 | 34 | ||
35 | obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o | 35 | obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o |
36 | 36 | ||
37 | obj-$(CONFIG_PCI_IOV) += iov.o | 37 | obj-$(CONFIG_PCI_IOV) += iov.o |
38 | 38 | ||
39 | # | 39 | # |
40 | # Some architectures use the generic PCI setup functions | 40 | # Some architectures use the generic PCI setup functions |
41 | # | 41 | # |
42 | obj-$(CONFIG_X86) += setup-bus.o | 42 | obj-$(CONFIG_X86) += setup-bus.o |
43 | obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o | 43 | obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o |
44 | obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o | 44 | obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o |
45 | obj-$(CONFIG_PARISC) += setup-bus.o | 45 | obj-$(CONFIG_PARISC) += setup-bus.o |
46 | obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o | 46 | obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o |
47 | obj-$(CONFIG_PPC) += setup-bus.o | 47 | obj-$(CONFIG_PPC) += setup-bus.o |
48 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o | 48 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o |
49 | obj-$(CONFIG_X86_VISWS) += setup-irq.o | 49 | obj-$(CONFIG_X86_VISWS) += setup-irq.o |
50 | obj-$(CONFIG_MN10300) += setup-bus.o | 50 | obj-$(CONFIG_MN10300) += setup-bus.o |
51 | obj-$(CONFIG_MICROBLAZE) += setup-bus.o | 51 | obj-$(CONFIG_MICROBLAZE) += setup-bus.o |
52 | 52 | ||
53 | # | 53 | # |
54 | # ACPI Related PCI FW Functions | 54 | # ACPI Related PCI FW Functions |
55 | # | 55 | # |
56 | obj-$(CONFIG_ACPI) += pci-acpi.o | 56 | obj-$(CONFIG_ACPI) += pci-acpi.o |
57 | 57 | ||
58 | # SMBIOS provided firmware instance and labels | ||
59 | obj-$(CONFIG_DMI) += pci-label.o | ||
60 | |||
58 | # Cardbus & CompactPCI use setup-bus | 61 | # Cardbus & CompactPCI use setup-bus |
59 | obj-$(CONFIG_HOTPLUG) += setup-bus.o | 62 | obj-$(CONFIG_HOTPLUG) += setup-bus.o |
60 | 63 | ||
61 | obj-$(CONFIG_PCI_SYSCALL) += syscall.o | 64 | obj-$(CONFIG_PCI_SYSCALL) += syscall.o |
62 | 65 | ||
63 | obj-$(CONFIG_PCI_STUB) += pci-stub.o | 66 | obj-$(CONFIG_PCI_STUB) += pci-stub.o |
64 | 67 | ||
65 | ifeq ($(CONFIG_PCI_DEBUG),y) | 68 | ifeq ($(CONFIG_PCI_DEBUG),y) |
66 | EXTRA_CFLAGS += -DDEBUG | 69 | EXTRA_CFLAGS += -DDEBUG |
67 | endif | 70 | endif |
68 | 71 |
drivers/pci/pci-label.c
File was created | 1 | /* | |
2 | * Purpose: Export the firmware instance and label associated with | ||
3 | * a pci device to sysfs | ||
4 | * Copyright (C) 2010 Dell Inc. | ||
5 | * by Narendra K <Narendra_K@dell.com>, | ||
6 | * Jordan Hargrave <Jordan_Hargrave@dell.com> | ||
7 | * | ||
8 | * SMBIOS defines type 41 for onboard pci devices. This code retrieves | ||
9 | * the instance number and string from the type 41 record and exports | ||
10 | * it to sysfs. | ||
11 | * | ||
12 | * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more | ||
13 | * information. | ||
14 | */ | ||
15 | |||
16 | #include <linux/dmi.h> | ||
17 | #include <linux/sysfs.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/pci_ids.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/device.h> | ||
22 | #include "pci.h" | ||
23 | |||
24 | enum smbios_attr_enum { | ||
25 | SMBIOS_ATTR_NONE = 0, | ||
26 | SMBIOS_ATTR_LABEL_SHOW, | ||
27 | SMBIOS_ATTR_INSTANCE_SHOW, | ||
28 | }; | ||
29 | |||
30 | static mode_t | ||
31 | find_smbios_instance_string(struct pci_dev *pdev, char *buf, | ||
32 | enum smbios_attr_enum attribute) | ||
33 | { | ||
34 | const struct dmi_device *dmi; | ||
35 | struct dmi_dev_onboard *donboard; | ||
36 | int bus; | ||
37 | int devfn; | ||
38 | |||
39 | bus = pdev->bus->number; | ||
40 | devfn = pdev->devfn; | ||
41 | |||
42 | dmi = NULL; | ||
43 | while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, | ||
44 | NULL, dmi)) != NULL) { | ||
45 | donboard = dmi->device_data; | ||
46 | if (donboard && donboard->bus == bus && | ||
47 | donboard->devfn == devfn) { | ||
48 | if (buf) { | ||
49 | if (attribute == SMBIOS_ATTR_INSTANCE_SHOW) | ||
50 | return scnprintf(buf, PAGE_SIZE, | ||
51 | "%d\n", | ||
52 | donboard->instance); | ||
53 | else if (attribute == SMBIOS_ATTR_LABEL_SHOW) | ||
54 | return scnprintf(buf, PAGE_SIZE, | ||
55 | "%s\n", | ||
56 | dmi->name); | ||
57 | } | ||
58 | return strlen(dmi->name); | ||
59 | } | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static mode_t | ||
65 | smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr, | ||
66 | int n) | ||
67 | { | ||
68 | struct device *dev; | ||
69 | struct pci_dev *pdev; | ||
70 | |||
71 | dev = container_of(kobj, struct device, kobj); | ||
72 | pdev = to_pci_dev(dev); | ||
73 | |||
74 | return find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE) ? | ||
75 | S_IRUGO : 0; | ||
76 | } | ||
77 | |||
78 | static ssize_t | ||
79 | smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
80 | { | ||
81 | struct pci_dev *pdev; | ||
82 | pdev = to_pci_dev(dev); | ||
83 | |||
84 | return find_smbios_instance_string(pdev, buf, | ||
85 | SMBIOS_ATTR_LABEL_SHOW); | ||
86 | } | ||
87 | |||
88 | static ssize_t | ||
89 | smbiosinstance_show(struct device *dev, | ||
90 | struct device_attribute *attr, char *buf) | ||
91 | { | ||
92 | struct pci_dev *pdev; | ||
93 | pdev = to_pci_dev(dev); | ||
94 | |||
95 | return find_smbios_instance_string(pdev, buf, | ||
96 | SMBIOS_ATTR_INSTANCE_SHOW); | ||
97 | } | ||
98 | |||
99 | static struct device_attribute smbios_attr_label = { | ||
100 | .attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE}, | ||
101 | .show = smbioslabel_show, | ||
102 | }; | ||
103 | |||
104 | static struct device_attribute smbios_attr_instance = { | ||
105 | .attr = {.name = "index", .mode = 0444, .owner = THIS_MODULE}, | ||
106 | .show = smbiosinstance_show, | ||
107 | }; | ||
108 | |||
109 | static struct attribute *smbios_attributes[] = { | ||
110 | &smbios_attr_label.attr, | ||
111 | &smbios_attr_instance.attr, | ||
112 | NULL, | ||
113 | }; | ||
114 | |||
115 | static struct attribute_group smbios_attr_group = { | ||
116 | .attrs = smbios_attributes, | ||
117 | .is_visible = smbios_instance_string_exist, | ||
118 | }; | ||
119 | |||
120 | static int | ||
121 | pci_create_smbiosname_file(struct pci_dev *pdev) | ||
122 | { | ||
123 | if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group)) | ||
124 | return 0; | ||
125 | return -ENODEV; | ||
126 | } | ||
127 | |||
128 | static void | ||
129 | pci_remove_smbiosname_file(struct pci_dev *pdev) | ||
130 | { | ||
131 | sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); | ||
132 | } | ||
133 | |||
134 | void pci_create_firmware_label_files(struct pci_dev *pdev) | ||
135 | { | ||
136 | if (!pci_create_smbiosname_file(pdev)) | ||
137 | ; | ||
138 | } | ||
139 | |||
140 | void pci_remove_firmware_label_files(struct pci_dev *pdev) | ||
141 | { | ||
142 | pci_remove_smbiosname_file(pdev); | ||
143 | } | ||
144 |
drivers/pci/pci-sysfs.c
1 | /* | 1 | /* |
2 | * drivers/pci/pci-sysfs.c | 2 | * drivers/pci/pci-sysfs.c |
3 | * | 3 | * |
4 | * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com> | 4 | * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com> |
5 | * (C) Copyright 2002-2004 IBM Corp. | 5 | * (C) Copyright 2002-2004 IBM Corp. |
6 | * (C) Copyright 2003 Matthew Wilcox | 6 | * (C) Copyright 2003 Matthew Wilcox |
7 | * (C) Copyright 2003 Hewlett-Packard | 7 | * (C) Copyright 2003 Hewlett-Packard |
8 | * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com> | 8 | * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com> |
9 | * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com> | 9 | * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com> |
10 | * | 10 | * |
11 | * File attributes for PCI devices | 11 | * File attributes for PCI devices |
12 | * | 12 | * |
13 | * Modeled after usb's driverfs.c | 13 | * Modeled after usb's driverfs.c |
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | #include <linux/stat.h> | 21 | #include <linux/stat.h> |
22 | #include <linux/topology.h> | 22 | #include <linux/topology.h> |
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
26 | #include <linux/pci-aspm.h> | 26 | #include <linux/pci-aspm.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include "pci.h" | 28 | #include "pci.h" |
29 | 29 | ||
30 | static int sysfs_initialized; /* = 0 */ | 30 | static int sysfs_initialized; /* = 0 */ |
31 | 31 | ||
32 | /* show configuration fields */ | 32 | /* show configuration fields */ |
33 | #define pci_config_attr(field, format_string) \ | 33 | #define pci_config_attr(field, format_string) \ |
34 | static ssize_t \ | 34 | static ssize_t \ |
35 | field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ | 35 | field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ |
36 | { \ | 36 | { \ |
37 | struct pci_dev *pdev; \ | 37 | struct pci_dev *pdev; \ |
38 | \ | 38 | \ |
39 | pdev = to_pci_dev (dev); \ | 39 | pdev = to_pci_dev (dev); \ |
40 | return sprintf (buf, format_string, pdev->field); \ | 40 | return sprintf (buf, format_string, pdev->field); \ |
41 | } | 41 | } |
42 | 42 | ||
43 | pci_config_attr(vendor, "0x%04x\n"); | 43 | pci_config_attr(vendor, "0x%04x\n"); |
44 | pci_config_attr(device, "0x%04x\n"); | 44 | pci_config_attr(device, "0x%04x\n"); |
45 | pci_config_attr(subsystem_vendor, "0x%04x\n"); | 45 | pci_config_attr(subsystem_vendor, "0x%04x\n"); |
46 | pci_config_attr(subsystem_device, "0x%04x\n"); | 46 | pci_config_attr(subsystem_device, "0x%04x\n"); |
47 | pci_config_attr(class, "0x%06x\n"); | 47 | pci_config_attr(class, "0x%06x\n"); |
48 | pci_config_attr(irq, "%u\n"); | 48 | pci_config_attr(irq, "%u\n"); |
49 | 49 | ||
50 | static ssize_t broken_parity_status_show(struct device *dev, | 50 | static ssize_t broken_parity_status_show(struct device *dev, |
51 | struct device_attribute *attr, | 51 | struct device_attribute *attr, |
52 | char *buf) | 52 | char *buf) |
53 | { | 53 | { |
54 | struct pci_dev *pdev = to_pci_dev(dev); | 54 | struct pci_dev *pdev = to_pci_dev(dev); |
55 | return sprintf (buf, "%u\n", pdev->broken_parity_status); | 55 | return sprintf (buf, "%u\n", pdev->broken_parity_status); |
56 | } | 56 | } |
57 | 57 | ||
58 | static ssize_t broken_parity_status_store(struct device *dev, | 58 | static ssize_t broken_parity_status_store(struct device *dev, |
59 | struct device_attribute *attr, | 59 | struct device_attribute *attr, |
60 | const char *buf, size_t count) | 60 | const char *buf, size_t count) |
61 | { | 61 | { |
62 | struct pci_dev *pdev = to_pci_dev(dev); | 62 | struct pci_dev *pdev = to_pci_dev(dev); |
63 | unsigned long val; | 63 | unsigned long val; |
64 | 64 | ||
65 | if (strict_strtoul(buf, 0, &val) < 0) | 65 | if (strict_strtoul(buf, 0, &val) < 0) |
66 | return -EINVAL; | 66 | return -EINVAL; |
67 | 67 | ||
68 | pdev->broken_parity_status = !!val; | 68 | pdev->broken_parity_status = !!val; |
69 | 69 | ||
70 | return count; | 70 | return count; |
71 | } | 71 | } |
72 | 72 | ||
73 | static ssize_t local_cpus_show(struct device *dev, | 73 | static ssize_t local_cpus_show(struct device *dev, |
74 | struct device_attribute *attr, char *buf) | 74 | struct device_attribute *attr, char *buf) |
75 | { | 75 | { |
76 | const struct cpumask *mask; | 76 | const struct cpumask *mask; |
77 | int len; | 77 | int len; |
78 | 78 | ||
79 | #ifdef CONFIG_NUMA | 79 | #ifdef CONFIG_NUMA |
80 | mask = (dev_to_node(dev) == -1) ? cpu_online_mask : | 80 | mask = (dev_to_node(dev) == -1) ? cpu_online_mask : |
81 | cpumask_of_node(dev_to_node(dev)); | 81 | cpumask_of_node(dev_to_node(dev)); |
82 | #else | 82 | #else |
83 | mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); | 83 | mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); |
84 | #endif | 84 | #endif |
85 | len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); | 85 | len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); |
86 | buf[len++] = '\n'; | 86 | buf[len++] = '\n'; |
87 | buf[len] = '\0'; | 87 | buf[len] = '\0'; |
88 | return len; | 88 | return len; |
89 | } | 89 | } |
90 | 90 | ||
91 | 91 | ||
92 | static ssize_t local_cpulist_show(struct device *dev, | 92 | static ssize_t local_cpulist_show(struct device *dev, |
93 | struct device_attribute *attr, char *buf) | 93 | struct device_attribute *attr, char *buf) |
94 | { | 94 | { |
95 | const struct cpumask *mask; | 95 | const struct cpumask *mask; |
96 | int len; | 96 | int len; |
97 | 97 | ||
98 | #ifdef CONFIG_NUMA | 98 | #ifdef CONFIG_NUMA |
99 | mask = (dev_to_node(dev) == -1) ? cpu_online_mask : | 99 | mask = (dev_to_node(dev) == -1) ? cpu_online_mask : |
100 | cpumask_of_node(dev_to_node(dev)); | 100 | cpumask_of_node(dev_to_node(dev)); |
101 | #else | 101 | #else |
102 | mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); | 102 | mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); |
103 | #endif | 103 | #endif |
104 | len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask); | 104 | len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask); |
105 | buf[len++] = '\n'; | 105 | buf[len++] = '\n'; |
106 | buf[len] = '\0'; | 106 | buf[len] = '\0'; |
107 | return len; | 107 | return len; |
108 | } | 108 | } |
109 | 109 | ||
110 | /* show resources */ | 110 | /* show resources */ |
111 | static ssize_t | 111 | static ssize_t |
112 | resource_show(struct device * dev, struct device_attribute *attr, char * buf) | 112 | resource_show(struct device * dev, struct device_attribute *attr, char * buf) |
113 | { | 113 | { |
114 | struct pci_dev * pci_dev = to_pci_dev(dev); | 114 | struct pci_dev * pci_dev = to_pci_dev(dev); |
115 | char * str = buf; | 115 | char * str = buf; |
116 | int i; | 116 | int i; |
117 | int max; | 117 | int max; |
118 | resource_size_t start, end; | 118 | resource_size_t start, end; |
119 | 119 | ||
120 | if (pci_dev->subordinate) | 120 | if (pci_dev->subordinate) |
121 | max = DEVICE_COUNT_RESOURCE; | 121 | max = DEVICE_COUNT_RESOURCE; |
122 | else | 122 | else |
123 | max = PCI_BRIDGE_RESOURCES; | 123 | max = PCI_BRIDGE_RESOURCES; |
124 | 124 | ||
125 | for (i = 0; i < max; i++) { | 125 | for (i = 0; i < max; i++) { |
126 | struct resource *res = &pci_dev->resource[i]; | 126 | struct resource *res = &pci_dev->resource[i]; |
127 | pci_resource_to_user(pci_dev, i, res, &start, &end); | 127 | pci_resource_to_user(pci_dev, i, res, &start, &end); |
128 | str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", | 128 | str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", |
129 | (unsigned long long)start, | 129 | (unsigned long long)start, |
130 | (unsigned long long)end, | 130 | (unsigned long long)end, |
131 | (unsigned long long)res->flags); | 131 | (unsigned long long)res->flags); |
132 | } | 132 | } |
133 | return (str - buf); | 133 | return (str - buf); |
134 | } | 134 | } |
135 | 135 | ||
136 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) | 136 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) |
137 | { | 137 | { |
138 | struct pci_dev *pci_dev = to_pci_dev(dev); | 138 | struct pci_dev *pci_dev = to_pci_dev(dev); |
139 | 139 | ||
140 | return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", | 140 | return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", |
141 | pci_dev->vendor, pci_dev->device, | 141 | pci_dev->vendor, pci_dev->device, |
142 | pci_dev->subsystem_vendor, pci_dev->subsystem_device, | 142 | pci_dev->subsystem_vendor, pci_dev->subsystem_device, |
143 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), | 143 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), |
144 | (u8)(pci_dev->class)); | 144 | (u8)(pci_dev->class)); |
145 | } | 145 | } |
146 | 146 | ||
147 | static ssize_t is_enabled_store(struct device *dev, | 147 | static ssize_t is_enabled_store(struct device *dev, |
148 | struct device_attribute *attr, const char *buf, | 148 | struct device_attribute *attr, const char *buf, |
149 | size_t count) | 149 | size_t count) |
150 | { | 150 | { |
151 | struct pci_dev *pdev = to_pci_dev(dev); | 151 | struct pci_dev *pdev = to_pci_dev(dev); |
152 | unsigned long val; | 152 | unsigned long val; |
153 | ssize_t result = strict_strtoul(buf, 0, &val); | 153 | ssize_t result = strict_strtoul(buf, 0, &val); |
154 | 154 | ||
155 | if (result < 0) | 155 | if (result < 0) |
156 | return result; | 156 | return result; |
157 | 157 | ||
158 | /* this can crash the machine when done on the "wrong" device */ | 158 | /* this can crash the machine when done on the "wrong" device */ |
159 | if (!capable(CAP_SYS_ADMIN)) | 159 | if (!capable(CAP_SYS_ADMIN)) |
160 | return -EPERM; | 160 | return -EPERM; |
161 | 161 | ||
162 | if (!val) { | 162 | if (!val) { |
163 | if (pci_is_enabled(pdev)) | 163 | if (pci_is_enabled(pdev)) |
164 | pci_disable_device(pdev); | 164 | pci_disable_device(pdev); |
165 | else | 165 | else |
166 | result = -EIO; | 166 | result = -EIO; |
167 | } else | 167 | } else |
168 | result = pci_enable_device(pdev); | 168 | result = pci_enable_device(pdev); |
169 | 169 | ||
170 | return result < 0 ? result : count; | 170 | return result < 0 ? result : count; |
171 | } | 171 | } |
172 | 172 | ||
173 | static ssize_t is_enabled_show(struct device *dev, | 173 | static ssize_t is_enabled_show(struct device *dev, |
174 | struct device_attribute *attr, char *buf) | 174 | struct device_attribute *attr, char *buf) |
175 | { | 175 | { |
176 | struct pci_dev *pdev; | 176 | struct pci_dev *pdev; |
177 | 177 | ||
178 | pdev = to_pci_dev (dev); | 178 | pdev = to_pci_dev (dev); |
179 | return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); | 179 | return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); |
180 | } | 180 | } |
181 | 181 | ||
182 | #ifdef CONFIG_NUMA | 182 | #ifdef CONFIG_NUMA |
183 | static ssize_t | 183 | static ssize_t |
184 | numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) | 184 | numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) |
185 | { | 185 | { |
186 | return sprintf (buf, "%d\n", dev->numa_node); | 186 | return sprintf (buf, "%d\n", dev->numa_node); |
187 | } | 187 | } |
188 | #endif | 188 | #endif |
189 | 189 | ||
190 | static ssize_t | 190 | static ssize_t |
191 | dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf) | 191 | dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf) |
192 | { | 192 | { |
193 | struct pci_dev *pdev = to_pci_dev(dev); | 193 | struct pci_dev *pdev = to_pci_dev(dev); |
194 | 194 | ||
195 | return sprintf (buf, "%d\n", fls64(pdev->dma_mask)); | 195 | return sprintf (buf, "%d\n", fls64(pdev->dma_mask)); |
196 | } | 196 | } |
197 | 197 | ||
198 | static ssize_t | 198 | static ssize_t |
199 | consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr, | 199 | consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr, |
200 | char *buf) | 200 | char *buf) |
201 | { | 201 | { |
202 | return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask)); | 202 | return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask)); |
203 | } | 203 | } |
204 | 204 | ||
205 | static ssize_t | 205 | static ssize_t |
206 | msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) | 206 | msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) |
207 | { | 207 | { |
208 | struct pci_dev *pdev = to_pci_dev(dev); | 208 | struct pci_dev *pdev = to_pci_dev(dev); |
209 | 209 | ||
210 | if (!pdev->subordinate) | 210 | if (!pdev->subordinate) |
211 | return 0; | 211 | return 0; |
212 | 212 | ||
213 | return sprintf (buf, "%u\n", | 213 | return sprintf (buf, "%u\n", |
214 | !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)); | 214 | !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)); |
215 | } | 215 | } |
216 | 216 | ||
217 | static ssize_t | 217 | static ssize_t |
218 | msi_bus_store(struct device *dev, struct device_attribute *attr, | 218 | msi_bus_store(struct device *dev, struct device_attribute *attr, |
219 | const char *buf, size_t count) | 219 | const char *buf, size_t count) |
220 | { | 220 | { |
221 | struct pci_dev *pdev = to_pci_dev(dev); | 221 | struct pci_dev *pdev = to_pci_dev(dev); |
222 | unsigned long val; | 222 | unsigned long val; |
223 | 223 | ||
224 | if (strict_strtoul(buf, 0, &val) < 0) | 224 | if (strict_strtoul(buf, 0, &val) < 0) |
225 | return -EINVAL; | 225 | return -EINVAL; |
226 | 226 | ||
227 | /* bad things may happen if the no_msi flag is changed | 227 | /* bad things may happen if the no_msi flag is changed |
228 | * while some drivers are loaded */ | 228 | * while some drivers are loaded */ |
229 | if (!capable(CAP_SYS_ADMIN)) | 229 | if (!capable(CAP_SYS_ADMIN)) |
230 | return -EPERM; | 230 | return -EPERM; |
231 | 231 | ||
232 | /* Maybe pci devices without subordinate busses shouldn't even have this | 232 | /* Maybe pci devices without subordinate busses shouldn't even have this |
233 | * attribute in the first place? */ | 233 | * attribute in the first place? */ |
234 | if (!pdev->subordinate) | 234 | if (!pdev->subordinate) |
235 | return count; | 235 | return count; |
236 | 236 | ||
237 | /* Is the flag going to change, or keep the value it already had? */ | 237 | /* Is the flag going to change, or keep the value it already had? */ |
238 | if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^ | 238 | if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^ |
239 | !!val) { | 239 | !!val) { |
240 | pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI; | 240 | pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI; |
241 | 241 | ||
242 | dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI," | 242 | dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI," |
243 | " bad things could happen\n", val ? "" : " not"); | 243 | " bad things could happen\n", val ? "" : " not"); |
244 | } | 244 | } |
245 | 245 | ||
246 | return count; | 246 | return count; |
247 | } | 247 | } |
248 | 248 | ||
249 | #ifdef CONFIG_HOTPLUG | 249 | #ifdef CONFIG_HOTPLUG |
250 | static DEFINE_MUTEX(pci_remove_rescan_mutex); | 250 | static DEFINE_MUTEX(pci_remove_rescan_mutex); |
251 | static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, | 251 | static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, |
252 | size_t count) | 252 | size_t count) |
253 | { | 253 | { |
254 | unsigned long val; | 254 | unsigned long val; |
255 | struct pci_bus *b = NULL; | 255 | struct pci_bus *b = NULL; |
256 | 256 | ||
257 | if (strict_strtoul(buf, 0, &val) < 0) | 257 | if (strict_strtoul(buf, 0, &val) < 0) |
258 | return -EINVAL; | 258 | return -EINVAL; |
259 | 259 | ||
260 | if (val) { | 260 | if (val) { |
261 | mutex_lock(&pci_remove_rescan_mutex); | 261 | mutex_lock(&pci_remove_rescan_mutex); |
262 | while ((b = pci_find_next_bus(b)) != NULL) | 262 | while ((b = pci_find_next_bus(b)) != NULL) |
263 | pci_rescan_bus(b); | 263 | pci_rescan_bus(b); |
264 | mutex_unlock(&pci_remove_rescan_mutex); | 264 | mutex_unlock(&pci_remove_rescan_mutex); |
265 | } | 265 | } |
266 | return count; | 266 | return count; |
267 | } | 267 | } |
268 | 268 | ||
269 | struct bus_attribute pci_bus_attrs[] = { | 269 | struct bus_attribute pci_bus_attrs[] = { |
270 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store), | 270 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store), |
271 | __ATTR_NULL | 271 | __ATTR_NULL |
272 | }; | 272 | }; |
273 | 273 | ||
274 | static ssize_t | 274 | static ssize_t |
275 | dev_rescan_store(struct device *dev, struct device_attribute *attr, | 275 | dev_rescan_store(struct device *dev, struct device_attribute *attr, |
276 | const char *buf, size_t count) | 276 | const char *buf, size_t count) |
277 | { | 277 | { |
278 | unsigned long val; | 278 | unsigned long val; |
279 | struct pci_dev *pdev = to_pci_dev(dev); | 279 | struct pci_dev *pdev = to_pci_dev(dev); |
280 | 280 | ||
281 | if (strict_strtoul(buf, 0, &val) < 0) | 281 | if (strict_strtoul(buf, 0, &val) < 0) |
282 | return -EINVAL; | 282 | return -EINVAL; |
283 | 283 | ||
284 | if (val) { | 284 | if (val) { |
285 | mutex_lock(&pci_remove_rescan_mutex); | 285 | mutex_lock(&pci_remove_rescan_mutex); |
286 | pci_rescan_bus(pdev->bus); | 286 | pci_rescan_bus(pdev->bus); |
287 | mutex_unlock(&pci_remove_rescan_mutex); | 287 | mutex_unlock(&pci_remove_rescan_mutex); |
288 | } | 288 | } |
289 | return count; | 289 | return count; |
290 | } | 290 | } |
291 | 291 | ||
292 | static void remove_callback(struct device *dev) | 292 | static void remove_callback(struct device *dev) |
293 | { | 293 | { |
294 | struct pci_dev *pdev = to_pci_dev(dev); | 294 | struct pci_dev *pdev = to_pci_dev(dev); |
295 | 295 | ||
296 | mutex_lock(&pci_remove_rescan_mutex); | 296 | mutex_lock(&pci_remove_rescan_mutex); |
297 | pci_remove_bus_device(pdev); | 297 | pci_remove_bus_device(pdev); |
298 | mutex_unlock(&pci_remove_rescan_mutex); | 298 | mutex_unlock(&pci_remove_rescan_mutex); |
299 | } | 299 | } |
300 | 300 | ||
301 | static ssize_t | 301 | static ssize_t |
302 | remove_store(struct device *dev, struct device_attribute *dummy, | 302 | remove_store(struct device *dev, struct device_attribute *dummy, |
303 | const char *buf, size_t count) | 303 | const char *buf, size_t count) |
304 | { | 304 | { |
305 | int ret = 0; | 305 | int ret = 0; |
306 | unsigned long val; | 306 | unsigned long val; |
307 | 307 | ||
308 | if (strict_strtoul(buf, 0, &val) < 0) | 308 | if (strict_strtoul(buf, 0, &val) < 0) |
309 | return -EINVAL; | 309 | return -EINVAL; |
310 | 310 | ||
311 | /* An attribute cannot be unregistered by one of its own methods, | 311 | /* An attribute cannot be unregistered by one of its own methods, |
312 | * so we have to use this roundabout approach. | 312 | * so we have to use this roundabout approach. |
313 | */ | 313 | */ |
314 | if (val) | 314 | if (val) |
315 | ret = device_schedule_callback(dev, remove_callback); | 315 | ret = device_schedule_callback(dev, remove_callback); |
316 | if (ret) | 316 | if (ret) |
317 | count = ret; | 317 | count = ret; |
318 | return count; | 318 | return count; |
319 | } | 319 | } |
320 | #endif | 320 | #endif |
321 | 321 | ||
322 | struct device_attribute pci_dev_attrs[] = { | 322 | struct device_attribute pci_dev_attrs[] = { |
323 | __ATTR_RO(resource), | 323 | __ATTR_RO(resource), |
324 | __ATTR_RO(vendor), | 324 | __ATTR_RO(vendor), |
325 | __ATTR_RO(device), | 325 | __ATTR_RO(device), |
326 | __ATTR_RO(subsystem_vendor), | 326 | __ATTR_RO(subsystem_vendor), |
327 | __ATTR_RO(subsystem_device), | 327 | __ATTR_RO(subsystem_device), |
328 | __ATTR_RO(class), | 328 | __ATTR_RO(class), |
329 | __ATTR_RO(irq), | 329 | __ATTR_RO(irq), |
330 | __ATTR_RO(local_cpus), | 330 | __ATTR_RO(local_cpus), |
331 | __ATTR_RO(local_cpulist), | 331 | __ATTR_RO(local_cpulist), |
332 | __ATTR_RO(modalias), | 332 | __ATTR_RO(modalias), |
333 | #ifdef CONFIG_NUMA | 333 | #ifdef CONFIG_NUMA |
334 | __ATTR_RO(numa_node), | 334 | __ATTR_RO(numa_node), |
335 | #endif | 335 | #endif |
336 | __ATTR_RO(dma_mask_bits), | 336 | __ATTR_RO(dma_mask_bits), |
337 | __ATTR_RO(consistent_dma_mask_bits), | 337 | __ATTR_RO(consistent_dma_mask_bits), |
338 | __ATTR(enable, 0600, is_enabled_show, is_enabled_store), | 338 | __ATTR(enable, 0600, is_enabled_show, is_enabled_store), |
339 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), | 339 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), |
340 | broken_parity_status_show,broken_parity_status_store), | 340 | broken_parity_status_show,broken_parity_status_store), |
341 | __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), | 341 | __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), |
342 | #ifdef CONFIG_HOTPLUG | 342 | #ifdef CONFIG_HOTPLUG |
343 | __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), | 343 | __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), |
344 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), | 344 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), |
345 | #endif | 345 | #endif |
346 | __ATTR_NULL, | 346 | __ATTR_NULL, |
347 | }; | 347 | }; |
348 | 348 | ||
349 | static ssize_t | 349 | static ssize_t |
350 | boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) | 350 | boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) |
351 | { | 351 | { |
352 | struct pci_dev *pdev = to_pci_dev(dev); | 352 | struct pci_dev *pdev = to_pci_dev(dev); |
353 | 353 | ||
354 | return sprintf(buf, "%u\n", | 354 | return sprintf(buf, "%u\n", |
355 | !!(pdev->resource[PCI_ROM_RESOURCE].flags & | 355 | !!(pdev->resource[PCI_ROM_RESOURCE].flags & |
356 | IORESOURCE_ROM_SHADOW)); | 356 | IORESOURCE_ROM_SHADOW)); |
357 | } | 357 | } |
358 | struct device_attribute vga_attr = __ATTR_RO(boot_vga); | 358 | struct device_attribute vga_attr = __ATTR_RO(boot_vga); |
359 | 359 | ||
360 | static ssize_t | 360 | static ssize_t |
361 | pci_read_config(struct file *filp, struct kobject *kobj, | 361 | pci_read_config(struct file *filp, struct kobject *kobj, |
362 | struct bin_attribute *bin_attr, | 362 | struct bin_attribute *bin_attr, |
363 | char *buf, loff_t off, size_t count) | 363 | char *buf, loff_t off, size_t count) |
364 | { | 364 | { |
365 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); | 365 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); |
366 | unsigned int size = 64; | 366 | unsigned int size = 64; |
367 | loff_t init_off = off; | 367 | loff_t init_off = off; |
368 | u8 *data = (u8*) buf; | 368 | u8 *data = (u8*) buf; |
369 | 369 | ||
370 | /* Several chips lock up trying to read undefined config space */ | 370 | /* Several chips lock up trying to read undefined config space */ |
371 | if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) { | 371 | if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) { |
372 | size = dev->cfg_size; | 372 | size = dev->cfg_size; |
373 | } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { | 373 | } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { |
374 | size = 128; | 374 | size = 128; |
375 | } | 375 | } |
376 | 376 | ||
377 | if (off > size) | 377 | if (off > size) |
378 | return 0; | 378 | return 0; |
379 | if (off + count > size) { | 379 | if (off + count > size) { |
380 | size -= off; | 380 | size -= off; |
381 | count = size; | 381 | count = size; |
382 | } else { | 382 | } else { |
383 | size = count; | 383 | size = count; |
384 | } | 384 | } |
385 | 385 | ||
386 | if ((off & 1) && size) { | 386 | if ((off & 1) && size) { |
387 | u8 val; | 387 | u8 val; |
388 | pci_user_read_config_byte(dev, off, &val); | 388 | pci_user_read_config_byte(dev, off, &val); |
389 | data[off - init_off] = val; | 389 | data[off - init_off] = val; |
390 | off++; | 390 | off++; |
391 | size--; | 391 | size--; |
392 | } | 392 | } |
393 | 393 | ||
394 | if ((off & 3) && size > 2) { | 394 | if ((off & 3) && size > 2) { |
395 | u16 val; | 395 | u16 val; |
396 | pci_user_read_config_word(dev, off, &val); | 396 | pci_user_read_config_word(dev, off, &val); |
397 | data[off - init_off] = val & 0xff; | 397 | data[off - init_off] = val & 0xff; |
398 | data[off - init_off + 1] = (val >> 8) & 0xff; | 398 | data[off - init_off + 1] = (val >> 8) & 0xff; |
399 | off += 2; | 399 | off += 2; |
400 | size -= 2; | 400 | size -= 2; |
401 | } | 401 | } |
402 | 402 | ||
403 | while (size > 3) { | 403 | while (size > 3) { |
404 | u32 val; | 404 | u32 val; |
405 | pci_user_read_config_dword(dev, off, &val); | 405 | pci_user_read_config_dword(dev, off, &val); |
406 | data[off - init_off] = val & 0xff; | 406 | data[off - init_off] = val & 0xff; |
407 | data[off - init_off + 1] = (val >> 8) & 0xff; | 407 | data[off - init_off + 1] = (val >> 8) & 0xff; |
408 | data[off - init_off + 2] = (val >> 16) & 0xff; | 408 | data[off - init_off + 2] = (val >> 16) & 0xff; |
409 | data[off - init_off + 3] = (val >> 24) & 0xff; | 409 | data[off - init_off + 3] = (val >> 24) & 0xff; |
410 | off += 4; | 410 | off += 4; |
411 | size -= 4; | 411 | size -= 4; |
412 | } | 412 | } |
413 | 413 | ||
414 | if (size >= 2) { | 414 | if (size >= 2) { |
415 | u16 val; | 415 | u16 val; |
416 | pci_user_read_config_word(dev, off, &val); | 416 | pci_user_read_config_word(dev, off, &val); |
417 | data[off - init_off] = val & 0xff; | 417 | data[off - init_off] = val & 0xff; |
418 | data[off - init_off + 1] = (val >> 8) & 0xff; | 418 | data[off - init_off + 1] = (val >> 8) & 0xff; |
419 | off += 2; | 419 | off += 2; |
420 | size -= 2; | 420 | size -= 2; |
421 | } | 421 | } |
422 | 422 | ||
423 | if (size > 0) { | 423 | if (size > 0) { |
424 | u8 val; | 424 | u8 val; |
425 | pci_user_read_config_byte(dev, off, &val); | 425 | pci_user_read_config_byte(dev, off, &val); |
426 | data[off - init_off] = val; | 426 | data[off - init_off] = val; |
427 | off++; | 427 | off++; |
428 | --size; | 428 | --size; |
429 | } | 429 | } |
430 | 430 | ||
431 | return count; | 431 | return count; |
432 | } | 432 | } |
433 | 433 | ||
434 | static ssize_t | 434 | static ssize_t |
435 | pci_write_config(struct file* filp, struct kobject *kobj, | 435 | pci_write_config(struct file* filp, struct kobject *kobj, |
436 | struct bin_attribute *bin_attr, | 436 | struct bin_attribute *bin_attr, |
437 | char *buf, loff_t off, size_t count) | 437 | char *buf, loff_t off, size_t count) |
438 | { | 438 | { |
439 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); | 439 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); |
440 | unsigned int size = count; | 440 | unsigned int size = count; |
441 | loff_t init_off = off; | 441 | loff_t init_off = off; |
442 | u8 *data = (u8*) buf; | 442 | u8 *data = (u8*) buf; |
443 | 443 | ||
444 | if (off > dev->cfg_size) | 444 | if (off > dev->cfg_size) |
445 | return 0; | 445 | return 0; |
446 | if (off + count > dev->cfg_size) { | 446 | if (off + count > dev->cfg_size) { |
447 | size = dev->cfg_size - off; | 447 | size = dev->cfg_size - off; |
448 | count = size; | 448 | count = size; |
449 | } | 449 | } |
450 | 450 | ||
451 | if ((off & 1) && size) { | 451 | if ((off & 1) && size) { |
452 | pci_user_write_config_byte(dev, off, data[off - init_off]); | 452 | pci_user_write_config_byte(dev, off, data[off - init_off]); |
453 | off++; | 453 | off++; |
454 | size--; | 454 | size--; |
455 | } | 455 | } |
456 | 456 | ||
457 | if ((off & 3) && size > 2) { | 457 | if ((off & 3) && size > 2) { |
458 | u16 val = data[off - init_off]; | 458 | u16 val = data[off - init_off]; |
459 | val |= (u16) data[off - init_off + 1] << 8; | 459 | val |= (u16) data[off - init_off + 1] << 8; |
460 | pci_user_write_config_word(dev, off, val); | 460 | pci_user_write_config_word(dev, off, val); |
461 | off += 2; | 461 | off += 2; |
462 | size -= 2; | 462 | size -= 2; |
463 | } | 463 | } |
464 | 464 | ||
465 | while (size > 3) { | 465 | while (size > 3) { |
466 | u32 val = data[off - init_off]; | 466 | u32 val = data[off - init_off]; |
467 | val |= (u32) data[off - init_off + 1] << 8; | 467 | val |= (u32) data[off - init_off + 1] << 8; |
468 | val |= (u32) data[off - init_off + 2] << 16; | 468 | val |= (u32) data[off - init_off + 2] << 16; |
469 | val |= (u32) data[off - init_off + 3] << 24; | 469 | val |= (u32) data[off - init_off + 3] << 24; |
470 | pci_user_write_config_dword(dev, off, val); | 470 | pci_user_write_config_dword(dev, off, val); |
471 | off += 4; | 471 | off += 4; |
472 | size -= 4; | 472 | size -= 4; |
473 | } | 473 | } |
474 | 474 | ||
475 | if (size >= 2) { | 475 | if (size >= 2) { |
476 | u16 val = data[off - init_off]; | 476 | u16 val = data[off - init_off]; |
477 | val |= (u16) data[off - init_off + 1] << 8; | 477 | val |= (u16) data[off - init_off + 1] << 8; |
478 | pci_user_write_config_word(dev, off, val); | 478 | pci_user_write_config_word(dev, off, val); |
479 | off += 2; | 479 | off += 2; |
480 | size -= 2; | 480 | size -= 2; |
481 | } | 481 | } |
482 | 482 | ||
483 | if (size) { | 483 | if (size) { |
484 | pci_user_write_config_byte(dev, off, data[off - init_off]); | 484 | pci_user_write_config_byte(dev, off, data[off - init_off]); |
485 | off++; | 485 | off++; |
486 | --size; | 486 | --size; |
487 | } | 487 | } |
488 | 488 | ||
489 | return count; | 489 | return count; |
490 | } | 490 | } |
491 | 491 | ||
492 | static ssize_t | 492 | static ssize_t |
493 | read_vpd_attr(struct file *filp, struct kobject *kobj, | 493 | read_vpd_attr(struct file *filp, struct kobject *kobj, |
494 | struct bin_attribute *bin_attr, | 494 | struct bin_attribute *bin_attr, |
495 | char *buf, loff_t off, size_t count) | 495 | char *buf, loff_t off, size_t count) |
496 | { | 496 | { |
497 | struct pci_dev *dev = | 497 | struct pci_dev *dev = |
498 | to_pci_dev(container_of(kobj, struct device, kobj)); | 498 | to_pci_dev(container_of(kobj, struct device, kobj)); |
499 | 499 | ||
500 | if (off > bin_attr->size) | 500 | if (off > bin_attr->size) |
501 | count = 0; | 501 | count = 0; |
502 | else if (count > bin_attr->size - off) | 502 | else if (count > bin_attr->size - off) |
503 | count = bin_attr->size - off; | 503 | count = bin_attr->size - off; |
504 | 504 | ||
505 | return pci_read_vpd(dev, off, count, buf); | 505 | return pci_read_vpd(dev, off, count, buf); |
506 | } | 506 | } |
507 | 507 | ||
508 | static ssize_t | 508 | static ssize_t |
509 | write_vpd_attr(struct file *filp, struct kobject *kobj, | 509 | write_vpd_attr(struct file *filp, struct kobject *kobj, |
510 | struct bin_attribute *bin_attr, | 510 | struct bin_attribute *bin_attr, |
511 | char *buf, loff_t off, size_t count) | 511 | char *buf, loff_t off, size_t count) |
512 | { | 512 | { |
513 | struct pci_dev *dev = | 513 | struct pci_dev *dev = |
514 | to_pci_dev(container_of(kobj, struct device, kobj)); | 514 | to_pci_dev(container_of(kobj, struct device, kobj)); |
515 | 515 | ||
516 | if (off > bin_attr->size) | 516 | if (off > bin_attr->size) |
517 | count = 0; | 517 | count = 0; |
518 | else if (count > bin_attr->size - off) | 518 | else if (count > bin_attr->size - off) |
519 | count = bin_attr->size - off; | 519 | count = bin_attr->size - off; |
520 | 520 | ||
521 | return pci_write_vpd(dev, off, count, buf); | 521 | return pci_write_vpd(dev, off, count, buf); |
522 | } | 522 | } |
523 | 523 | ||
524 | #ifdef HAVE_PCI_LEGACY | 524 | #ifdef HAVE_PCI_LEGACY |
525 | /** | 525 | /** |
526 | * pci_read_legacy_io - read byte(s) from legacy I/O port space | 526 | * pci_read_legacy_io - read byte(s) from legacy I/O port space |
527 | * @filp: open sysfs file | 527 | * @filp: open sysfs file |
528 | * @kobj: kobject corresponding to file to read from | 528 | * @kobj: kobject corresponding to file to read from |
529 | * @bin_attr: struct bin_attribute for this file | 529 | * @bin_attr: struct bin_attribute for this file |
530 | * @buf: buffer to store results | 530 | * @buf: buffer to store results |
531 | * @off: offset into legacy I/O port space | 531 | * @off: offset into legacy I/O port space |
532 | * @count: number of bytes to read | 532 | * @count: number of bytes to read |
533 | * | 533 | * |
534 | * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific | 534 | * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific |
535 | * callback routine (pci_legacy_read). | 535 | * callback routine (pci_legacy_read). |
536 | */ | 536 | */ |
537 | static ssize_t | 537 | static ssize_t |
538 | pci_read_legacy_io(struct file *filp, struct kobject *kobj, | 538 | pci_read_legacy_io(struct file *filp, struct kobject *kobj, |
539 | struct bin_attribute *bin_attr, | 539 | struct bin_attribute *bin_attr, |
540 | char *buf, loff_t off, size_t count) | 540 | char *buf, loff_t off, size_t count) |
541 | { | 541 | { |
542 | struct pci_bus *bus = to_pci_bus(container_of(kobj, | 542 | struct pci_bus *bus = to_pci_bus(container_of(kobj, |
543 | struct device, | 543 | struct device, |
544 | kobj)); | 544 | kobj)); |
545 | 545 | ||
546 | /* Only support 1, 2 or 4 byte accesses */ | 546 | /* Only support 1, 2 or 4 byte accesses */ |
547 | if (count != 1 && count != 2 && count != 4) | 547 | if (count != 1 && count != 2 && count != 4) |
548 | return -EINVAL; | 548 | return -EINVAL; |
549 | 549 | ||
550 | return pci_legacy_read(bus, off, (u32 *)buf, count); | 550 | return pci_legacy_read(bus, off, (u32 *)buf, count); |
551 | } | 551 | } |
552 | 552 | ||
553 | /** | 553 | /** |
554 | * pci_write_legacy_io - write byte(s) to legacy I/O port space | 554 | * pci_write_legacy_io - write byte(s) to legacy I/O port space |
555 | * @filp: open sysfs file | 555 | * @filp: open sysfs file |
556 | * @kobj: kobject corresponding to file to read from | 556 | * @kobj: kobject corresponding to file to read from |
557 | * @bin_attr: struct bin_attribute for this file | 557 | * @bin_attr: struct bin_attribute for this file |
558 | * @buf: buffer containing value to be written | 558 | * @buf: buffer containing value to be written |
559 | * @off: offset into legacy I/O port space | 559 | * @off: offset into legacy I/O port space |
560 | * @count: number of bytes to write | 560 | * @count: number of bytes to write |
561 | * | 561 | * |
562 | * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific | 562 | * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific |
563 | * callback routine (pci_legacy_write). | 563 | * callback routine (pci_legacy_write). |
564 | */ | 564 | */ |
565 | static ssize_t | 565 | static ssize_t |
566 | pci_write_legacy_io(struct file *filp, struct kobject *kobj, | 566 | pci_write_legacy_io(struct file *filp, struct kobject *kobj, |
567 | struct bin_attribute *bin_attr, | 567 | struct bin_attribute *bin_attr, |
568 | char *buf, loff_t off, size_t count) | 568 | char *buf, loff_t off, size_t count) |
569 | { | 569 | { |
570 | struct pci_bus *bus = to_pci_bus(container_of(kobj, | 570 | struct pci_bus *bus = to_pci_bus(container_of(kobj, |
571 | struct device, | 571 | struct device, |
572 | kobj)); | 572 | kobj)); |
573 | /* Only support 1, 2 or 4 byte accesses */ | 573 | /* Only support 1, 2 or 4 byte accesses */ |
574 | if (count != 1 && count != 2 && count != 4) | 574 | if (count != 1 && count != 2 && count != 4) |
575 | return -EINVAL; | 575 | return -EINVAL; |
576 | 576 | ||
577 | return pci_legacy_write(bus, off, *(u32 *)buf, count); | 577 | return pci_legacy_write(bus, off, *(u32 *)buf, count); |
578 | } | 578 | } |
579 | 579 | ||
580 | /** | 580 | /** |
581 | * pci_mmap_legacy_mem - map legacy PCI memory into user memory space | 581 | * pci_mmap_legacy_mem - map legacy PCI memory into user memory space |
582 | * @filp: open sysfs file | 582 | * @filp: open sysfs file |
583 | * @kobj: kobject corresponding to device to be mapped | 583 | * @kobj: kobject corresponding to device to be mapped |
584 | * @attr: struct bin_attribute for this file | 584 | * @attr: struct bin_attribute for this file |
585 | * @vma: struct vm_area_struct passed to mmap | 585 | * @vma: struct vm_area_struct passed to mmap |
586 | * | 586 | * |
587 | * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap | 587 | * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap |
588 | * legacy memory space (first meg of bus space) into application virtual | 588 | * legacy memory space (first meg of bus space) into application virtual |
589 | * memory space. | 589 | * memory space. |
590 | */ | 590 | */ |
591 | static int | 591 | static int |
592 | pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, | 592 | pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, |
593 | struct bin_attribute *attr, | 593 | struct bin_attribute *attr, |
594 | struct vm_area_struct *vma) | 594 | struct vm_area_struct *vma) |
595 | { | 595 | { |
596 | struct pci_bus *bus = to_pci_bus(container_of(kobj, | 596 | struct pci_bus *bus = to_pci_bus(container_of(kobj, |
597 | struct device, | 597 | struct device, |
598 | kobj)); | 598 | kobj)); |
599 | 599 | ||
600 | return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem); | 600 | return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem); |
601 | } | 601 | } |
602 | 602 | ||
603 | /** | 603 | /** |
604 | * pci_mmap_legacy_io - map legacy PCI IO into user memory space | 604 | * pci_mmap_legacy_io - map legacy PCI IO into user memory space |
605 | * @filp: open sysfs file | 605 | * @filp: open sysfs file |
606 | * @kobj: kobject corresponding to device to be mapped | 606 | * @kobj: kobject corresponding to device to be mapped |
607 | * @attr: struct bin_attribute for this file | 607 | * @attr: struct bin_attribute for this file |
608 | * @vma: struct vm_area_struct passed to mmap | 608 | * @vma: struct vm_area_struct passed to mmap |
609 | * | 609 | * |
610 | * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap | 610 | * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap |
611 | * legacy IO space (first meg of bus space) into application virtual | 611 | * legacy IO space (first meg of bus space) into application virtual |
612 | * memory space. Returns -ENOSYS if the operation isn't supported | 612 | * memory space. Returns -ENOSYS if the operation isn't supported |
613 | */ | 613 | */ |
614 | static int | 614 | static int |
615 | pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, | 615 | pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, |
616 | struct bin_attribute *attr, | 616 | struct bin_attribute *attr, |
617 | struct vm_area_struct *vma) | 617 | struct vm_area_struct *vma) |
618 | { | 618 | { |
619 | struct pci_bus *bus = to_pci_bus(container_of(kobj, | 619 | struct pci_bus *bus = to_pci_bus(container_of(kobj, |
620 | struct device, | 620 | struct device, |
621 | kobj)); | 621 | kobj)); |
622 | 622 | ||
623 | return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io); | 623 | return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io); |
624 | } | 624 | } |
625 | 625 | ||
626 | /** | 626 | /** |
627 | * pci_adjust_legacy_attr - adjustment of legacy file attributes | 627 | * pci_adjust_legacy_attr - adjustment of legacy file attributes |
628 | * @b: bus to create files under | 628 | * @b: bus to create files under |
629 | * @mmap_type: I/O port or memory | 629 | * @mmap_type: I/O port or memory |
630 | * | 630 | * |
631 | * Stub implementation. Can be overridden by arch if necessary. | 631 | * Stub implementation. Can be overridden by arch if necessary. |
632 | */ | 632 | */ |
633 | void __weak | 633 | void __weak |
634 | pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) | 634 | pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) |
635 | { | 635 | { |
636 | return; | 636 | return; |
637 | } | 637 | } |
638 | 638 | ||
639 | /** | 639 | /** |
640 | * pci_create_legacy_files - create legacy I/O port and memory files | 640 | * pci_create_legacy_files - create legacy I/O port and memory files |
641 | * @b: bus to create files under | 641 | * @b: bus to create files under |
642 | * | 642 | * |
643 | * Some platforms allow access to legacy I/O port and ISA memory space on | 643 | * Some platforms allow access to legacy I/O port and ISA memory space on |
644 | * a per-bus basis. This routine creates the files and ties them into | 644 | * a per-bus basis. This routine creates the files and ties them into |
645 | * their associated read, write and mmap files from pci-sysfs.c | 645 | * their associated read, write and mmap files from pci-sysfs.c |
646 | * | 646 | * |
647 | * On error unwind, but don't propogate the error to the caller | 647 | * On error unwind, but don't propogate the error to the caller |
648 | * as it is ok to set up the PCI bus without these files. | 648 | * as it is ok to set up the PCI bus without these files. |
649 | */ | 649 | */ |
650 | void pci_create_legacy_files(struct pci_bus *b) | 650 | void pci_create_legacy_files(struct pci_bus *b) |
651 | { | 651 | { |
652 | int error; | 652 | int error; |
653 | 653 | ||
654 | b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2, | 654 | b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2, |
655 | GFP_ATOMIC); | 655 | GFP_ATOMIC); |
656 | if (!b->legacy_io) | 656 | if (!b->legacy_io) |
657 | goto kzalloc_err; | 657 | goto kzalloc_err; |
658 | 658 | ||
659 | sysfs_bin_attr_init(b->legacy_io); | 659 | sysfs_bin_attr_init(b->legacy_io); |
660 | b->legacy_io->attr.name = "legacy_io"; | 660 | b->legacy_io->attr.name = "legacy_io"; |
661 | b->legacy_io->size = 0xffff; | 661 | b->legacy_io->size = 0xffff; |
662 | b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; | 662 | b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; |
663 | b->legacy_io->read = pci_read_legacy_io; | 663 | b->legacy_io->read = pci_read_legacy_io; |
664 | b->legacy_io->write = pci_write_legacy_io; | 664 | b->legacy_io->write = pci_write_legacy_io; |
665 | b->legacy_io->mmap = pci_mmap_legacy_io; | 665 | b->legacy_io->mmap = pci_mmap_legacy_io; |
666 | pci_adjust_legacy_attr(b, pci_mmap_io); | 666 | pci_adjust_legacy_attr(b, pci_mmap_io); |
667 | error = device_create_bin_file(&b->dev, b->legacy_io); | 667 | error = device_create_bin_file(&b->dev, b->legacy_io); |
668 | if (error) | 668 | if (error) |
669 | goto legacy_io_err; | 669 | goto legacy_io_err; |
670 | 670 | ||
671 | /* Allocated above after the legacy_io struct */ | 671 | /* Allocated above after the legacy_io struct */ |
672 | b->legacy_mem = b->legacy_io + 1; | 672 | b->legacy_mem = b->legacy_io + 1; |
673 | sysfs_bin_attr_init(b->legacy_mem); | 673 | sysfs_bin_attr_init(b->legacy_mem); |
674 | b->legacy_mem->attr.name = "legacy_mem"; | 674 | b->legacy_mem->attr.name = "legacy_mem"; |
675 | b->legacy_mem->size = 1024*1024; | 675 | b->legacy_mem->size = 1024*1024; |
676 | b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; | 676 | b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; |
677 | b->legacy_mem->mmap = pci_mmap_legacy_mem; | 677 | b->legacy_mem->mmap = pci_mmap_legacy_mem; |
678 | pci_adjust_legacy_attr(b, pci_mmap_mem); | 678 | pci_adjust_legacy_attr(b, pci_mmap_mem); |
679 | error = device_create_bin_file(&b->dev, b->legacy_mem); | 679 | error = device_create_bin_file(&b->dev, b->legacy_mem); |
680 | if (error) | 680 | if (error) |
681 | goto legacy_mem_err; | 681 | goto legacy_mem_err; |
682 | 682 | ||
683 | return; | 683 | return; |
684 | 684 | ||
685 | legacy_mem_err: | 685 | legacy_mem_err: |
686 | device_remove_bin_file(&b->dev, b->legacy_io); | 686 | device_remove_bin_file(&b->dev, b->legacy_io); |
687 | legacy_io_err: | 687 | legacy_io_err: |
688 | kfree(b->legacy_io); | 688 | kfree(b->legacy_io); |
689 | b->legacy_io = NULL; | 689 | b->legacy_io = NULL; |
690 | kzalloc_err: | 690 | kzalloc_err: |
691 | printk(KERN_WARNING "pci: warning: could not create legacy I/O port " | 691 | printk(KERN_WARNING "pci: warning: could not create legacy I/O port " |
692 | "and ISA memory resources to sysfs\n"); | 692 | "and ISA memory resources to sysfs\n"); |
693 | return; | 693 | return; |
694 | } | 694 | } |
695 | 695 | ||
696 | void pci_remove_legacy_files(struct pci_bus *b) | 696 | void pci_remove_legacy_files(struct pci_bus *b) |
697 | { | 697 | { |
698 | if (b->legacy_io) { | 698 | if (b->legacy_io) { |
699 | device_remove_bin_file(&b->dev, b->legacy_io); | 699 | device_remove_bin_file(&b->dev, b->legacy_io); |
700 | device_remove_bin_file(&b->dev, b->legacy_mem); | 700 | device_remove_bin_file(&b->dev, b->legacy_mem); |
701 | kfree(b->legacy_io); /* both are allocated here */ | 701 | kfree(b->legacy_io); /* both are allocated here */ |
702 | } | 702 | } |
703 | } | 703 | } |
704 | #endif /* HAVE_PCI_LEGACY */ | 704 | #endif /* HAVE_PCI_LEGACY */ |
705 | 705 | ||
706 | #ifdef HAVE_PCI_MMAP | 706 | #ifdef HAVE_PCI_MMAP |
707 | 707 | ||
708 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) | 708 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) |
709 | { | 709 | { |
710 | unsigned long nr, start, size; | 710 | unsigned long nr, start, size; |
711 | 711 | ||
712 | nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | 712 | nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; |
713 | start = vma->vm_pgoff; | 713 | start = vma->vm_pgoff; |
714 | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; | 714 | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; |
715 | if (start < size && size - start >= nr) | 715 | if (start < size && size - start >= nr) |
716 | return 1; | 716 | return 1; |
717 | WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n", | 717 | WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n", |
718 | current->comm, start, start+nr, pci_name(pdev), resno, size); | 718 | current->comm, start, start+nr, pci_name(pdev), resno, size); |
719 | return 0; | 719 | return 0; |
720 | } | 720 | } |
721 | 721 | ||
722 | /** | 722 | /** |
723 | * pci_mmap_resource - map a PCI resource into user memory space | 723 | * pci_mmap_resource - map a PCI resource into user memory space |
724 | * @kobj: kobject for mapping | 724 | * @kobj: kobject for mapping |
725 | * @attr: struct bin_attribute for the file being mapped | 725 | * @attr: struct bin_attribute for the file being mapped |
726 | * @vma: struct vm_area_struct passed into the mmap | 726 | * @vma: struct vm_area_struct passed into the mmap |
727 | * @write_combine: 1 for write_combine mapping | 727 | * @write_combine: 1 for write_combine mapping |
728 | * | 728 | * |
729 | * Use the regular PCI mapping routines to map a PCI resource into userspace. | 729 | * Use the regular PCI mapping routines to map a PCI resource into userspace. |
730 | */ | 730 | */ |
731 | static int | 731 | static int |
732 | pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | 732 | pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, |
733 | struct vm_area_struct *vma, int write_combine) | 733 | struct vm_area_struct *vma, int write_combine) |
734 | { | 734 | { |
735 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, | 735 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, |
736 | struct device, kobj)); | 736 | struct device, kobj)); |
737 | struct resource *res = attr->private; | 737 | struct resource *res = attr->private; |
738 | enum pci_mmap_state mmap_type; | 738 | enum pci_mmap_state mmap_type; |
739 | resource_size_t start, end; | 739 | resource_size_t start, end; |
740 | int i; | 740 | int i; |
741 | 741 | ||
742 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | 742 | for (i = 0; i < PCI_ROM_RESOURCE; i++) |
743 | if (res == &pdev->resource[i]) | 743 | if (res == &pdev->resource[i]) |
744 | break; | 744 | break; |
745 | if (i >= PCI_ROM_RESOURCE) | 745 | if (i >= PCI_ROM_RESOURCE) |
746 | return -ENODEV; | 746 | return -ENODEV; |
747 | 747 | ||
748 | if (!pci_mmap_fits(pdev, i, vma)) | 748 | if (!pci_mmap_fits(pdev, i, vma)) |
749 | return -EINVAL; | 749 | return -EINVAL; |
750 | 750 | ||
751 | /* pci_mmap_page_range() expects the same kind of entry as coming | 751 | /* pci_mmap_page_range() expects the same kind of entry as coming |
752 | * from /proc/bus/pci/ which is a "user visible" value. If this is | 752 | * from /proc/bus/pci/ which is a "user visible" value. If this is |
753 | * different from the resource itself, arch will do necessary fixup. | 753 | * different from the resource itself, arch will do necessary fixup. |
754 | */ | 754 | */ |
755 | pci_resource_to_user(pdev, i, res, &start, &end); | 755 | pci_resource_to_user(pdev, i, res, &start, &end); |
756 | vma->vm_pgoff += start >> PAGE_SHIFT; | 756 | vma->vm_pgoff += start >> PAGE_SHIFT; |
757 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; | 757 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; |
758 | 758 | ||
759 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start)) | 759 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start)) |
760 | return -EINVAL; | 760 | return -EINVAL; |
761 | 761 | ||
762 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); | 762 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); |
763 | } | 763 | } |
764 | 764 | ||
765 | static int | 765 | static int |
766 | pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, | 766 | pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, |
767 | struct bin_attribute *attr, | 767 | struct bin_attribute *attr, |
768 | struct vm_area_struct *vma) | 768 | struct vm_area_struct *vma) |
769 | { | 769 | { |
770 | return pci_mmap_resource(kobj, attr, vma, 0); | 770 | return pci_mmap_resource(kobj, attr, vma, 0); |
771 | } | 771 | } |
772 | 772 | ||
773 | static int | 773 | static int |
774 | pci_mmap_resource_wc(struct file *filp, struct kobject *kobj, | 774 | pci_mmap_resource_wc(struct file *filp, struct kobject *kobj, |
775 | struct bin_attribute *attr, | 775 | struct bin_attribute *attr, |
776 | struct vm_area_struct *vma) | 776 | struct vm_area_struct *vma) |
777 | { | 777 | { |
778 | return pci_mmap_resource(kobj, attr, vma, 1); | 778 | return pci_mmap_resource(kobj, attr, vma, 1); |
779 | } | 779 | } |
780 | 780 | ||
781 | static ssize_t | 781 | static ssize_t |
782 | pci_resource_io(struct file *filp, struct kobject *kobj, | 782 | pci_resource_io(struct file *filp, struct kobject *kobj, |
783 | struct bin_attribute *attr, char *buf, | 783 | struct bin_attribute *attr, char *buf, |
784 | loff_t off, size_t count, bool write) | 784 | loff_t off, size_t count, bool write) |
785 | { | 785 | { |
786 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, | 786 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, |
787 | struct device, kobj)); | 787 | struct device, kobj)); |
788 | struct resource *res = attr->private; | 788 | struct resource *res = attr->private; |
789 | unsigned long port = off; | 789 | unsigned long port = off; |
790 | int i; | 790 | int i; |
791 | 791 | ||
792 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | 792 | for (i = 0; i < PCI_ROM_RESOURCE; i++) |
793 | if (res == &pdev->resource[i]) | 793 | if (res == &pdev->resource[i]) |
794 | break; | 794 | break; |
795 | if (i >= PCI_ROM_RESOURCE) | 795 | if (i >= PCI_ROM_RESOURCE) |
796 | return -ENODEV; | 796 | return -ENODEV; |
797 | 797 | ||
798 | port += pci_resource_start(pdev, i); | 798 | port += pci_resource_start(pdev, i); |
799 | 799 | ||
800 | if (port > pci_resource_end(pdev, i)) | 800 | if (port > pci_resource_end(pdev, i)) |
801 | return 0; | 801 | return 0; |
802 | 802 | ||
803 | if (port + count - 1 > pci_resource_end(pdev, i)) | 803 | if (port + count - 1 > pci_resource_end(pdev, i)) |
804 | return -EINVAL; | 804 | return -EINVAL; |
805 | 805 | ||
806 | switch (count) { | 806 | switch (count) { |
807 | case 1: | 807 | case 1: |
808 | if (write) | 808 | if (write) |
809 | outb(*(u8 *)buf, port); | 809 | outb(*(u8 *)buf, port); |
810 | else | 810 | else |
811 | *(u8 *)buf = inb(port); | 811 | *(u8 *)buf = inb(port); |
812 | return 1; | 812 | return 1; |
813 | case 2: | 813 | case 2: |
814 | if (write) | 814 | if (write) |
815 | outw(*(u16 *)buf, port); | 815 | outw(*(u16 *)buf, port); |
816 | else | 816 | else |
817 | *(u16 *)buf = inw(port); | 817 | *(u16 *)buf = inw(port); |
818 | return 2; | 818 | return 2; |
819 | case 4: | 819 | case 4: |
820 | if (write) | 820 | if (write) |
821 | outl(*(u32 *)buf, port); | 821 | outl(*(u32 *)buf, port); |
822 | else | 822 | else |
823 | *(u32 *)buf = inl(port); | 823 | *(u32 *)buf = inl(port); |
824 | return 4; | 824 | return 4; |
825 | } | 825 | } |
826 | return -EINVAL; | 826 | return -EINVAL; |
827 | } | 827 | } |
828 | 828 | ||
829 | static ssize_t | 829 | static ssize_t |
830 | pci_read_resource_io(struct file *filp, struct kobject *kobj, | 830 | pci_read_resource_io(struct file *filp, struct kobject *kobj, |
831 | struct bin_attribute *attr, char *buf, | 831 | struct bin_attribute *attr, char *buf, |
832 | loff_t off, size_t count) | 832 | loff_t off, size_t count) |
833 | { | 833 | { |
834 | return pci_resource_io(filp, kobj, attr, buf, off, count, false); | 834 | return pci_resource_io(filp, kobj, attr, buf, off, count, false); |
835 | } | 835 | } |
836 | 836 | ||
837 | static ssize_t | 837 | static ssize_t |
838 | pci_write_resource_io(struct file *filp, struct kobject *kobj, | 838 | pci_write_resource_io(struct file *filp, struct kobject *kobj, |
839 | struct bin_attribute *attr, char *buf, | 839 | struct bin_attribute *attr, char *buf, |
840 | loff_t off, size_t count) | 840 | loff_t off, size_t count) |
841 | { | 841 | { |
842 | return pci_resource_io(filp, kobj, attr, buf, off, count, true); | 842 | return pci_resource_io(filp, kobj, attr, buf, off, count, true); |
843 | } | 843 | } |
844 | 844 | ||
845 | /** | 845 | /** |
846 | * pci_remove_resource_files - cleanup resource files | 846 | * pci_remove_resource_files - cleanup resource files |
847 | * @pdev: dev to cleanup | 847 | * @pdev: dev to cleanup |
848 | * | 848 | * |
849 | * If we created resource files for @pdev, remove them from sysfs and | 849 | * If we created resource files for @pdev, remove them from sysfs and |
850 | * free their resources. | 850 | * free their resources. |
851 | */ | 851 | */ |
852 | static void | 852 | static void |
853 | pci_remove_resource_files(struct pci_dev *pdev) | 853 | pci_remove_resource_files(struct pci_dev *pdev) |
854 | { | 854 | { |
855 | int i; | 855 | int i; |
856 | 856 | ||
857 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | 857 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { |
858 | struct bin_attribute *res_attr; | 858 | struct bin_attribute *res_attr; |
859 | 859 | ||
860 | res_attr = pdev->res_attr[i]; | 860 | res_attr = pdev->res_attr[i]; |
861 | if (res_attr) { | 861 | if (res_attr) { |
862 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | 862 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); |
863 | kfree(res_attr); | 863 | kfree(res_attr); |
864 | } | 864 | } |
865 | 865 | ||
866 | res_attr = pdev->res_attr_wc[i]; | 866 | res_attr = pdev->res_attr_wc[i]; |
867 | if (res_attr) { | 867 | if (res_attr) { |
868 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | 868 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); |
869 | kfree(res_attr); | 869 | kfree(res_attr); |
870 | } | 870 | } |
871 | } | 871 | } |
872 | } | 872 | } |
873 | 873 | ||
874 | static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) | 874 | static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) |
875 | { | 875 | { |
876 | /* allocate attribute structure, piggyback attribute name */ | 876 | /* allocate attribute structure, piggyback attribute name */ |
877 | int name_len = write_combine ? 13 : 10; | 877 | int name_len = write_combine ? 13 : 10; |
878 | struct bin_attribute *res_attr; | 878 | struct bin_attribute *res_attr; |
879 | int retval; | 879 | int retval; |
880 | 880 | ||
881 | res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); | 881 | res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); |
882 | if (res_attr) { | 882 | if (res_attr) { |
883 | char *res_attr_name = (char *)(res_attr + 1); | 883 | char *res_attr_name = (char *)(res_attr + 1); |
884 | 884 | ||
885 | sysfs_bin_attr_init(res_attr); | 885 | sysfs_bin_attr_init(res_attr); |
886 | if (write_combine) { | 886 | if (write_combine) { |
887 | pdev->res_attr_wc[num] = res_attr; | 887 | pdev->res_attr_wc[num] = res_attr; |
888 | sprintf(res_attr_name, "resource%d_wc", num); | 888 | sprintf(res_attr_name, "resource%d_wc", num); |
889 | res_attr->mmap = pci_mmap_resource_wc; | 889 | res_attr->mmap = pci_mmap_resource_wc; |
890 | } else { | 890 | } else { |
891 | pdev->res_attr[num] = res_attr; | 891 | pdev->res_attr[num] = res_attr; |
892 | sprintf(res_attr_name, "resource%d", num); | 892 | sprintf(res_attr_name, "resource%d", num); |
893 | res_attr->mmap = pci_mmap_resource_uc; | 893 | res_attr->mmap = pci_mmap_resource_uc; |
894 | } | 894 | } |
895 | if (pci_resource_flags(pdev, num) & IORESOURCE_IO) { | 895 | if (pci_resource_flags(pdev, num) & IORESOURCE_IO) { |
896 | res_attr->read = pci_read_resource_io; | 896 | res_attr->read = pci_read_resource_io; |
897 | res_attr->write = pci_write_resource_io; | 897 | res_attr->write = pci_write_resource_io; |
898 | } | 898 | } |
899 | res_attr->attr.name = res_attr_name; | 899 | res_attr->attr.name = res_attr_name; |
900 | res_attr->attr.mode = S_IRUSR | S_IWUSR; | 900 | res_attr->attr.mode = S_IRUSR | S_IWUSR; |
901 | res_attr->size = pci_resource_len(pdev, num); | 901 | res_attr->size = pci_resource_len(pdev, num); |
902 | res_attr->private = &pdev->resource[num]; | 902 | res_attr->private = &pdev->resource[num]; |
903 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); | 903 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); |
904 | } else | 904 | } else |
905 | retval = -ENOMEM; | 905 | retval = -ENOMEM; |
906 | 906 | ||
907 | return retval; | 907 | return retval; |
908 | } | 908 | } |
909 | 909 | ||
910 | /** | 910 | /** |
911 | * pci_create_resource_files - create resource files in sysfs for @dev | 911 | * pci_create_resource_files - create resource files in sysfs for @dev |
912 | * @pdev: dev in question | 912 | * @pdev: dev in question |
913 | * | 913 | * |
914 | * Walk the resources in @pdev creating files for each resource available. | 914 | * Walk the resources in @pdev creating files for each resource available. |
915 | */ | 915 | */ |
916 | static int pci_create_resource_files(struct pci_dev *pdev) | 916 | static int pci_create_resource_files(struct pci_dev *pdev) |
917 | { | 917 | { |
918 | int i; | 918 | int i; |
919 | int retval; | 919 | int retval; |
920 | 920 | ||
921 | /* Expose the PCI resources from this device as files */ | 921 | /* Expose the PCI resources from this device as files */ |
922 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | 922 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { |
923 | 923 | ||
924 | /* skip empty resources */ | 924 | /* skip empty resources */ |
925 | if (!pci_resource_len(pdev, i)) | 925 | if (!pci_resource_len(pdev, i)) |
926 | continue; | 926 | continue; |
927 | 927 | ||
928 | retval = pci_create_attr(pdev, i, 0); | 928 | retval = pci_create_attr(pdev, i, 0); |
929 | /* for prefetchable resources, create a WC mappable file */ | 929 | /* for prefetchable resources, create a WC mappable file */ |
930 | if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) | 930 | if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) |
931 | retval = pci_create_attr(pdev, i, 1); | 931 | retval = pci_create_attr(pdev, i, 1); |
932 | 932 | ||
933 | if (retval) { | 933 | if (retval) { |
934 | pci_remove_resource_files(pdev); | 934 | pci_remove_resource_files(pdev); |
935 | return retval; | 935 | return retval; |
936 | } | 936 | } |
937 | } | 937 | } |
938 | return 0; | 938 | return 0; |
939 | } | 939 | } |
940 | #else /* !HAVE_PCI_MMAP */ | 940 | #else /* !HAVE_PCI_MMAP */ |
941 | int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; } | 941 | int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; } |
942 | void __weak pci_remove_resource_files(struct pci_dev *dev) { return; } | 942 | void __weak pci_remove_resource_files(struct pci_dev *dev) { return; } |
943 | #endif /* HAVE_PCI_MMAP */ | 943 | #endif /* HAVE_PCI_MMAP */ |
944 | 944 | ||
945 | /** | 945 | /** |
946 | * pci_write_rom - used to enable access to the PCI ROM display | 946 | * pci_write_rom - used to enable access to the PCI ROM display |
947 | * @filp: sysfs file | 947 | * @filp: sysfs file |
948 | * @kobj: kernel object handle | 948 | * @kobj: kernel object handle |
949 | * @bin_attr: struct bin_attribute for this file | 949 | * @bin_attr: struct bin_attribute for this file |
950 | * @buf: user input | 950 | * @buf: user input |
951 | * @off: file offset | 951 | * @off: file offset |
952 | * @count: number of byte in input | 952 | * @count: number of byte in input |
953 | * | 953 | * |
954 | * writing anything except 0 enables it | 954 | * writing anything except 0 enables it |
955 | */ | 955 | */ |
956 | static ssize_t | 956 | static ssize_t |
957 | pci_write_rom(struct file *filp, struct kobject *kobj, | 957 | pci_write_rom(struct file *filp, struct kobject *kobj, |
958 | struct bin_attribute *bin_attr, | 958 | struct bin_attribute *bin_attr, |
959 | char *buf, loff_t off, size_t count) | 959 | char *buf, loff_t off, size_t count) |
960 | { | 960 | { |
961 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); | 961 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); |
962 | 962 | ||
963 | if ((off == 0) && (*buf == '0') && (count == 2)) | 963 | if ((off == 0) && (*buf == '0') && (count == 2)) |
964 | pdev->rom_attr_enabled = 0; | 964 | pdev->rom_attr_enabled = 0; |
965 | else | 965 | else |
966 | pdev->rom_attr_enabled = 1; | 966 | pdev->rom_attr_enabled = 1; |
967 | 967 | ||
968 | return count; | 968 | return count; |
969 | } | 969 | } |
970 | 970 | ||
971 | /** | 971 | /** |
972 | * pci_read_rom - read a PCI ROM | 972 | * pci_read_rom - read a PCI ROM |
973 | * @filp: sysfs file | 973 | * @filp: sysfs file |
974 | * @kobj: kernel object handle | 974 | * @kobj: kernel object handle |
975 | * @bin_attr: struct bin_attribute for this file | 975 | * @bin_attr: struct bin_attribute for this file |
976 | * @buf: where to put the data we read from the ROM | 976 | * @buf: where to put the data we read from the ROM |
977 | * @off: file offset | 977 | * @off: file offset |
978 | * @count: number of bytes to read | 978 | * @count: number of bytes to read |
979 | * | 979 | * |
980 | * Put @count bytes starting at @off into @buf from the ROM in the PCI | 980 | * Put @count bytes starting at @off into @buf from the ROM in the PCI |
981 | * device corresponding to @kobj. | 981 | * device corresponding to @kobj. |
982 | */ | 982 | */ |
983 | static ssize_t | 983 | static ssize_t |
984 | pci_read_rom(struct file *filp, struct kobject *kobj, | 984 | pci_read_rom(struct file *filp, struct kobject *kobj, |
985 | struct bin_attribute *bin_attr, | 985 | struct bin_attribute *bin_attr, |
986 | char *buf, loff_t off, size_t count) | 986 | char *buf, loff_t off, size_t count) |
987 | { | 987 | { |
988 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); | 988 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); |
989 | void __iomem *rom; | 989 | void __iomem *rom; |
990 | size_t size; | 990 | size_t size; |
991 | 991 | ||
992 | if (!pdev->rom_attr_enabled) | 992 | if (!pdev->rom_attr_enabled) |
993 | return -EINVAL; | 993 | return -EINVAL; |
994 | 994 | ||
995 | rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ | 995 | rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ |
996 | if (!rom || !size) | 996 | if (!rom || !size) |
997 | return -EIO; | 997 | return -EIO; |
998 | 998 | ||
999 | if (off >= size) | 999 | if (off >= size) |
1000 | count = 0; | 1000 | count = 0; |
1001 | else { | 1001 | else { |
1002 | if (off + count > size) | 1002 | if (off + count > size) |
1003 | count = size - off; | 1003 | count = size - off; |
1004 | 1004 | ||
1005 | memcpy_fromio(buf, rom + off, count); | 1005 | memcpy_fromio(buf, rom + off, count); |
1006 | } | 1006 | } |
1007 | pci_unmap_rom(pdev, rom); | 1007 | pci_unmap_rom(pdev, rom); |
1008 | 1008 | ||
1009 | return count; | 1009 | return count; |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | static struct bin_attribute pci_config_attr = { | 1012 | static struct bin_attribute pci_config_attr = { |
1013 | .attr = { | 1013 | .attr = { |
1014 | .name = "config", | 1014 | .name = "config", |
1015 | .mode = S_IRUGO | S_IWUSR, | 1015 | .mode = S_IRUGO | S_IWUSR, |
1016 | }, | 1016 | }, |
1017 | .size = PCI_CFG_SPACE_SIZE, | 1017 | .size = PCI_CFG_SPACE_SIZE, |
1018 | .read = pci_read_config, | 1018 | .read = pci_read_config, |
1019 | .write = pci_write_config, | 1019 | .write = pci_write_config, |
1020 | }; | 1020 | }; |
1021 | 1021 | ||
1022 | static struct bin_attribute pcie_config_attr = { | 1022 | static struct bin_attribute pcie_config_attr = { |
1023 | .attr = { | 1023 | .attr = { |
1024 | .name = "config", | 1024 | .name = "config", |
1025 | .mode = S_IRUGO | S_IWUSR, | 1025 | .mode = S_IRUGO | S_IWUSR, |
1026 | }, | 1026 | }, |
1027 | .size = PCI_CFG_SPACE_EXP_SIZE, | 1027 | .size = PCI_CFG_SPACE_EXP_SIZE, |
1028 | .read = pci_read_config, | 1028 | .read = pci_read_config, |
1029 | .write = pci_write_config, | 1029 | .write = pci_write_config, |
1030 | }; | 1030 | }; |
1031 | 1031 | ||
1032 | int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev) | 1032 | int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev) |
1033 | { | 1033 | { |
1034 | return 0; | 1034 | return 0; |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | static ssize_t reset_store(struct device *dev, | 1037 | static ssize_t reset_store(struct device *dev, |
1038 | struct device_attribute *attr, const char *buf, | 1038 | struct device_attribute *attr, const char *buf, |
1039 | size_t count) | 1039 | size_t count) |
1040 | { | 1040 | { |
1041 | struct pci_dev *pdev = to_pci_dev(dev); | 1041 | struct pci_dev *pdev = to_pci_dev(dev); |
1042 | unsigned long val; | 1042 | unsigned long val; |
1043 | ssize_t result = strict_strtoul(buf, 0, &val); | 1043 | ssize_t result = strict_strtoul(buf, 0, &val); |
1044 | 1044 | ||
1045 | if (result < 0) | 1045 | if (result < 0) |
1046 | return result; | 1046 | return result; |
1047 | 1047 | ||
1048 | if (val != 1) | 1048 | if (val != 1) |
1049 | return -EINVAL; | 1049 | return -EINVAL; |
1050 | 1050 | ||
1051 | result = pci_reset_function(pdev); | 1051 | result = pci_reset_function(pdev); |
1052 | if (result < 0) | 1052 | if (result < 0) |
1053 | return result; | 1053 | return result; |
1054 | 1054 | ||
1055 | return count; | 1055 | return count; |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store); | 1058 | static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store); |
1059 | 1059 | ||
1060 | static int pci_create_capabilities_sysfs(struct pci_dev *dev) | 1060 | static int pci_create_capabilities_sysfs(struct pci_dev *dev) |
1061 | { | 1061 | { |
1062 | int retval; | 1062 | int retval; |
1063 | struct bin_attribute *attr; | 1063 | struct bin_attribute *attr; |
1064 | 1064 | ||
1065 | /* If the device has VPD, try to expose it in sysfs. */ | 1065 | /* If the device has VPD, try to expose it in sysfs. */ |
1066 | if (dev->vpd) { | 1066 | if (dev->vpd) { |
1067 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); | 1067 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); |
1068 | if (!attr) | 1068 | if (!attr) |
1069 | return -ENOMEM; | 1069 | return -ENOMEM; |
1070 | 1070 | ||
1071 | sysfs_bin_attr_init(attr); | 1071 | sysfs_bin_attr_init(attr); |
1072 | attr->size = dev->vpd->len; | 1072 | attr->size = dev->vpd->len; |
1073 | attr->attr.name = "vpd"; | 1073 | attr->attr.name = "vpd"; |
1074 | attr->attr.mode = S_IRUSR | S_IWUSR; | 1074 | attr->attr.mode = S_IRUSR | S_IWUSR; |
1075 | attr->read = read_vpd_attr; | 1075 | attr->read = read_vpd_attr; |
1076 | attr->write = write_vpd_attr; | 1076 | attr->write = write_vpd_attr; |
1077 | retval = sysfs_create_bin_file(&dev->dev.kobj, attr); | 1077 | retval = sysfs_create_bin_file(&dev->dev.kobj, attr); |
1078 | if (retval) { | 1078 | if (retval) { |
1079 | kfree(dev->vpd->attr); | 1079 | kfree(dev->vpd->attr); |
1080 | return retval; | 1080 | return retval; |
1081 | } | 1081 | } |
1082 | dev->vpd->attr = attr; | 1082 | dev->vpd->attr = attr; |
1083 | } | 1083 | } |
1084 | 1084 | ||
1085 | /* Active State Power Management */ | 1085 | /* Active State Power Management */ |
1086 | pcie_aspm_create_sysfs_dev_files(dev); | 1086 | pcie_aspm_create_sysfs_dev_files(dev); |
1087 | 1087 | ||
1088 | if (!pci_probe_reset_function(dev)) { | 1088 | if (!pci_probe_reset_function(dev)) { |
1089 | retval = device_create_file(&dev->dev, &reset_attr); | 1089 | retval = device_create_file(&dev->dev, &reset_attr); |
1090 | if (retval) | 1090 | if (retval) |
1091 | goto error; | 1091 | goto error; |
1092 | dev->reset_fn = 1; | 1092 | dev->reset_fn = 1; |
1093 | } | 1093 | } |
1094 | return 0; | 1094 | return 0; |
1095 | 1095 | ||
1096 | error: | 1096 | error: |
1097 | pcie_aspm_remove_sysfs_dev_files(dev); | 1097 | pcie_aspm_remove_sysfs_dev_files(dev); |
1098 | if (dev->vpd && dev->vpd->attr) { | 1098 | if (dev->vpd && dev->vpd->attr) { |
1099 | sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr); | 1099 | sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr); |
1100 | kfree(dev->vpd->attr); | 1100 | kfree(dev->vpd->attr); |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | return retval; | 1103 | return retval; |
1104 | } | 1104 | } |
1105 | 1105 | ||
1106 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | 1106 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) |
1107 | { | 1107 | { |
1108 | int retval; | 1108 | int retval; |
1109 | int rom_size = 0; | 1109 | int rom_size = 0; |
1110 | struct bin_attribute *attr; | 1110 | struct bin_attribute *attr; |
1111 | 1111 | ||
1112 | if (!sysfs_initialized) | 1112 | if (!sysfs_initialized) |
1113 | return -EACCES; | 1113 | return -EACCES; |
1114 | 1114 | ||
1115 | if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) | 1115 | if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) |
1116 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); | 1116 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); |
1117 | else | 1117 | else |
1118 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); | 1118 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); |
1119 | if (retval) | 1119 | if (retval) |
1120 | goto err; | 1120 | goto err; |
1121 | 1121 | ||
1122 | retval = pci_create_resource_files(pdev); | 1122 | retval = pci_create_resource_files(pdev); |
1123 | if (retval) | 1123 | if (retval) |
1124 | goto err_config_file; | 1124 | goto err_config_file; |
1125 | 1125 | ||
1126 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) | 1126 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) |
1127 | rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE); | 1127 | rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE); |
1128 | else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) | 1128 | else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) |
1129 | rom_size = 0x20000; | 1129 | rom_size = 0x20000; |
1130 | 1130 | ||
1131 | /* If the device has a ROM, try to expose it in sysfs. */ | 1131 | /* If the device has a ROM, try to expose it in sysfs. */ |
1132 | if (rom_size) { | 1132 | if (rom_size) { |
1133 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); | 1133 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); |
1134 | if (!attr) { | 1134 | if (!attr) { |
1135 | retval = -ENOMEM; | 1135 | retval = -ENOMEM; |
1136 | goto err_resource_files; | 1136 | goto err_resource_files; |
1137 | } | 1137 | } |
1138 | sysfs_bin_attr_init(attr); | 1138 | sysfs_bin_attr_init(attr); |
1139 | attr->size = rom_size; | 1139 | attr->size = rom_size; |
1140 | attr->attr.name = "rom"; | 1140 | attr->attr.name = "rom"; |
1141 | attr->attr.mode = S_IRUSR; | 1141 | attr->attr.mode = S_IRUSR; |
1142 | attr->read = pci_read_rom; | 1142 | attr->read = pci_read_rom; |
1143 | attr->write = pci_write_rom; | 1143 | attr->write = pci_write_rom; |
1144 | retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); | 1144 | retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); |
1145 | if (retval) { | 1145 | if (retval) { |
1146 | kfree(attr); | 1146 | kfree(attr); |
1147 | goto err_resource_files; | 1147 | goto err_resource_files; |
1148 | } | 1148 | } |
1149 | pdev->rom_attr = attr; | 1149 | pdev->rom_attr = attr; |
1150 | } | 1150 | } |
1151 | 1151 | ||
1152 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { | 1152 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { |
1153 | retval = device_create_file(&pdev->dev, &vga_attr); | 1153 | retval = device_create_file(&pdev->dev, &vga_attr); |
1154 | if (retval) | 1154 | if (retval) |
1155 | goto err_rom_file; | 1155 | goto err_rom_file; |
1156 | } | 1156 | } |
1157 | 1157 | ||
1158 | /* add platform-specific attributes */ | 1158 | /* add platform-specific attributes */ |
1159 | retval = pcibios_add_platform_entries(pdev); | 1159 | retval = pcibios_add_platform_entries(pdev); |
1160 | if (retval) | 1160 | if (retval) |
1161 | goto err_vga_file; | 1161 | goto err_vga_file; |
1162 | 1162 | ||
1163 | /* add sysfs entries for various capabilities */ | 1163 | /* add sysfs entries for various capabilities */ |
1164 | retval = pci_create_capabilities_sysfs(pdev); | 1164 | retval = pci_create_capabilities_sysfs(pdev); |
1165 | if (retval) | 1165 | if (retval) |
1166 | goto err_vga_file; | 1166 | goto err_vga_file; |
1167 | 1167 | ||
1168 | pci_create_firmware_label_files(pdev); | ||
1169 | |||
1168 | return 0; | 1170 | return 0; |
1169 | 1171 | ||
1170 | err_vga_file: | 1172 | err_vga_file: |
1171 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) | 1173 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) |
1172 | device_remove_file(&pdev->dev, &vga_attr); | 1174 | device_remove_file(&pdev->dev, &vga_attr); |
1173 | err_rom_file: | 1175 | err_rom_file: |
1174 | if (rom_size) { | 1176 | if (rom_size) { |
1175 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); | 1177 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); |
1176 | kfree(pdev->rom_attr); | 1178 | kfree(pdev->rom_attr); |
1177 | pdev->rom_attr = NULL; | 1179 | pdev->rom_attr = NULL; |
1178 | } | 1180 | } |
1179 | err_resource_files: | 1181 | err_resource_files: |
1180 | pci_remove_resource_files(pdev); | 1182 | pci_remove_resource_files(pdev); |
1181 | err_config_file: | 1183 | err_config_file: |
1182 | if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) | 1184 | if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) |
1183 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); | 1185 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); |
1184 | else | 1186 | else |
1185 | sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); | 1187 | sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); |
1186 | err: | 1188 | err: |
1187 | return retval; | 1189 | return retval; |
1188 | } | 1190 | } |
1189 | 1191 | ||
1190 | static void pci_remove_capabilities_sysfs(struct pci_dev *dev) | 1192 | static void pci_remove_capabilities_sysfs(struct pci_dev *dev) |
1191 | { | 1193 | { |
1192 | if (dev->vpd && dev->vpd->attr) { | 1194 | if (dev->vpd && dev->vpd->attr) { |
1193 | sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr); | 1195 | sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr); |
1194 | kfree(dev->vpd->attr); | 1196 | kfree(dev->vpd->attr); |
1195 | } | 1197 | } |
1196 | 1198 | ||
1197 | pcie_aspm_remove_sysfs_dev_files(dev); | 1199 | pcie_aspm_remove_sysfs_dev_files(dev); |
1198 | if (dev->reset_fn) { | 1200 | if (dev->reset_fn) { |
1199 | device_remove_file(&dev->dev, &reset_attr); | 1201 | device_remove_file(&dev->dev, &reset_attr); |
1200 | dev->reset_fn = 0; | 1202 | dev->reset_fn = 0; |
1201 | } | 1203 | } |
1202 | } | 1204 | } |
1203 | 1205 | ||
1204 | /** | 1206 | /** |
1205 | * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files | 1207 | * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files |
1206 | * @pdev: device whose entries we should free | 1208 | * @pdev: device whose entries we should free |
1207 | * | 1209 | * |
1208 | * Cleanup when @pdev is removed from sysfs. | 1210 | * Cleanup when @pdev is removed from sysfs. |
1209 | */ | 1211 | */ |
1210 | void pci_remove_sysfs_dev_files(struct pci_dev *pdev) | 1212 | void pci_remove_sysfs_dev_files(struct pci_dev *pdev) |
1211 | { | 1213 | { |
1212 | int rom_size = 0; | 1214 | int rom_size = 0; |
1213 | 1215 | ||
1214 | if (!sysfs_initialized) | 1216 | if (!sysfs_initialized) |
1215 | return; | 1217 | return; |
1216 | 1218 | ||
1217 | pci_remove_capabilities_sysfs(pdev); | 1219 | pci_remove_capabilities_sysfs(pdev); |
1218 | 1220 | ||
1219 | if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) | 1221 | if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) |
1220 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); | 1222 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); |
1221 | else | 1223 | else |
1222 | sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); | 1224 | sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); |
1223 | 1225 | ||
1224 | pci_remove_resource_files(pdev); | 1226 | pci_remove_resource_files(pdev); |
1225 | 1227 | ||
1226 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) | 1228 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) |
1227 | rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE); | 1229 | rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE); |
1228 | else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) | 1230 | else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) |
1229 | rom_size = 0x20000; | 1231 | rom_size = 0x20000; |
1230 | 1232 | ||
1231 | if (rom_size && pdev->rom_attr) { | 1233 | if (rom_size && pdev->rom_attr) { |
1232 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); | 1234 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); |
1233 | kfree(pdev->rom_attr); | 1235 | kfree(pdev->rom_attr); |
1234 | } | 1236 | } |
1237 | |||
1238 | pci_remove_firmware_label_files(pdev); | ||
1239 | |||
1235 | } | 1240 | } |
1236 | 1241 | ||
1237 | static int __init pci_sysfs_init(void) | 1242 | static int __init pci_sysfs_init(void) |
1238 | { | 1243 | { |
1239 | struct pci_dev *pdev = NULL; | 1244 | struct pci_dev *pdev = NULL; |
1240 | int retval; | 1245 | int retval; |
1241 | 1246 | ||
1242 | sysfs_initialized = 1; | 1247 | sysfs_initialized = 1; |
1243 | for_each_pci_dev(pdev) { | 1248 | for_each_pci_dev(pdev) { |
1244 | retval = pci_create_sysfs_dev_files(pdev); | 1249 | retval = pci_create_sysfs_dev_files(pdev); |
1245 | if (retval) { | 1250 | if (retval) { |
1246 | pci_dev_put(pdev); | 1251 | pci_dev_put(pdev); |
1247 | return retval; | 1252 | return retval; |
1248 | } | 1253 | } |
1249 | } | 1254 | } |
1250 | 1255 | ||
1251 | return 0; | 1256 | return 0; |
1252 | } | 1257 | } |
1253 | 1258 | ||
1254 | late_initcall(pci_sysfs_init); | 1259 | late_initcall(pci_sysfs_init); |
1255 | 1260 |
drivers/pci/pci.h
1 | #ifndef DRIVERS_PCI_H | 1 | #ifndef DRIVERS_PCI_H |
2 | #define DRIVERS_PCI_H | 2 | #define DRIVERS_PCI_H |
3 | 3 | ||
4 | #include <linux/workqueue.h> | 4 | #include <linux/workqueue.h> |
5 | 5 | ||
6 | #define PCI_CFG_SPACE_SIZE 256 | 6 | #define PCI_CFG_SPACE_SIZE 256 |
7 | #define PCI_CFG_SPACE_EXP_SIZE 4096 | 7 | #define PCI_CFG_SPACE_EXP_SIZE 4096 |
8 | 8 | ||
9 | /* Functions internal to the PCI core code */ | 9 | /* Functions internal to the PCI core code */ |
10 | 10 | ||
11 | extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); | 11 | extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); |
12 | extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); | 12 | extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); |
13 | extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); | 13 | extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); |
14 | #ifndef CONFIG_DMI | ||
15 | static inline void pci_create_firmware_label_files(struct pci_dev *pdev) | ||
16 | { return 0; } | ||
17 | static inline void pci_remove_firmware_label_files(struct pci_dev *pdev) | ||
18 | { return 0; } | ||
19 | #else | ||
20 | extern void pci_create_firmware_label_files(struct pci_dev *pdev); | ||
21 | extern void pci_remove_firmware_label_files(struct pci_dev *pdev); | ||
22 | #endif | ||
14 | extern void pci_cleanup_rom(struct pci_dev *dev); | 23 | extern void pci_cleanup_rom(struct pci_dev *dev); |
15 | #ifdef HAVE_PCI_MMAP | 24 | #ifdef HAVE_PCI_MMAP |
16 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, | 25 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, |
17 | struct vm_area_struct *vma); | 26 | struct vm_area_struct *vma); |
18 | #endif | 27 | #endif |
19 | int pci_probe_reset_function(struct pci_dev *dev); | 28 | int pci_probe_reset_function(struct pci_dev *dev); |
20 | 29 | ||
21 | /** | 30 | /** |
22 | * struct pci_platform_pm_ops - Firmware PM callbacks | 31 | * struct pci_platform_pm_ops - Firmware PM callbacks |
23 | * | 32 | * |
24 | * @is_manageable: returns 'true' if given device is power manageable by the | 33 | * @is_manageable: returns 'true' if given device is power manageable by the |
25 | * platform firmware | 34 | * platform firmware |
26 | * | 35 | * |
27 | * @set_state: invokes the platform firmware to set the device's power state | 36 | * @set_state: invokes the platform firmware to set the device's power state |
28 | * | 37 | * |
29 | * @choose_state: returns PCI power state of given device preferred by the | 38 | * @choose_state: returns PCI power state of given device preferred by the |
30 | * platform; to be used during system-wide transitions from a | 39 | * platform; to be used during system-wide transitions from a |
31 | * sleeping state to the working state and vice versa | 40 | * sleeping state to the working state and vice versa |
32 | * | 41 | * |
33 | * @can_wakeup: returns 'true' if given device is capable of waking up the | 42 | * @can_wakeup: returns 'true' if given device is capable of waking up the |
34 | * system from a sleeping state | 43 | * system from a sleeping state |
35 | * | 44 | * |
36 | * @sleep_wake: enables/disables the system wake up capability of given device | 45 | * @sleep_wake: enables/disables the system wake up capability of given device |
37 | * | 46 | * |
38 | * @run_wake: enables/disables the platform to generate run-time wake-up events | 47 | * @run_wake: enables/disables the platform to generate run-time wake-up events |
39 | * for given device (the device's wake-up capability has to be | 48 | * for given device (the device's wake-up capability has to be |
40 | * enabled by @sleep_wake for this feature to work) | 49 | * enabled by @sleep_wake for this feature to work) |
41 | * | 50 | * |
42 | * If given platform is generally capable of power managing PCI devices, all of | 51 | * If given platform is generally capable of power managing PCI devices, all of |
43 | * these callbacks are mandatory. | 52 | * these callbacks are mandatory. |
44 | */ | 53 | */ |
45 | struct pci_platform_pm_ops { | 54 | struct pci_platform_pm_ops { |
46 | bool (*is_manageable)(struct pci_dev *dev); | 55 | bool (*is_manageable)(struct pci_dev *dev); |
47 | int (*set_state)(struct pci_dev *dev, pci_power_t state); | 56 | int (*set_state)(struct pci_dev *dev, pci_power_t state); |
48 | pci_power_t (*choose_state)(struct pci_dev *dev); | 57 | pci_power_t (*choose_state)(struct pci_dev *dev); |
49 | bool (*can_wakeup)(struct pci_dev *dev); | 58 | bool (*can_wakeup)(struct pci_dev *dev); |
50 | int (*sleep_wake)(struct pci_dev *dev, bool enable); | 59 | int (*sleep_wake)(struct pci_dev *dev, bool enable); |
51 | int (*run_wake)(struct pci_dev *dev, bool enable); | 60 | int (*run_wake)(struct pci_dev *dev, bool enable); |
52 | }; | 61 | }; |
53 | 62 | ||
54 | extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); | 63 | extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); |
55 | extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state); | 64 | extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state); |
56 | extern void pci_disable_enabled_device(struct pci_dev *dev); | 65 | extern void pci_disable_enabled_device(struct pci_dev *dev); |
57 | extern bool pci_check_pme_status(struct pci_dev *dev); | 66 | extern bool pci_check_pme_status(struct pci_dev *dev); |
58 | extern int pci_finish_runtime_suspend(struct pci_dev *dev); | 67 | extern int pci_finish_runtime_suspend(struct pci_dev *dev); |
59 | extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); | 68 | extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); |
60 | extern void pci_pme_wakeup_bus(struct pci_bus *bus); | 69 | extern void pci_pme_wakeup_bus(struct pci_bus *bus); |
61 | extern void pci_pm_init(struct pci_dev *dev); | 70 | extern void pci_pm_init(struct pci_dev *dev); |
62 | extern void platform_pci_wakeup_init(struct pci_dev *dev); | 71 | extern void platform_pci_wakeup_init(struct pci_dev *dev); |
63 | extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); | 72 | extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); |
64 | 73 | ||
65 | static inline bool pci_is_bridge(struct pci_dev *pci_dev) | 74 | static inline bool pci_is_bridge(struct pci_dev *pci_dev) |
66 | { | 75 | { |
67 | return !!(pci_dev->subordinate); | 76 | return !!(pci_dev->subordinate); |
68 | } | 77 | } |
69 | 78 | ||
70 | extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); | 79 | extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); |
71 | extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); | 80 | extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); |
72 | extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); | 81 | extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); |
73 | extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); | 82 | extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); |
74 | extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); | 83 | extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); |
75 | extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); | 84 | extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); |
76 | 85 | ||
77 | struct pci_vpd_ops { | 86 | struct pci_vpd_ops { |
78 | ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); | 87 | ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); |
79 | ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); | 88 | ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); |
80 | void (*release)(struct pci_dev *dev); | 89 | void (*release)(struct pci_dev *dev); |
81 | }; | 90 | }; |
82 | 91 | ||
83 | struct pci_vpd { | 92 | struct pci_vpd { |
84 | unsigned int len; | 93 | unsigned int len; |
85 | const struct pci_vpd_ops *ops; | 94 | const struct pci_vpd_ops *ops; |
86 | struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ | 95 | struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ |
87 | }; | 96 | }; |
88 | 97 | ||
89 | extern int pci_vpd_pci22_init(struct pci_dev *dev); | 98 | extern int pci_vpd_pci22_init(struct pci_dev *dev); |
90 | static inline void pci_vpd_release(struct pci_dev *dev) | 99 | static inline void pci_vpd_release(struct pci_dev *dev) |
91 | { | 100 | { |
92 | if (dev->vpd) | 101 | if (dev->vpd) |
93 | dev->vpd->ops->release(dev); | 102 | dev->vpd->ops->release(dev); |
94 | } | 103 | } |
95 | 104 | ||
96 | /* PCI /proc functions */ | 105 | /* PCI /proc functions */ |
97 | #ifdef CONFIG_PROC_FS | 106 | #ifdef CONFIG_PROC_FS |
98 | extern int pci_proc_attach_device(struct pci_dev *dev); | 107 | extern int pci_proc_attach_device(struct pci_dev *dev); |
99 | extern int pci_proc_detach_device(struct pci_dev *dev); | 108 | extern int pci_proc_detach_device(struct pci_dev *dev); |
100 | extern int pci_proc_detach_bus(struct pci_bus *bus); | 109 | extern int pci_proc_detach_bus(struct pci_bus *bus); |
101 | #else | 110 | #else |
102 | static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; } | 111 | static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; } |
103 | static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; } | 112 | static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; } |
104 | static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } | 113 | static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } |
105 | #endif | 114 | #endif |
106 | 115 | ||
107 | /* Functions for PCI Hotplug drivers to use */ | 116 | /* Functions for PCI Hotplug drivers to use */ |
108 | extern unsigned int pci_do_scan_bus(struct pci_bus *bus); | 117 | extern unsigned int pci_do_scan_bus(struct pci_bus *bus); |
109 | 118 | ||
110 | #ifdef HAVE_PCI_LEGACY | 119 | #ifdef HAVE_PCI_LEGACY |
111 | extern void pci_create_legacy_files(struct pci_bus *bus); | 120 | extern void pci_create_legacy_files(struct pci_bus *bus); |
112 | extern void pci_remove_legacy_files(struct pci_bus *bus); | 121 | extern void pci_remove_legacy_files(struct pci_bus *bus); |
113 | #else | 122 | #else |
114 | static inline void pci_create_legacy_files(struct pci_bus *bus) { return; } | 123 | static inline void pci_create_legacy_files(struct pci_bus *bus) { return; } |
115 | static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; } | 124 | static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; } |
116 | #endif | 125 | #endif |
117 | 126 | ||
118 | /* Lock for read/write access to pci device and bus lists */ | 127 | /* Lock for read/write access to pci device and bus lists */ |
119 | extern struct rw_semaphore pci_bus_sem; | 128 | extern struct rw_semaphore pci_bus_sem; |
120 | 129 | ||
121 | extern unsigned int pci_pm_d3_delay; | 130 | extern unsigned int pci_pm_d3_delay; |
122 | 131 | ||
123 | #ifdef CONFIG_PCI_MSI | 132 | #ifdef CONFIG_PCI_MSI |
124 | void pci_no_msi(void); | 133 | void pci_no_msi(void); |
125 | extern void pci_msi_init_pci_dev(struct pci_dev *dev); | 134 | extern void pci_msi_init_pci_dev(struct pci_dev *dev); |
126 | #else | 135 | #else |
127 | static inline void pci_no_msi(void) { } | 136 | static inline void pci_no_msi(void) { } |
128 | static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } | 137 | static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } |
129 | #endif | 138 | #endif |
130 | 139 | ||
131 | #ifdef CONFIG_PCIEAER | 140 | #ifdef CONFIG_PCIEAER |
132 | void pci_no_aer(void); | 141 | void pci_no_aer(void); |
133 | #else | 142 | #else |
134 | static inline void pci_no_aer(void) { } | 143 | static inline void pci_no_aer(void) { } |
135 | #endif | 144 | #endif |
136 | 145 | ||
137 | static inline int pci_no_d1d2(struct pci_dev *dev) | 146 | static inline int pci_no_d1d2(struct pci_dev *dev) |
138 | { | 147 | { |
139 | unsigned int parent_dstates = 0; | 148 | unsigned int parent_dstates = 0; |
140 | 149 | ||
141 | if (dev->bus->self) | 150 | if (dev->bus->self) |
142 | parent_dstates = dev->bus->self->no_d1d2; | 151 | parent_dstates = dev->bus->self->no_d1d2; |
143 | return (dev->no_d1d2 || parent_dstates); | 152 | return (dev->no_d1d2 || parent_dstates); |
144 | 153 | ||
145 | } | 154 | } |
146 | extern struct device_attribute pci_dev_attrs[]; | 155 | extern struct device_attribute pci_dev_attrs[]; |
147 | extern struct device_attribute dev_attr_cpuaffinity; | 156 | extern struct device_attribute dev_attr_cpuaffinity; |
148 | extern struct device_attribute dev_attr_cpulistaffinity; | 157 | extern struct device_attribute dev_attr_cpulistaffinity; |
149 | #ifdef CONFIG_HOTPLUG | 158 | #ifdef CONFIG_HOTPLUG |
150 | extern struct bus_attribute pci_bus_attrs[]; | 159 | extern struct bus_attribute pci_bus_attrs[]; |
151 | #else | 160 | #else |
152 | #define pci_bus_attrs NULL | 161 | #define pci_bus_attrs NULL |
153 | #endif | 162 | #endif |
154 | 163 | ||
155 | 164 | ||
156 | /** | 165 | /** |
157 | * pci_match_one_device - Tell if a PCI device structure has a matching | 166 | * pci_match_one_device - Tell if a PCI device structure has a matching |
158 | * PCI device id structure | 167 | * PCI device id structure |
159 | * @id: single PCI device id structure to match | 168 | * @id: single PCI device id structure to match |
160 | * @dev: the PCI device structure to match against | 169 | * @dev: the PCI device structure to match against |
161 | * | 170 | * |
162 | * Returns the matching pci_device_id structure or %NULL if there is no match. | 171 | * Returns the matching pci_device_id structure or %NULL if there is no match. |
163 | */ | 172 | */ |
164 | static inline const struct pci_device_id * | 173 | static inline const struct pci_device_id * |
165 | pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) | 174 | pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) |
166 | { | 175 | { |
167 | if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && | 176 | if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && |
168 | (id->device == PCI_ANY_ID || id->device == dev->device) && | 177 | (id->device == PCI_ANY_ID || id->device == dev->device) && |
169 | (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) && | 178 | (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) && |
170 | (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) && | 179 | (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) && |
171 | !((id->class ^ dev->class) & id->class_mask)) | 180 | !((id->class ^ dev->class) & id->class_mask)) |
172 | return id; | 181 | return id; |
173 | return NULL; | 182 | return NULL; |
174 | } | 183 | } |
175 | 184 | ||
176 | struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); | 185 | struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); |
177 | 186 | ||
178 | /* PCI slot sysfs helper code */ | 187 | /* PCI slot sysfs helper code */ |
179 | #define to_pci_slot(s) container_of(s, struct pci_slot, kobj) | 188 | #define to_pci_slot(s) container_of(s, struct pci_slot, kobj) |
180 | 189 | ||
181 | extern struct kset *pci_slots_kset; | 190 | extern struct kset *pci_slots_kset; |
182 | 191 | ||
183 | struct pci_slot_attribute { | 192 | struct pci_slot_attribute { |
184 | struct attribute attr; | 193 | struct attribute attr; |
185 | ssize_t (*show)(struct pci_slot *, char *); | 194 | ssize_t (*show)(struct pci_slot *, char *); |
186 | ssize_t (*store)(struct pci_slot *, const char *, size_t); | 195 | ssize_t (*store)(struct pci_slot *, const char *, size_t); |
187 | }; | 196 | }; |
188 | #define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr) | 197 | #define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr) |
189 | 198 | ||
190 | enum pci_bar_type { | 199 | enum pci_bar_type { |
191 | pci_bar_unknown, /* Standard PCI BAR probe */ | 200 | pci_bar_unknown, /* Standard PCI BAR probe */ |
192 | pci_bar_io, /* An io port BAR */ | 201 | pci_bar_io, /* An io port BAR */ |
193 | pci_bar_mem32, /* A 32-bit memory BAR */ | 202 | pci_bar_mem32, /* A 32-bit memory BAR */ |
194 | pci_bar_mem64, /* A 64-bit memory BAR */ | 203 | pci_bar_mem64, /* A 64-bit memory BAR */ |
195 | }; | 204 | }; |
196 | 205 | ||
197 | extern int pci_setup_device(struct pci_dev *dev); | 206 | extern int pci_setup_device(struct pci_dev *dev); |
198 | extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | 207 | extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, |
199 | struct resource *res, unsigned int reg); | 208 | struct resource *res, unsigned int reg); |
200 | extern int pci_resource_bar(struct pci_dev *dev, int resno, | 209 | extern int pci_resource_bar(struct pci_dev *dev, int resno, |
201 | enum pci_bar_type *type); | 210 | enum pci_bar_type *type); |
202 | extern int pci_bus_add_child(struct pci_bus *bus); | 211 | extern int pci_bus_add_child(struct pci_bus *bus); |
203 | extern void pci_enable_ari(struct pci_dev *dev); | 212 | extern void pci_enable_ari(struct pci_dev *dev); |
204 | /** | 213 | /** |
205 | * pci_ari_enabled - query ARI forwarding status | 214 | * pci_ari_enabled - query ARI forwarding status |
206 | * @bus: the PCI bus | 215 | * @bus: the PCI bus |
207 | * | 216 | * |
208 | * Returns 1 if ARI forwarding is enabled, or 0 if not enabled; | 217 | * Returns 1 if ARI forwarding is enabled, or 0 if not enabled; |
209 | */ | 218 | */ |
210 | static inline int pci_ari_enabled(struct pci_bus *bus) | 219 | static inline int pci_ari_enabled(struct pci_bus *bus) |
211 | { | 220 | { |
212 | return bus->self && bus->self->ari_enabled; | 221 | return bus->self && bus->self->ari_enabled; |
213 | } | 222 | } |
214 | 223 | ||
215 | #ifdef CONFIG_PCI_QUIRKS | 224 | #ifdef CONFIG_PCI_QUIRKS |
216 | extern int pci_is_reassigndev(struct pci_dev *dev); | 225 | extern int pci_is_reassigndev(struct pci_dev *dev); |
217 | resource_size_t pci_specified_resource_alignment(struct pci_dev *dev); | 226 | resource_size_t pci_specified_resource_alignment(struct pci_dev *dev); |
218 | extern void pci_disable_bridge_window(struct pci_dev *dev); | 227 | extern void pci_disable_bridge_window(struct pci_dev *dev); |
219 | #endif | 228 | #endif |
220 | 229 | ||
221 | /* Single Root I/O Virtualization */ | 230 | /* Single Root I/O Virtualization */ |
222 | struct pci_sriov { | 231 | struct pci_sriov { |
223 | int pos; /* capability position */ | 232 | int pos; /* capability position */ |
224 | int nres; /* number of resources */ | 233 | int nres; /* number of resources */ |
225 | u32 cap; /* SR-IOV Capabilities */ | 234 | u32 cap; /* SR-IOV Capabilities */ |
226 | u16 ctrl; /* SR-IOV Control */ | 235 | u16 ctrl; /* SR-IOV Control */ |
227 | u16 total; /* total VFs associated with the PF */ | 236 | u16 total; /* total VFs associated with the PF */ |
228 | u16 initial; /* initial VFs associated with the PF */ | 237 | u16 initial; /* initial VFs associated with the PF */ |
229 | u16 nr_virtfn; /* number of VFs available */ | 238 | u16 nr_virtfn; /* number of VFs available */ |
230 | u16 offset; /* first VF Routing ID offset */ | 239 | u16 offset; /* first VF Routing ID offset */ |
231 | u16 stride; /* following VF stride */ | 240 | u16 stride; /* following VF stride */ |
232 | u32 pgsz; /* page size for BAR alignment */ | 241 | u32 pgsz; /* page size for BAR alignment */ |
233 | u8 link; /* Function Dependency Link */ | 242 | u8 link; /* Function Dependency Link */ |
234 | struct pci_dev *dev; /* lowest numbered PF */ | 243 | struct pci_dev *dev; /* lowest numbered PF */ |
235 | struct pci_dev *self; /* this PF */ | 244 | struct pci_dev *self; /* this PF */ |
236 | struct mutex lock; /* lock for VF bus */ | 245 | struct mutex lock; /* lock for VF bus */ |
237 | struct work_struct mtask; /* VF Migration task */ | 246 | struct work_struct mtask; /* VF Migration task */ |
238 | u8 __iomem *mstate; /* VF Migration State Array */ | 247 | u8 __iomem *mstate; /* VF Migration State Array */ |
239 | }; | 248 | }; |
240 | 249 | ||
241 | /* Address Translation Service */ | 250 | /* Address Translation Service */ |
242 | struct pci_ats { | 251 | struct pci_ats { |
243 | int pos; /* capability position */ | 252 | int pos; /* capability position */ |
244 | int stu; /* Smallest Translation Unit */ | 253 | int stu; /* Smallest Translation Unit */ |
245 | int qdep; /* Invalidate Queue Depth */ | 254 | int qdep; /* Invalidate Queue Depth */ |
246 | int ref_cnt; /* Physical Function reference count */ | 255 | int ref_cnt; /* Physical Function reference count */ |
247 | unsigned int is_enabled:1; /* Enable bit is set */ | 256 | unsigned int is_enabled:1; /* Enable bit is set */ |
248 | }; | 257 | }; |
249 | 258 | ||
250 | #ifdef CONFIG_PCI_IOV | 259 | #ifdef CONFIG_PCI_IOV |
251 | extern int pci_iov_init(struct pci_dev *dev); | 260 | extern int pci_iov_init(struct pci_dev *dev); |
252 | extern void pci_iov_release(struct pci_dev *dev); | 261 | extern void pci_iov_release(struct pci_dev *dev); |
253 | extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, | 262 | extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, |
254 | enum pci_bar_type *type); | 263 | enum pci_bar_type *type); |
255 | extern int pci_sriov_resource_alignment(struct pci_dev *dev, int resno); | 264 | extern int pci_sriov_resource_alignment(struct pci_dev *dev, int resno); |
256 | extern void pci_restore_iov_state(struct pci_dev *dev); | 265 | extern void pci_restore_iov_state(struct pci_dev *dev); |
257 | extern int pci_iov_bus_range(struct pci_bus *bus); | 266 | extern int pci_iov_bus_range(struct pci_bus *bus); |
258 | 267 | ||
259 | extern int pci_enable_ats(struct pci_dev *dev, int ps); | 268 | extern int pci_enable_ats(struct pci_dev *dev, int ps); |
260 | extern void pci_disable_ats(struct pci_dev *dev); | 269 | extern void pci_disable_ats(struct pci_dev *dev); |
261 | extern int pci_ats_queue_depth(struct pci_dev *dev); | 270 | extern int pci_ats_queue_depth(struct pci_dev *dev); |
262 | /** | 271 | /** |
263 | * pci_ats_enabled - query the ATS status | 272 | * pci_ats_enabled - query the ATS status |
264 | * @dev: the PCI device | 273 | * @dev: the PCI device |
265 | * | 274 | * |
266 | * Returns 1 if ATS capability is enabled, or 0 if not. | 275 | * Returns 1 if ATS capability is enabled, or 0 if not. |
267 | */ | 276 | */ |
268 | static inline int pci_ats_enabled(struct pci_dev *dev) | 277 | static inline int pci_ats_enabled(struct pci_dev *dev) |
269 | { | 278 | { |
270 | return dev->ats && dev->ats->is_enabled; | 279 | return dev->ats && dev->ats->is_enabled; |
271 | } | 280 | } |
272 | #else | 281 | #else |
273 | static inline int pci_iov_init(struct pci_dev *dev) | 282 | static inline int pci_iov_init(struct pci_dev *dev) |
274 | { | 283 | { |
275 | return -ENODEV; | 284 | return -ENODEV; |
276 | } | 285 | } |
277 | static inline void pci_iov_release(struct pci_dev *dev) | 286 | static inline void pci_iov_release(struct pci_dev *dev) |
278 | 287 | ||
279 | { | 288 | { |
280 | } | 289 | } |
281 | static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno, | 290 | static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno, |
282 | enum pci_bar_type *type) | 291 | enum pci_bar_type *type) |
283 | { | 292 | { |
284 | return 0; | 293 | return 0; |
285 | } | 294 | } |
286 | static inline void pci_restore_iov_state(struct pci_dev *dev) | 295 | static inline void pci_restore_iov_state(struct pci_dev *dev) |
287 | { | 296 | { |
288 | } | 297 | } |
289 | static inline int pci_iov_bus_range(struct pci_bus *bus) | 298 | static inline int pci_iov_bus_range(struct pci_bus *bus) |
290 | { | 299 | { |
291 | return 0; | 300 | return 0; |
292 | } | 301 | } |
293 | 302 | ||
294 | static inline int pci_enable_ats(struct pci_dev *dev, int ps) | 303 | static inline int pci_enable_ats(struct pci_dev *dev, int ps) |
295 | { | 304 | { |
296 | return -ENODEV; | 305 | return -ENODEV; |
297 | } | 306 | } |
298 | static inline void pci_disable_ats(struct pci_dev *dev) | 307 | static inline void pci_disable_ats(struct pci_dev *dev) |
299 | { | 308 | { |
300 | } | 309 | } |
301 | static inline int pci_ats_queue_depth(struct pci_dev *dev) | 310 | static inline int pci_ats_queue_depth(struct pci_dev *dev) |
302 | { | 311 | { |
303 | return -ENODEV; | 312 | return -ENODEV; |
304 | } | 313 | } |
305 | static inline int pci_ats_enabled(struct pci_dev *dev) | 314 | static inline int pci_ats_enabled(struct pci_dev *dev) |
306 | { | 315 | { |
307 | return 0; | 316 | return 0; |
308 | } | 317 | } |
309 | #endif /* CONFIG_PCI_IOV */ | 318 | #endif /* CONFIG_PCI_IOV */ |
310 | 319 | ||
311 | static inline int pci_resource_alignment(struct pci_dev *dev, | 320 | static inline int pci_resource_alignment(struct pci_dev *dev, |
312 | struct resource *res) | 321 | struct resource *res) |
313 | { | 322 | { |
314 | #ifdef CONFIG_PCI_IOV | 323 | #ifdef CONFIG_PCI_IOV |
315 | int resno = res - dev->resource; | 324 | int resno = res - dev->resource; |
316 | 325 | ||
317 | if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END) | 326 | if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END) |
318 | return pci_sriov_resource_alignment(dev, resno); | 327 | return pci_sriov_resource_alignment(dev, resno); |
319 | #endif | 328 | #endif |
320 | return resource_alignment(res); | 329 | return resource_alignment(res); |
321 | } | 330 | } |
322 | 331 | ||
323 | extern void pci_enable_acs(struct pci_dev *dev); | 332 | extern void pci_enable_acs(struct pci_dev *dev); |
324 | 333 | ||
325 | struct pci_dev_reset_methods { | 334 | struct pci_dev_reset_methods { |
326 | u16 vendor; | 335 | u16 vendor; |
327 | u16 device; | 336 | u16 device; |
328 | int (*reset)(struct pci_dev *dev, int probe); | 337 | int (*reset)(struct pci_dev *dev, int probe); |
329 | }; | 338 | }; |
330 | 339 | ||
331 | #ifdef CONFIG_PCI_QUIRKS | 340 | #ifdef CONFIG_PCI_QUIRKS |
332 | extern int pci_dev_specific_reset(struct pci_dev *dev, int probe); | 341 | extern int pci_dev_specific_reset(struct pci_dev *dev, int probe); |
333 | #else | 342 | #else |
334 | static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) | 343 | static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) |
335 | { | 344 | { |
336 | return -ENOTTY; | 345 | return -ENOTTY; |
337 | } | 346 | } |
338 | #endif | 347 | #endif |
339 | 348 | ||
340 | #endif /* DRIVERS_PCI_H */ | 349 | #endif /* DRIVERS_PCI_H */ |
341 | 350 |
include/linux/dmi.h
1 | #ifndef __DMI_H__ | 1 | #ifndef __DMI_H__ |
2 | #define __DMI_H__ | 2 | #define __DMI_H__ |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <linux/mod_devicetable.h> | 5 | #include <linux/mod_devicetable.h> |
6 | 6 | ||
7 | /* enum dmi_field is in mod_devicetable.h */ | 7 | /* enum dmi_field is in mod_devicetable.h */ |
8 | 8 | ||
9 | enum dmi_device_type { | 9 | enum dmi_device_type { |
10 | DMI_DEV_TYPE_ANY = 0, | 10 | DMI_DEV_TYPE_ANY = 0, |
11 | DMI_DEV_TYPE_OTHER, | 11 | DMI_DEV_TYPE_OTHER, |
12 | DMI_DEV_TYPE_UNKNOWN, | 12 | DMI_DEV_TYPE_UNKNOWN, |
13 | DMI_DEV_TYPE_VIDEO, | 13 | DMI_DEV_TYPE_VIDEO, |
14 | DMI_DEV_TYPE_SCSI, | 14 | DMI_DEV_TYPE_SCSI, |
15 | DMI_DEV_TYPE_ETHERNET, | 15 | DMI_DEV_TYPE_ETHERNET, |
16 | DMI_DEV_TYPE_TOKENRING, | 16 | DMI_DEV_TYPE_TOKENRING, |
17 | DMI_DEV_TYPE_SOUND, | 17 | DMI_DEV_TYPE_SOUND, |
18 | DMI_DEV_TYPE_PATA, | 18 | DMI_DEV_TYPE_PATA, |
19 | DMI_DEV_TYPE_SATA, | 19 | DMI_DEV_TYPE_SATA, |
20 | DMI_DEV_TYPE_SAS, | 20 | DMI_DEV_TYPE_SAS, |
21 | DMI_DEV_TYPE_IPMI = -1, | 21 | DMI_DEV_TYPE_IPMI = -1, |
22 | DMI_DEV_TYPE_OEM_STRING = -2, | 22 | DMI_DEV_TYPE_OEM_STRING = -2, |
23 | DMI_DEV_TYPE_DEV_ONBOARD = -3, | ||
23 | }; | 24 | }; |
24 | 25 | ||
25 | struct dmi_header { | 26 | struct dmi_header { |
26 | u8 type; | 27 | u8 type; |
27 | u8 length; | 28 | u8 length; |
28 | u16 handle; | 29 | u16 handle; |
29 | }; | 30 | }; |
30 | 31 | ||
31 | struct dmi_device { | 32 | struct dmi_device { |
32 | struct list_head list; | 33 | struct list_head list; |
33 | int type; | 34 | int type; |
34 | const char *name; | 35 | const char *name; |
35 | void *device_data; /* Type specific data */ | 36 | void *device_data; /* Type specific data */ |
36 | }; | 37 | }; |
37 | 38 | ||
38 | #ifdef CONFIG_DMI | 39 | #ifdef CONFIG_DMI |
40 | |||
41 | struct dmi_dev_onboard { | ||
42 | struct dmi_device dev; | ||
43 | int instance; | ||
44 | int segment; | ||
45 | int bus; | ||
46 | int devfn; | ||
47 | }; | ||
39 | 48 | ||
40 | extern int dmi_check_system(const struct dmi_system_id *list); | 49 | extern int dmi_check_system(const struct dmi_system_id *list); |
41 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); | 50 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); |
42 | extern const char * dmi_get_system_info(int field); | 51 | extern const char * dmi_get_system_info(int field); |
43 | extern const struct dmi_device * dmi_find_device(int type, const char *name, | 52 | extern const struct dmi_device * dmi_find_device(int type, const char *name, |
44 | const struct dmi_device *from); | 53 | const struct dmi_device *from); |
45 | extern void dmi_scan_machine(void); | 54 | extern void dmi_scan_machine(void); |
46 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); | 55 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); |
47 | extern int dmi_name_in_vendors(const char *str); | 56 | extern int dmi_name_in_vendors(const char *str); |
48 | extern int dmi_name_in_serial(const char *str); | 57 | extern int dmi_name_in_serial(const char *str); |
49 | extern int dmi_available; | 58 | extern int dmi_available; |
50 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), | 59 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
51 | void *private_data); | 60 | void *private_data); |
52 | extern bool dmi_match(enum dmi_field f, const char *str); | 61 | extern bool dmi_match(enum dmi_field f, const char *str); |
53 | 62 | ||
54 | #else | 63 | #else |
55 | 64 | ||
56 | static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } | 65 | static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } |
57 | static inline const char * dmi_get_system_info(int field) { return NULL; } | 66 | static inline const char * dmi_get_system_info(int field) { return NULL; } |
58 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, | 67 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, |
59 | const struct dmi_device *from) { return NULL; } | 68 | const struct dmi_device *from) { return NULL; } |
60 | static inline void dmi_scan_machine(void) { return; } | 69 | static inline void dmi_scan_machine(void) { return; } |
61 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) | 70 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) |
62 | { | 71 | { |
63 | if (yearp) | 72 | if (yearp) |
64 | *yearp = 0; | 73 | *yearp = 0; |
65 | if (monthp) | 74 | if (monthp) |
66 | *monthp = 0; | 75 | *monthp = 0; |
67 | if (dayp) | 76 | if (dayp) |
68 | *dayp = 0; | 77 | *dayp = 0; |
69 | return false; | 78 | return false; |
70 | } | 79 | } |
71 | static inline int dmi_name_in_vendors(const char *s) { return 0; } | 80 | static inline int dmi_name_in_vendors(const char *s) { return 0; } |
72 | static inline int dmi_name_in_serial(const char *s) { return 0; } | 81 | static inline int dmi_name_in_serial(const char *s) { return 0; } |
73 | #define dmi_available 0 | 82 | #define dmi_available 0 |
74 | static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *), | 83 | static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
75 | void *private_data) { return -1; } | 84 | void *private_data) { return -1; } |
76 | static inline bool dmi_match(enum dmi_field f, const char *str) | 85 | static inline bool dmi_match(enum dmi_field f, const char *str) |
77 | { return false; } | 86 | { return false; } |
78 | static inline const struct dmi_system_id * | 87 | static inline const struct dmi_system_id * |
79 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } | 88 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } |
80 | 89 | ||
81 | #endif | 90 | #endif |
82 | 91 | ||
83 | #endif /* __DMI_H__ */ | 92 | #endif /* __DMI_H__ */ |
84 | 93 |