aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
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:16 -0500
commit1120f8b8169fb2cb51219d326892d963e762edb6 (patch)
tree8ee86fe0b3dffa0ebff4406f1470092c4df84f25 /drivers/pci
parent904d6a303361a85bfa4c8181ef62a24edb8da0a8 (diff)
PCI: handle long delays in VPD access
Accessing the VPD area can take a long time. The existing VPD access code fails consistently on my hardware. There are comments in the SysKonnect vendor driver that it can take up to 13ms per word. Change the access routines to: * use a mutex rather than spinning with IRQ's disabled and lock held * have a much longer timeout * call cond_resched while spinning Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Reviewed-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/access.c55
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
134struct pci_vpd_pci22 { 134struct 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 */
143static int pci_vpd_pci22_wait(struct pci_dev *dev) 148static 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);
201out: 211out:
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);
249out: 260out:
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;