aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/access.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r--drivers/pci/access.c226
1 files changed, 151 insertions, 75 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 39bb96b413ef..381444794778 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
@@ -133,125 +166,145 @@ PCI_USER_WRITE_CONFIG(dword, u32)
133 166
134struct pci_vpd_pci22 { 167struct pci_vpd_pci22 {
135 struct pci_vpd base; 168 struct pci_vpd base;
136 spinlock_t lock; /* controls access to hardware and the flags */ 169 struct mutex lock;
137 u8 cap; 170 u16 flag;
138 bool busy; 171 bool busy;
139 bool flag; /* value of F bit to wait for */ 172 u8 cap;
140}; 173};
141 174
142/* Wait for last operation to complete */ 175/*
176 * Wait for last operation to complete.
177 * This code has to spin since there is no other notification from the PCI
178 * hardware. Since the VPD is often implemented by serial attachment to an
179 * EEPROM, it may take many milliseconds to complete.
180 */
143static int pci_vpd_pci22_wait(struct pci_dev *dev) 181static int pci_vpd_pci22_wait(struct pci_dev *dev)
144{ 182{
145 struct pci_vpd_pci22 *vpd = 183 struct pci_vpd_pci22 *vpd =
146 container_of(dev->vpd, struct pci_vpd_pci22, base); 184 container_of(dev->vpd, struct pci_vpd_pci22, base);
147 u16 flag, status; 185 unsigned long timeout = jiffies + HZ/20 + 2;
148 int wait; 186 u16 status;
149 int ret; 187 int ret;
150 188
151 if (!vpd->busy) 189 if (!vpd->busy)
152 return 0; 190 return 0;
153 191
154 flag = vpd->flag ? PCI_VPD_ADDR_F : 0;
155 wait = vpd->flag ? 10 : 1000; /* read: 100 us; write: 10 ms */
156 for (;;) { 192 for (;;) {
157 ret = pci_user_read_config_word(dev, 193 ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
158 vpd->cap + PCI_VPD_ADDR,
159 &status); 194 &status);
160 if (ret < 0) 195 if (ret)
161 return ret; 196 return ret;
162 if ((status & PCI_VPD_ADDR_F) == flag) { 197
198 if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
163 vpd->busy = false; 199 vpd->busy = false;
164 return 0; 200 return 0;
165 } 201 }
166 if (wait-- == 0) 202
203 if (time_after(jiffies, timeout))
167 return -ETIMEDOUT; 204 return -ETIMEDOUT;
168 udelay(10); 205 if (fatal_signal_pending(current))
206 return -EINTR;
207 if (!cond_resched())
208 udelay(10);
169 } 209 }
170} 210}
171 211
172static 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,
173 char *buf) 213 void *arg)
174{ 214{
175 struct pci_vpd_pci22 *vpd = 215 struct pci_vpd_pci22 *vpd =
176 container_of(dev->vpd, struct pci_vpd_pci22, base); 216 container_of(dev->vpd, struct pci_vpd_pci22, base);
177 u32 val;
178 int ret; 217 int ret;
179 int begin, end, i; 218 loff_t end = pos + count;
219 u8 *buf = arg;
180 220
181 if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) 221 if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
182 return -EINVAL; 222 return -EINVAL;
183 if (size == 0)
184 return 0;
185 223
186 spin_lock_irq(&vpd->lock); 224 if (mutex_lock_killable(&vpd->lock))
187 ret = pci_vpd_pci22_wait(dev); 225 return -EINTR;
188 if (ret < 0) 226
189 goto out;
190 ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
191 pos & ~3);
192 if (ret < 0)
193 goto out;
194 vpd->busy = true;
195 vpd->flag = 1;
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_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, 230
200 &val); 231 while (pos < end) {
201out: 232 u32 val;
202 spin_unlock_irq(&vpd->lock); 233 unsigned int i, skip;
203 if (ret < 0) 234
204 return ret; 235 ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
205 236 pos & ~3);
206 /* Convert to bytes */ 237 if (ret < 0)
207 begin = pos & 3; 238 break;
208 end = min(4, begin + size); 239 vpd->busy = true;
209 for (i = 0; i < end; ++i) { 240 vpd->flag = PCI_VPD_ADDR_F;
210 if (i >= begin) 241 ret = pci_vpd_pci22_wait(dev);
211 *buf++ = val; 242 if (ret < 0)
212 val >>= 8; 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 }
213 } 258 }
214 return end - begin; 259out:
260 mutex_unlock(&vpd->lock);
261 return ret ? ret : count;
215} 262}
216 263
217static 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,
218 const char *buf) 265 const void *arg)
219{ 266{
220 struct pci_vpd_pci22 *vpd = 267 struct pci_vpd_pci22 *vpd =
221 container_of(dev->vpd, struct pci_vpd_pci22, base); 268 container_of(dev->vpd, struct pci_vpd_pci22, base);
222 u32 val; 269 const u8 *buf = arg;
223 int ret; 270 loff_t end = pos + count;
271 int ret = 0;
224 272
225 if (pos < 0 || pos > vpd->base.len || pos & 3 || 273 if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
226 size > vpd->base.len - pos || size < 4)
227 return -EINVAL; 274 return -EINVAL;
228 275
229 val = (u8) *buf++; 276 if (mutex_lock_killable(&vpd->lock))
230 val |= ((u8) *buf++) << 8; 277 return -EINTR;
231 val |= ((u8) *buf++) << 16;
232 val |= ((u32)(u8) *buf++) << 24;
233 278
234 spin_lock_irq(&vpd->lock);
235 ret = pci_vpd_pci22_wait(dev); 279 ret = pci_vpd_pci22_wait(dev);
236 if (ret < 0) 280 if (ret < 0)
237 goto out; 281 goto out;
238 ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA,
239 val);
240 if (ret < 0)
241 goto out;
242 ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
243 pos | PCI_VPD_ADDR_F);
244 if (ret < 0)
245 goto out;
246 vpd->busy = true;
247 vpd->flag = 0;
248 ret = pci_vpd_pci22_wait(dev);
249out:
250 spin_unlock_irq(&vpd->lock);
251 if (ret < 0)
252 return ret;
253 282
254 return 4; 283 while (pos < end) {
284 u32 val;
285
286 val = *buf++;
287 val |= *buf++ << 8;
288 val |= *buf++ << 16;
289 val |= *buf++ << 24;
290
291 ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val);
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 }
305out:
306 mutex_unlock(&vpd->lock);
307 return ret ? ret : count;
255} 308}
256 309
257static void pci_vpd_pci22_release(struct pci_dev *dev) 310static void pci_vpd_pci22_release(struct pci_dev *dev)
@@ -259,7 +312,7 @@ static void pci_vpd_pci22_release(struct pci_dev *dev)
259 kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); 312 kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
260} 313}
261 314
262static struct pci_vpd_ops pci_vpd_pci22_ops = { 315static const struct pci_vpd_ops pci_vpd_pci22_ops = {
263 .read = pci_vpd_pci22_read, 316 .read = pci_vpd_pci22_read,
264 .write = pci_vpd_pci22_write, 317 .write = pci_vpd_pci22_write,
265 .release = pci_vpd_pci22_release, 318 .release = pci_vpd_pci22_release,
@@ -279,7 +332,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
279 332
280 vpd->base.len = PCI_VPD_PCI22_SIZE; 333 vpd->base.len = PCI_VPD_PCI22_SIZE;
281 vpd->base.ops = &pci_vpd_pci22_ops; 334 vpd->base.ops = &pci_vpd_pci22_ops;
282 spin_lock_init(&vpd->lock); 335 mutex_init(&vpd->lock);
283 vpd->cap = cap; 336 vpd->cap = cap;
284 vpd->busy = false; 337 vpd->busy = false;
285 dev->vpd = &vpd->base; 338 dev->vpd = &vpd->base;
@@ -287,6 +340,29 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
287} 340}
288 341
289/** 342/**
343 * pci_vpd_truncate - Set available Vital Product Data size
344 * @dev: pci device struct
345 * @size: available memory in bytes
346 *
347 * Adjust size of available VPD area.
348 */
349int pci_vpd_truncate(struct pci_dev *dev, size_t size)
350{
351 if (!dev->vpd)
352 return -EINVAL;
353
354 /* limited by the access method */
355 if (size > dev->vpd->len)
356 return -EINVAL;
357
358 dev->vpd->len = size;
359 dev->vpd->attr->size = size;
360
361 return 0;
362}
363EXPORT_SYMBOL(pci_vpd_truncate);
364
365/**
290 * pci_block_user_cfg_access - Block userspace PCI config reads/writes 366 * pci_block_user_cfg_access - Block userspace PCI config reads/writes
291 * @dev: pci device struct 367 * @dev: pci device struct
292 * 368 *