diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2008-12-18 12:17:16 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-01-07 14:13:17 -0500 |
commit | 287d19ce2e67c15e79a187b3bdcbbea1a0a51a7d (patch) | |
tree | 128d9c67557a4fe5e5e910b8ca2d50aedee31b7c /drivers/pci/access.c | |
parent | 1120f8b8169fb2cb51219d326892d963e762edb6 (diff) |
PCI: revise VPD access interface
Change PCI VPD API which was only used by sysfs to something usable
in drivers.
* move iteration over multiple words to the low level
* use conventional types for arguments
* add exportable wrapper
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r-- | drivers/pci/access.c | 156 |
1 files changed, 99 insertions, 57 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 98ddba94b5b9..86ec4ad44bcd 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -66,6 +66,39 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); | |||
66 | EXPORT_SYMBOL(pci_bus_write_config_word); | 66 | EXPORT_SYMBOL(pci_bus_write_config_word); |
67 | EXPORT_SYMBOL(pci_bus_write_config_dword); | 67 | EXPORT_SYMBOL(pci_bus_write_config_dword); |
68 | 68 | ||
69 | |||
70 | /** | ||
71 | * pci_read_vpd - Read one entry from Vital Product Data | ||
72 | * @dev: pci device struct | ||
73 | * @pos: offset in vpd space | ||
74 | * @count: number of bytes to read | ||
75 | * @buf: pointer to where to store result | ||
76 | * | ||
77 | */ | ||
78 | ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf) | ||
79 | { | ||
80 | if (!dev->vpd || !dev->vpd->ops) | ||
81 | return -ENODEV; | ||
82 | return dev->vpd->ops->read(dev, pos, count, buf); | ||
83 | } | ||
84 | EXPORT_SYMBOL(pci_read_vpd); | ||
85 | |||
86 | /** | ||
87 | * pci_write_vpd - Write entry to Vital Product Data | ||
88 | * @dev: pci device struct | ||
89 | * @pos: offset in vpd space | ||
90 | * @count: number of bytes to read | ||
91 | * @val: value to write | ||
92 | * | ||
93 | */ | ||
94 | ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf) | ||
95 | { | ||
96 | if (!dev->vpd || !dev->vpd->ops) | ||
97 | return -ENODEV; | ||
98 | return dev->vpd->ops->write(dev, pos, count, buf); | ||
99 | } | ||
100 | EXPORT_SYMBOL(pci_write_vpd); | ||
101 | |||
69 | /* | 102 | /* |
70 | * The following routines are to prevent the user from accessing PCI config | 103 | * The following routines are to prevent the user from accessing PCI config |
71 | * space when it's unsafe to do so. Some devices require this during BIST and | 104 | * space when it's unsafe to do so. Some devices require this during BIST and |
@@ -176,19 +209,17 @@ static int pci_vpd_pci22_wait(struct pci_dev *dev) | |||
176 | } | 209 | } |
177 | } | 210 | } |
178 | 211 | ||
179 | static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, | 212 | static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, |
180 | char *buf) | 213 | void *arg) |
181 | { | 214 | { |
182 | struct pci_vpd_pci22 *vpd = | 215 | struct pci_vpd_pci22 *vpd = |
183 | container_of(dev->vpd, struct pci_vpd_pci22, base); | 216 | container_of(dev->vpd, struct pci_vpd_pci22, base); |
184 | u32 val; | 217 | int ret; |
185 | int ret = 0; | 218 | loff_t end = pos + count; |
186 | int begin, end, i; | 219 | u8 *buf = arg; |
187 | 220 | ||
188 | if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) | 221 | if (pos < 0 || pos > vpd->base.len || end > vpd->base.len) |
189 | return -EINVAL; | 222 | return -EINVAL; |
190 | if (size == 0) | ||
191 | return 0; | ||
192 | 223 | ||
193 | if (mutex_lock_killable(&vpd->lock)) | 224 | if (mutex_lock_killable(&vpd->lock)) |
194 | return -EINTR; | 225 | return -EINTR; |
@@ -196,73 +227,84 @@ static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, | |||
196 | ret = pci_vpd_pci22_wait(dev); | 227 | ret = pci_vpd_pci22_wait(dev); |
197 | if (ret < 0) | 228 | if (ret < 0) |
198 | goto out; | 229 | goto out; |
199 | ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, | ||
200 | pos & ~3); | ||
201 | if (ret < 0) | ||
202 | goto out; | ||
203 | 230 | ||
204 | vpd->busy = true; | 231 | while (pos < end) { |
205 | vpd->flag = PCI_VPD_ADDR_F; | 232 | u32 val; |
206 | ret = pci_vpd_pci22_wait(dev); | 233 | unsigned int i, skip; |
207 | if (ret < 0) | 234 | |
208 | goto out; | 235 | ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, |
209 | ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, | 236 | pos & ~3); |
210 | &val); | 237 | if (ret < 0) |
238 | break; | ||
239 | vpd->busy = true; | ||
240 | vpd->flag = PCI_VPD_ADDR_F; | ||
241 | ret = pci_vpd_pci22_wait(dev); | ||
242 | if (ret < 0) | ||
243 | break; | ||
244 | |||
245 | ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val); | ||
246 | if (ret < 0) | ||
247 | break; | ||
248 | |||
249 | skip = pos & 3; | ||
250 | for (i = 0; i < sizeof(u32); i++) { | ||
251 | if (i >= skip) { | ||
252 | *buf++ = val; | ||
253 | if (++pos == end) | ||
254 | break; | ||
255 | } | ||
256 | val >>= 8; | ||
257 | } | ||
258 | } | ||
211 | out: | 259 | out: |
212 | mutex_unlock(&vpd->lock); | 260 | mutex_unlock(&vpd->lock); |
213 | if (ret < 0) | 261 | return ret ? ret : count; |
214 | return ret; | ||
215 | |||
216 | /* Convert to bytes */ | ||
217 | begin = pos & 3; | ||
218 | end = min(4, begin + size); | ||
219 | for (i = 0; i < end; ++i) { | ||
220 | if (i >= begin) | ||
221 | *buf++ = val; | ||
222 | val >>= 8; | ||
223 | } | ||
224 | return end - begin; | ||
225 | } | 262 | } |
226 | 263 | ||
227 | static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, | 264 | static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count, |
228 | const char *buf) | 265 | const void *arg) |
229 | { | 266 | { |
230 | struct pci_vpd_pci22 *vpd = | 267 | struct pci_vpd_pci22 *vpd = |
231 | container_of(dev->vpd, struct pci_vpd_pci22, base); | 268 | container_of(dev->vpd, struct pci_vpd_pci22, base); |
232 | u32 val; | 269 | const u8 *buf = arg; |
270 | loff_t end = pos + count; | ||
233 | int ret = 0; | 271 | int ret = 0; |
234 | 272 | ||
235 | if (pos < 0 || pos > vpd->base.len || pos & 3 || | 273 | if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len) |
236 | size > vpd->base.len - pos || size < 4) | ||
237 | return -EINVAL; | 274 | return -EINVAL; |
238 | 275 | ||
239 | val = (u8) *buf++; | ||
240 | val |= ((u8) *buf++) << 8; | ||
241 | val |= ((u8) *buf++) << 16; | ||
242 | val |= ((u32)(u8) *buf++) << 24; | ||
243 | |||
244 | if (mutex_lock_killable(&vpd->lock)) | 276 | if (mutex_lock_killable(&vpd->lock)) |
245 | return -EINTR; | 277 | return -EINTR; |
278 | |||
246 | ret = pci_vpd_pci22_wait(dev); | 279 | ret = pci_vpd_pci22_wait(dev); |
247 | if (ret < 0) | 280 | if (ret < 0) |
248 | goto out; | 281 | goto out; |
249 | ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, | 282 | |
250 | val); | 283 | while (pos < end) { |
251 | if (ret < 0) | 284 | u32 val; |
252 | goto out; | 285 | |
253 | ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, | 286 | val = *buf++; |
254 | pos | PCI_VPD_ADDR_F); | 287 | val |= *buf++ << 8; |
255 | if (ret < 0) | 288 | val |= *buf++ << 16; |
256 | goto out; | 289 | val |= *buf++ << 24; |
257 | vpd->busy = true; | 290 | |
258 | vpd->flag = 0; | 291 | ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val); |
259 | ret = pci_vpd_pci22_wait(dev); | 292 | if (ret < 0) |
293 | break; | ||
294 | ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, | ||
295 | pos | PCI_VPD_ADDR_F); | ||
296 | if (ret < 0) | ||
297 | break; | ||
298 | |||
299 | vpd->busy = true; | ||
300 | vpd->flag = 0; | ||
301 | ret = pci_vpd_pci22_wait(dev); | ||
302 | |||
303 | pos += sizeof(u32); | ||
304 | } | ||
260 | out: | 305 | out: |
261 | mutex_unlock(&vpd->lock); | 306 | mutex_unlock(&vpd->lock); |
262 | if (ret < 0) | 307 | return ret ? ret : count; |
263 | return ret; | ||
264 | |||
265 | return 4; | ||
266 | } | 308 | } |
267 | 309 | ||
268 | static void pci_vpd_pci22_release(struct pci_dev *dev) | 310 | static void pci_vpd_pci22_release(struct pci_dev *dev) |
@@ -270,7 +312,7 @@ static void pci_vpd_pci22_release(struct pci_dev *dev) | |||
270 | kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); | 312 | kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); |
271 | } | 313 | } |
272 | 314 | ||
273 | static struct pci_vpd_ops pci_vpd_pci22_ops = { | 315 | static const struct pci_vpd_ops pci_vpd_pci22_ops = { |
274 | .read = pci_vpd_pci22_read, | 316 | .read = pci_vpd_pci22_read, |
275 | .write = pci_vpd_pci22_write, | 317 | .write = pci_vpd_pci22_write, |
276 | .release = pci_vpd_pci22_release, | 318 | .release = pci_vpd_pci22_release, |