diff options
author | Trent Piepho <xyzzy@speakeasy.org> | 2008-11-30 20:10:12 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-01-07 14:12:58 -0500 |
commit | 92425a405ea482209b43093a5e35be7de02acf18 (patch) | |
tree | 0cf7d494d8a743350f29a827a272287a7d99b5d1 /drivers/pci/pci-sysfs.c | |
parent | 1684f5ddd4c0c754f52c78eaa2c5c69ad09fb18c (diff) |
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d5cdccf27a69..d2f1354fd189 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -58,13 +58,14 @@ static ssize_t broken_parity_status_store(struct device *dev, | |||
58 | const char *buf, size_t count) | 58 | const char *buf, size_t count) |
59 | { | 59 | { |
60 | struct pci_dev *pdev = to_pci_dev(dev); | 60 | struct pci_dev *pdev = to_pci_dev(dev); |
61 | ssize_t consumed = -EINVAL; | 61 | unsigned long val; |
62 | 62 | ||
63 | if ((count > 0) && (*buf == '0' || *buf == '1')) { | 63 | if (strict_strtoul(buf, 0, &val) < 0) |
64 | pdev->broken_parity_status = *buf == '1' ? 1 : 0; | 64 | return -EINVAL; |
65 | consumed = count; | 65 | |
66 | } | 66 | pdev->broken_parity_status = !!val; |
67 | return consumed; | 67 | |
68 | return count; | ||
68 | } | 69 | } |
69 | 70 | ||
70 | static ssize_t local_cpus_show(struct device *dev, | 71 | static ssize_t local_cpus_show(struct device *dev, |
@@ -133,19 +134,23 @@ static ssize_t is_enabled_store(struct device *dev, | |||
133 | struct device_attribute *attr, const char *buf, | 134 | struct device_attribute *attr, const char *buf, |
134 | size_t count) | 135 | size_t count) |
135 | { | 136 | { |
136 | ssize_t result = -EINVAL; | ||
137 | struct pci_dev *pdev = to_pci_dev(dev); | 137 | struct pci_dev *pdev = to_pci_dev(dev); |
138 | unsigned long val; | ||
139 | ssize_t result = strict_strtoul(buf, 0, &val); | ||
140 | |||
141 | if (result < 0) | ||
142 | return result; | ||
138 | 143 | ||
139 | /* this can crash the machine when done on the "wrong" device */ | 144 | /* this can crash the machine when done on the "wrong" device */ |
140 | if (!capable(CAP_SYS_ADMIN)) | 145 | if (!capable(CAP_SYS_ADMIN)) |
141 | return count; | 146 | return -EPERM; |
142 | 147 | ||
143 | if (*buf == '0') { | 148 | if (!val) { |
144 | if (atomic_read(&pdev->enable_cnt) != 0) | 149 | if (atomic_read(&pdev->enable_cnt) != 0) |
145 | pci_disable_device(pdev); | 150 | pci_disable_device(pdev); |
146 | else | 151 | else |
147 | result = -EIO; | 152 | result = -EIO; |
148 | } else if (*buf == '1') | 153 | } else |
149 | result = pci_enable_device(pdev); | 154 | result = pci_enable_device(pdev); |
150 | 155 | ||
151 | return result < 0 ? result : count; | 156 | return result < 0 ? result : count; |
@@ -185,25 +190,28 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, | |||
185 | const char *buf, size_t count) | 190 | const char *buf, size_t count) |
186 | { | 191 | { |
187 | struct pci_dev *pdev = to_pci_dev(dev); | 192 | struct pci_dev *pdev = to_pci_dev(dev); |
193 | unsigned long val; | ||
194 | |||
195 | if (strict_strtoul(buf, 0, &val) < 0) | ||
196 | return -EINVAL; | ||
188 | 197 | ||
189 | /* bad things may happen if the no_msi flag is changed | 198 | /* bad things may happen if the no_msi flag is changed |
190 | * while some drivers are loaded */ | 199 | * while some drivers are loaded */ |
191 | if (!capable(CAP_SYS_ADMIN)) | 200 | if (!capable(CAP_SYS_ADMIN)) |
192 | return count; | 201 | return -EPERM; |
193 | 202 | ||
203 | /* Maybe pci devices without subordinate busses shouldn't even have this | ||
204 | * attribute in the first place? */ | ||
194 | if (!pdev->subordinate) | 205 | if (!pdev->subordinate) |
195 | return count; | 206 | return count; |
196 | 207 | ||
197 | if (*buf == '0') { | 208 | /* Is the flag going to change, or keep the value it already had? */ |
198 | pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; | 209 | if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^ |
199 | dev_warn(&pdev->dev, "forced subordinate bus to not support MSI," | 210 | !!val) { |
200 | " bad things could happen.\n"); | 211 | pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI; |
201 | } | ||
202 | 212 | ||
203 | if (*buf == '1') { | 213 | dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI," |
204 | pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI; | 214 | " bad things could happen\n", val ? "" : " not"); |
205 | dev_warn(&pdev->dev, "forced subordinate bus to support MSI," | ||
206 | " bad things could happen.\n"); | ||
207 | } | 215 | } |
208 | 216 | ||
209 | return count; | 217 | return count; |