diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/access.c | 55 |
1 files changed, 33 insertions, 22 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 39bb96b413ef..98ddba94b5b9 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -133,39 +133,46 @@ PCI_USER_WRITE_CONFIG(dword, u32) | |||
133 | 133 | ||
134 | struct pci_vpd_pci22 { | 134 | struct pci_vpd_pci22 { |
135 | struct pci_vpd base; | 135 | struct pci_vpd base; |
136 | spinlock_t lock; /* controls access to hardware and the flags */ | 136 | struct mutex lock; |
137 | u8 cap; | 137 | u16 flag; |
138 | bool busy; | 138 | bool busy; |
139 | bool flag; /* value of F bit to wait for */ | 139 | u8 cap; |
140 | }; | 140 | }; |
141 | 141 | ||
142 | /* Wait for last operation to complete */ | 142 | /* |
143 | * Wait for last operation to complete. | ||
144 | * This code has to spin since there is no other notification from the PCI | ||
145 | * hardware. Since the VPD is often implemented by serial attachment to an | ||
146 | * EEPROM, it may take many milliseconds to complete. | ||
147 | */ | ||
143 | static int pci_vpd_pci22_wait(struct pci_dev *dev) | 148 | static int pci_vpd_pci22_wait(struct pci_dev *dev) |
144 | { | 149 | { |
145 | struct pci_vpd_pci22 *vpd = | 150 | struct pci_vpd_pci22 *vpd = |
146 | container_of(dev->vpd, struct pci_vpd_pci22, base); | 151 | container_of(dev->vpd, struct pci_vpd_pci22, base); |
147 | u16 flag, status; | 152 | unsigned long timeout = jiffies + HZ/20 + 2; |
148 | int wait; | 153 | u16 status; |
149 | int ret; | 154 | int ret; |
150 | 155 | ||
151 | if (!vpd->busy) | 156 | if (!vpd->busy) |
152 | return 0; | 157 | return 0; |
153 | 158 | ||
154 | flag = vpd->flag ? PCI_VPD_ADDR_F : 0; | ||
155 | wait = vpd->flag ? 10 : 1000; /* read: 100 us; write: 10 ms */ | ||
156 | for (;;) { | 159 | for (;;) { |
157 | ret = pci_user_read_config_word(dev, | 160 | ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR, |
158 | vpd->cap + PCI_VPD_ADDR, | ||
159 | &status); | 161 | &status); |
160 | if (ret < 0) | 162 | if (ret) |
161 | return ret; | 163 | return ret; |
162 | if ((status & PCI_VPD_ADDR_F) == flag) { | 164 | |
165 | if ((status & PCI_VPD_ADDR_F) == vpd->flag) { | ||
163 | vpd->busy = false; | 166 | vpd->busy = false; |
164 | return 0; | 167 | return 0; |
165 | } | 168 | } |
166 | if (wait-- == 0) | 169 | |
170 | if (time_after(jiffies, timeout)) | ||
167 | return -ETIMEDOUT; | 171 | return -ETIMEDOUT; |
168 | udelay(10); | 172 | if (fatal_signal_pending(current)) |
173 | return -EINTR; | ||
174 | if (!cond_resched()) | ||
175 | udelay(10); | ||
169 | } | 176 | } |
170 | } | 177 | } |
171 | 178 | ||
@@ -175,7 +182,7 @@ static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, | |||
175 | struct pci_vpd_pci22 *vpd = | 182 | struct pci_vpd_pci22 *vpd = |
176 | container_of(dev->vpd, struct pci_vpd_pci22, base); | 183 | container_of(dev->vpd, struct pci_vpd_pci22, base); |
177 | u32 val; | 184 | u32 val; |
178 | int ret; | 185 | int ret = 0; |
179 | int begin, end, i; | 186 | int begin, end, i; |
180 | 187 | ||
181 | if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) | 188 | if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) |
@@ -183,7 +190,9 @@ static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, | |||
183 | if (size == 0) | 190 | if (size == 0) |
184 | return 0; | 191 | return 0; |
185 | 192 | ||
186 | spin_lock_irq(&vpd->lock); | 193 | if (mutex_lock_killable(&vpd->lock)) |
194 | return -EINTR; | ||
195 | |||
187 | ret = pci_vpd_pci22_wait(dev); | 196 | ret = pci_vpd_pci22_wait(dev); |
188 | if (ret < 0) | 197 | if (ret < 0) |
189 | goto out; | 198 | goto out; |
@@ -191,15 +200,16 @@ static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, | |||
191 | pos & ~3); | 200 | pos & ~3); |
192 | if (ret < 0) | 201 | if (ret < 0) |
193 | goto out; | 202 | goto out; |
203 | |||
194 | vpd->busy = true; | 204 | vpd->busy = true; |
195 | vpd->flag = 1; | 205 | vpd->flag = PCI_VPD_ADDR_F; |
196 | ret = pci_vpd_pci22_wait(dev); | 206 | ret = pci_vpd_pci22_wait(dev); |
197 | if (ret < 0) | 207 | if (ret < 0) |
198 | goto out; | 208 | goto out; |
199 | ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, | 209 | ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, |
200 | &val); | 210 | &val); |
201 | out: | 211 | out: |
202 | spin_unlock_irq(&vpd->lock); | 212 | mutex_unlock(&vpd->lock); |
203 | if (ret < 0) | 213 | if (ret < 0) |
204 | return ret; | 214 | return ret; |
205 | 215 | ||
@@ -220,7 +230,7 @@ static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, | |||
220 | struct pci_vpd_pci22 *vpd = | 230 | struct pci_vpd_pci22 *vpd = |
221 | container_of(dev->vpd, struct pci_vpd_pci22, base); | 231 | container_of(dev->vpd, struct pci_vpd_pci22, base); |
222 | u32 val; | 232 | u32 val; |
223 | int ret; | 233 | int ret = 0; |
224 | 234 | ||
225 | if (pos < 0 || pos > vpd->base.len || pos & 3 || | 235 | if (pos < 0 || pos > vpd->base.len || pos & 3 || |
226 | size > vpd->base.len - pos || size < 4) | 236 | size > vpd->base.len - pos || size < 4) |
@@ -231,7 +241,8 @@ static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, | |||
231 | val |= ((u8) *buf++) << 16; | 241 | val |= ((u8) *buf++) << 16; |
232 | val |= ((u32)(u8) *buf++) << 24; | 242 | val |= ((u32)(u8) *buf++) << 24; |
233 | 243 | ||
234 | spin_lock_irq(&vpd->lock); | 244 | if (mutex_lock_killable(&vpd->lock)) |
245 | return -EINTR; | ||
235 | ret = pci_vpd_pci22_wait(dev); | 246 | ret = pci_vpd_pci22_wait(dev); |
236 | if (ret < 0) | 247 | if (ret < 0) |
237 | goto out; | 248 | goto out; |
@@ -247,7 +258,7 @@ static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, | |||
247 | vpd->flag = 0; | 258 | vpd->flag = 0; |
248 | ret = pci_vpd_pci22_wait(dev); | 259 | ret = pci_vpd_pci22_wait(dev); |
249 | out: | 260 | out: |
250 | spin_unlock_irq(&vpd->lock); | 261 | mutex_unlock(&vpd->lock); |
251 | if (ret < 0) | 262 | if (ret < 0) |
252 | return ret; | 263 | return ret; |
253 | 264 | ||
@@ -279,7 +290,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev) | |||
279 | 290 | ||
280 | vpd->base.len = PCI_VPD_PCI22_SIZE; | 291 | vpd->base.len = PCI_VPD_PCI22_SIZE; |
281 | vpd->base.ops = &pci_vpd_pci22_ops; | 292 | vpd->base.ops = &pci_vpd_pci22_ops; |
282 | spin_lock_init(&vpd->lock); | 293 | mutex_init(&vpd->lock); |
283 | vpd->cap = cap; | 294 | vpd->cap = cap; |
284 | vpd->busy = false; | 295 | vpd->busy = false; |
285 | dev->vpd = &vpd->base; | 296 | dev->vpd = &vpd->base; |