Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Stephen Hemminger and committed by
Jesse Barnes
287d19ce 1120f8b8

+124 -100
+99 -57
drivers/pci/access.c
··· 66 66 EXPORT_SYMBOL(pci_bus_write_config_word); 67 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 103 * The following routines are to prevent the user from accessing PCI config 71 104 * space when it's unsafe to do so. Some devices require this during BIST and ··· 209 176 } 210 177 } 211 178 212 - static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, 213 - char *buf) 179 + static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, 180 + void *arg) 214 181 { 215 182 struct pci_vpd_pci22 *vpd = 216 183 container_of(dev->vpd, struct pci_vpd_pci22, base); 217 - u32 val; 218 - int ret = 0; 219 - int begin, end, i; 184 + int ret; 185 + loff_t end = pos + count; 186 + u8 *buf = arg; 220 187 221 - if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) 188 + if (pos < 0 || pos > vpd->base.len || end > vpd->base.len) 222 189 return -EINVAL; 223 - if (size == 0) 224 - return 0; 225 190 226 191 if (mutex_lock_killable(&vpd->lock)) 227 192 return -EINTR; ··· 227 196 ret = pci_vpd_pci22_wait(dev); 228 197 if (ret < 0) 229 198 goto out; 230 - ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, 231 - pos & ~3); 232 - if (ret < 0) 233 - goto out; 234 199 235 - vpd->busy = true; 236 - vpd->flag = PCI_VPD_ADDR_F; 237 - ret = pci_vpd_pci22_wait(dev); 238 - if (ret < 0) 239 - goto out; 240 - ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, 241 - &val); 200 + while (pos < end) { 201 + u32 val; 202 + unsigned int i, skip; 203 + 204 + ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, 205 + pos & ~3); 206 + if (ret < 0) 207 + break; 208 + vpd->busy = true; 209 + vpd->flag = PCI_VPD_ADDR_F; 210 + ret = pci_vpd_pci22_wait(dev); 211 + if (ret < 0) 212 + break; 213 + 214 + ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val); 215 + if (ret < 0) 216 + break; 217 + 218 + skip = pos & 3; 219 + for (i = 0; i < sizeof(u32); i++) { 220 + if (i >= skip) { 221 + *buf++ = val; 222 + if (++pos == end) 223 + break; 224 + } 225 + val >>= 8; 226 + } 227 + } 242 228 out: 243 229 mutex_unlock(&vpd->lock); 244 - if (ret < 0) 245 - return ret; 246 - 247 - /* Convert to bytes */ 248 - begin = pos & 3; 249 - end = min(4, begin + size); 250 - for (i = 0; i < end; ++i) { 251 - if (i >= begin) 252 - *buf++ = val; 253 - val >>= 8; 254 - } 255 - return end - begin; 230 + return ret ? ret : count; 256 231 } 257 232 258 - static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, 259 - const char *buf) 233 + static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count, 234 + const void *arg) 260 235 { 261 236 struct pci_vpd_pci22 *vpd = 262 237 container_of(dev->vpd, struct pci_vpd_pci22, base); 263 - u32 val; 238 + const u8 *buf = arg; 239 + loff_t end = pos + count; 264 240 int ret = 0; 265 241 266 - if (pos < 0 || pos > vpd->base.len || pos & 3 || 267 - size > vpd->base.len - pos || size < 4) 242 + if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len) 268 243 return -EINVAL; 269 - 270 - val = (u8) *buf++; 271 - val |= ((u8) *buf++) << 8; 272 - val |= ((u8) *buf++) << 16; 273 - val |= ((u32)(u8) *buf++) << 24; 274 244 275 245 if (mutex_lock_killable(&vpd->lock)) 276 246 return -EINTR; 247 + 277 248 ret = pci_vpd_pci22_wait(dev); 278 249 if (ret < 0) 279 250 goto out; 280 - ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, 281 - val); 282 - if (ret < 0) 283 - goto out; 284 - ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, 285 - pos | PCI_VPD_ADDR_F); 286 - if (ret < 0) 287 - goto out; 288 - vpd->busy = true; 289 - vpd->flag = 0; 290 - ret = pci_vpd_pci22_wait(dev); 251 + 252 + while (pos < end) { 253 + u32 val; 254 + 255 + val = *buf++; 256 + val |= *buf++ << 8; 257 + val |= *buf++ << 16; 258 + val |= *buf++ << 24; 259 + 260 + ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val); 261 + if (ret < 0) 262 + break; 263 + ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, 264 + pos | PCI_VPD_ADDR_F); 265 + if (ret < 0) 266 + break; 267 + 268 + vpd->busy = true; 269 + vpd->flag = 0; 270 + ret = pci_vpd_pci22_wait(dev); 271 + 272 + pos += sizeof(u32); 273 + } 291 274 out: 292 275 mutex_unlock(&vpd->lock); 293 - if (ret < 0) 294 - return ret; 295 - 296 - return 4; 276 + return ret ? ret : count; 297 277 } 298 278 299 279 static void pci_vpd_pci22_release(struct pci_dev *dev) ··· 312 270 kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); 313 271 } 314 272 315 - static struct pci_vpd_ops pci_vpd_pci22_ops = { 273 + static const struct pci_vpd_ops pci_vpd_pci22_ops = { 316 274 .read = pci_vpd_pci22_read, 317 275 .write = pci_vpd_pci22_write, 318 276 .release = pci_vpd_pci22_release,
+18 -40
drivers/pci/pci-sysfs.c
··· 371 371 } 372 372 373 373 static ssize_t 374 - pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, 375 - char *buf, loff_t off, size_t count) 376 - { 377 - struct pci_dev *dev = 378 - to_pci_dev(container_of(kobj, struct device, kobj)); 379 - int end; 380 - int ret; 381 - 382 - if (off > bin_attr->size) 383 - count = 0; 384 - else if (count > bin_attr->size - off) 385 - count = bin_attr->size - off; 386 - end = off + count; 387 - 388 - while (off < end) { 389 - ret = dev->vpd->ops->read(dev, off, end - off, buf); 390 - if (ret < 0) 391 - return ret; 392 - buf += ret; 393 - off += ret; 394 - } 395 - 396 - return count; 397 - } 398 - 399 - static ssize_t 400 - pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, 374 + read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, 401 375 char *buf, loff_t off, size_t count) 402 376 { 403 377 struct pci_dev *dev = 404 378 to_pci_dev(container_of(kobj, struct device, kobj)); 405 - int end; 406 - int ret; 407 379 408 380 if (off > bin_attr->size) 409 381 count = 0; 410 382 else if (count > bin_attr->size - off) 411 383 count = bin_attr->size - off; 412 - end = off + count; 413 384 414 - while (off < end) { 415 - ret = dev->vpd->ops->write(dev, off, end - off, buf); 416 - if (ret < 0) 417 - return ret; 418 - buf += ret; 419 - off += ret; 420 - } 385 + return pci_read_vpd(dev, off, count, buf); 386 + } 421 387 422 - return count; 388 + static ssize_t 389 + write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, 390 + char *buf, loff_t off, size_t count) 391 + { 392 + struct pci_dev *dev = 393 + to_pci_dev(container_of(kobj, struct device, kobj)); 394 + 395 + if (off > bin_attr->size) 396 + count = 0; 397 + else if (count > bin_attr->size - off) 398 + count = bin_attr->size - off; 399 + 400 + return pci_write_vpd(dev, off, count, buf); 423 401 } 424 402 425 403 #ifdef HAVE_PCI_LEGACY ··· 823 845 attr->size = dev->vpd->len; 824 846 attr->attr.name = "vpd"; 825 847 attr->attr.mode = S_IRUSR | S_IWUSR; 826 - attr->read = pci_read_vpd; 827 - attr->write = pci_write_vpd; 848 + attr->read = read_vpd_attr; 849 + attr->write = write_vpd_attr; 828 850 retval = sysfs_create_bin_file(&dev->dev.kobj, attr); 829 851 if (retval) { 830 852 kfree(dev->vpd->attr);
+3 -3
drivers/pci/pci.h
··· 56 56 extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); 57 57 58 58 struct pci_vpd_ops { 59 - int (*read)(struct pci_dev *dev, int pos, int size, char *buf); 60 - int (*write)(struct pci_dev *dev, int pos, int size, const char *buf); 59 + ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); 60 + ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); 61 61 void (*release)(struct pci_dev *dev); 62 62 }; 63 63 64 64 struct pci_vpd { 65 65 unsigned int len; 66 - struct pci_vpd_ops *ops; 66 + const struct pci_vpd_ops *ops; 67 67 struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ 68 68 }; 69 69
+4
include/linux/pci.h
··· 687 687 /* Functions for PCI Hotplug drivers to use */ 688 688 int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); 689 689 690 + /* Vital product data routines */ 691 + ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); 692 + ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); 693 + 690 694 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ 691 695 void pci_bus_assign_resources(struct pci_bus *bus); 692 696 void pci_bus_size_bridges(struct pci_bus *bus);