aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/access.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2008-12-18 12:17:16 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-01-07 14:13:17 -0500
commit287d19ce2e67c15e79a187b3bdcbbea1a0a51a7d (patch)
tree128d9c67557a4fe5e5e910b8ca2d50aedee31b7c /drivers/pci/access.c
parent1120f8b8169fb2cb51219d326892d963e762edb6 (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.c156
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);
66EXPORT_SYMBOL(pci_bus_write_config_word); 66EXPORT_SYMBOL(pci_bus_write_config_word);
67EXPORT_SYMBOL(pci_bus_write_config_dword); 67EXPORT_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 */
78ssize_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}
84EXPORT_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 */
94ssize_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}
100EXPORT_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
179static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, 212static 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 }
211out: 259out:
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
227static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, 264static 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 }
260out: 305out:
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
268static void pci_vpd_pci22_release(struct pci_dev *dev) 310static 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
273static struct pci_vpd_ops pci_vpd_pci22_ops = { 315static 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,