diff options
Diffstat (limited to 'drivers/net/wireless/orinoco_plx.c')
-rw-r--r-- | drivers/net/wireless/orinoco_plx.c | 259 |
1 files changed, 89 insertions, 170 deletions
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 3fe7a2f37896..c00388ec9460 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c | |||
@@ -33,7 +33,7 @@ | |||
33 | 33 | ||
34 | * Caution: this is experimental and probably buggy. For success and | 34 | * Caution: this is experimental and probably buggy. For success and |
35 | * failure reports for different cards and adaptors, see | 35 | * failure reports for different cards and adaptors, see |
36 | * orinoco_plx_pci_id_table near the end of the file. If you have a | 36 | * orinoco_plx_id_table near the end of the file. If you have a |
37 | * card we don't have the PCI id for, and looks like it should work, | 37 | * card we don't have the PCI id for, and looks like it should work, |
38 | * drop me mail with the id and "it works"/"it doesn't work". | 38 | * drop me mail with the id and "it works"/"it doesn't work". |
39 | * | 39 | * |
@@ -125,6 +125,7 @@ | |||
125 | #include <pcmcia/cisreg.h> | 125 | #include <pcmcia/cisreg.h> |
126 | 126 | ||
127 | #include "orinoco.h" | 127 | #include "orinoco.h" |
128 | #include "orinoco_pci.h" | ||
128 | 129 | ||
129 | #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ | 130 | #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ |
130 | #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ | 131 | #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ |
@@ -134,30 +135,20 @@ | |||
134 | #define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ | 135 | #define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ |
135 | #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ | 136 | #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ |
136 | 137 | ||
137 | static const u8 cis_magic[] = { | ||
138 | 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 | ||
139 | }; | ||
140 | |||
141 | /* Orinoco PLX specific data */ | ||
142 | struct orinoco_plx_card { | ||
143 | void __iomem *attr_mem; | ||
144 | }; | ||
145 | |||
146 | /* | 138 | /* |
147 | * Do a soft reset of the card using the Configuration Option Register | 139 | * Do a soft reset of the card using the Configuration Option Register |
148 | */ | 140 | */ |
149 | static int orinoco_plx_cor_reset(struct orinoco_private *priv) | 141 | static int orinoco_plx_cor_reset(struct orinoco_private *priv) |
150 | { | 142 | { |
151 | hermes_t *hw = &priv->hw; | 143 | hermes_t *hw = &priv->hw; |
152 | struct orinoco_plx_card *card = priv->card; | 144 | struct orinoco_pci_card *card = priv->card; |
153 | u8 __iomem *attr_mem = card->attr_mem; | ||
154 | unsigned long timeout; | 145 | unsigned long timeout; |
155 | u16 reg; | 146 | u16 reg; |
156 | 147 | ||
157 | writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET); | 148 | iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); |
158 | mdelay(1); | 149 | mdelay(1); |
159 | 150 | ||
160 | writeb(COR_VALUE, attr_mem + COR_OFFSET); | 151 | iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); |
161 | mdelay(1); | 152 | mdelay(1); |
162 | 153 | ||
163 | /* Just in case, wait more until the card is no longer busy */ | 154 | /* Just in case, wait more until the card is no longer busy */ |
@@ -168,7 +159,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv) | |||
168 | reg = hermes_read_regn(hw, CMD); | 159 | reg = hermes_read_regn(hw, CMD); |
169 | } | 160 | } |
170 | 161 | ||
171 | /* Did we timeout ? */ | 162 | /* Still busy? */ |
172 | if (reg & HERMES_CMD_BUSY) { | 163 | if (reg & HERMES_CMD_BUSY) { |
173 | printk(KERN_ERR PFX "Busy timeout\n"); | 164 | printk(KERN_ERR PFX "Busy timeout\n"); |
174 | return -ETIMEDOUT; | 165 | return -ETIMEDOUT; |
@@ -177,20 +168,55 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv) | |||
177 | return 0; | 168 | return 0; |
178 | } | 169 | } |
179 | 170 | ||
171 | static int orinoco_plx_hw_init(struct orinoco_pci_card *card) | ||
172 | { | ||
173 | int i; | ||
174 | u32 csr_reg; | ||
175 | static const u8 cis_magic[] = { | ||
176 | 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 | ||
177 | }; | ||
178 | |||
179 | printk(KERN_DEBUG PFX "CIS: "); | ||
180 | for (i = 0; i < 16; i++) { | ||
181 | printk("%02X:", ioread8(card->attr_io + (i << 1))); | ||
182 | } | ||
183 | printk("\n"); | ||
184 | |||
185 | /* Verify whether a supported PC card is present */ | ||
186 | /* FIXME: we probably need to be smarted about this */ | ||
187 | for (i = 0; i < sizeof(cis_magic); i++) { | ||
188 | if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { | ||
189 | printk(KERN_ERR PFX "The CIS value of Prism2 PC " | ||
190 | "card is unexpected\n"); | ||
191 | return -ENODEV; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /* bjoern: We need to tell the card to enable interrupts, in | ||
196 | case the serial eprom didn't do this already. See the | ||
197 | PLX9052 data book, p8-1 and 8-24 for reference. */ | ||
198 | csr_reg = ioread32(card->bridge_io + PLX_INTCSR); | ||
199 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
200 | csr_reg |= PLX_INTCSR_INTEN; | ||
201 | iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); | ||
202 | csr_reg = ioread32(card->bridge_io + PLX_INTCSR); | ||
203 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
204 | printk(KERN_ERR PFX "Cannot enable interrupts\n"); | ||
205 | return -EIO; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
180 | 211 | ||
181 | static int orinoco_plx_init_one(struct pci_dev *pdev, | 212 | static int orinoco_plx_init_one(struct pci_dev *pdev, |
182 | const struct pci_device_id *ent) | 213 | const struct pci_device_id *ent) |
183 | { | 214 | { |
184 | int err = 0; | 215 | int err; |
185 | u8 __iomem *attr_mem = NULL; | 216 | struct orinoco_private *priv; |
186 | u32 csr_reg, plx_addr; | 217 | struct orinoco_pci_card *card; |
187 | struct orinoco_private *priv = NULL; | 218 | struct net_device *dev; |
188 | struct orinoco_plx_card *card; | 219 | void __iomem *hermes_io, *attr_io, *bridge_io; |
189 | unsigned long pccard_ioaddr = 0; | ||
190 | unsigned long pccard_iolen = 0; | ||
191 | struct net_device *dev = NULL; | ||
192 | void __iomem *mem; | ||
193 | int i; | ||
194 | 220 | ||
195 | err = pci_enable_device(pdev); | 221 | err = pci_enable_device(pdev); |
196 | if (err) { | 222 | if (err) { |
@@ -199,30 +225,30 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, | |||
199 | } | 225 | } |
200 | 226 | ||
201 | err = pci_request_regions(pdev, DRIVER_NAME); | 227 | err = pci_request_regions(pdev, DRIVER_NAME); |
202 | if (err != 0) { | 228 | if (err) { |
203 | printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); | 229 | printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); |
204 | goto fail_resources; | 230 | goto fail_resources; |
205 | } | 231 | } |
206 | 232 | ||
207 | /* Resource 1 is mapped to PLX-specific registers */ | 233 | bridge_io = pci_iomap(pdev, 1, 0); |
208 | plx_addr = pci_resource_start(pdev, 1); | 234 | if (!bridge_io) { |
235 | printk(KERN_ERR PFX "Cannot map bridge registers\n"); | ||
236 | err = -EIO; | ||
237 | goto fail_map_bridge; | ||
238 | } | ||
209 | 239 | ||
210 | /* Resource 2 is mapped to the PCMCIA attribute memory */ | 240 | attr_io = pci_iomap(pdev, 2, 0); |
211 | attr_mem = ioremap(pci_resource_start(pdev, 2), | 241 | if (!attr_io) { |
212 | pci_resource_len(pdev, 2)); | 242 | printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); |
213 | if (!attr_mem) { | 243 | err = -EIO; |
214 | printk(KERN_ERR PFX "Cannot remap PCMCIA space\n"); | ||
215 | goto fail_map_attr; | 244 | goto fail_map_attr; |
216 | } | 245 | } |
217 | 246 | ||
218 | /* Resource 3 is mapped to the PCMCIA I/O address space */ | 247 | hermes_io = pci_iomap(pdev, 3, 0); |
219 | pccard_ioaddr = pci_resource_start(pdev, 3); | 248 | if (!hermes_io) { |
220 | pccard_iolen = pci_resource_len(pdev, 3); | 249 | printk(KERN_ERR PFX "Cannot map chipset registers\n"); |
221 | 250 | err = -EIO; | |
222 | mem = pci_iomap(pdev, 3, 0); | 251 | goto fail_map_hermes; |
223 | if (!mem) { | ||
224 | err = -ENOMEM; | ||
225 | goto fail_map_io; | ||
226 | } | 252 | } |
227 | 253 | ||
228 | /* Allocate network device */ | 254 | /* Allocate network device */ |
@@ -235,16 +261,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, | |||
235 | 261 | ||
236 | priv = netdev_priv(dev); | 262 | priv = netdev_priv(dev); |
237 | card = priv->card; | 263 | card = priv->card; |
238 | card->attr_mem = attr_mem; | 264 | card->bridge_io = bridge_io; |
239 | dev->base_addr = pccard_ioaddr; | 265 | card->attr_io = attr_io; |
240 | SET_MODULE_OWNER(dev); | 266 | SET_MODULE_OWNER(dev); |
241 | SET_NETDEV_DEV(dev, &pdev->dev); | 267 | SET_NETDEV_DEV(dev, &pdev->dev); |
242 | 268 | ||
243 | hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); | 269 | hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); |
244 | |||
245 | printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device " | ||
246 | "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, | ||
247 | pccard_ioaddr); | ||
248 | 270 | ||
249 | err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, | 271 | err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, |
250 | dev->name, dev); | 272 | dev->name, dev); |
@@ -253,20 +275,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, | |||
253 | err = -EBUSY; | 275 | err = -EBUSY; |
254 | goto fail_irq; | 276 | goto fail_irq; |
255 | } | 277 | } |
256 | dev->irq = pdev->irq; | 278 | orinoco_pci_setup_netdev(dev, pdev, 2); |
257 | 279 | ||
258 | /* bjoern: We need to tell the card to enable interrupts, in | 280 | err = orinoco_plx_hw_init(card); |
259 | case the serial eprom didn't do this already. See the | 281 | if (err) { |
260 | PLX9052 data book, p8-1 and 8-24 for reference. */ | 282 | printk(KERN_ERR PFX "Hardware initialization failed\n"); |
261 | csr_reg = inl(plx_addr + PLX_INTCSR); | 283 | goto fail; |
262 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
263 | csr_reg |= PLX_INTCSR_INTEN; | ||
264 | outl(csr_reg, plx_addr + PLX_INTCSR); | ||
265 | csr_reg = inl(plx_addr + PLX_INTCSR); | ||
266 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
267 | printk(KERN_ERR PFX "Cannot enable interrupts\n"); | ||
268 | goto fail; | ||
269 | } | ||
270 | } | 284 | } |
271 | 285 | ||
272 | err = orinoco_plx_cor_reset(priv); | 286 | err = orinoco_plx_cor_reset(priv); |
@@ -275,23 +289,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, | |||
275 | goto fail; | 289 | goto fail; |
276 | } | 290 | } |
277 | 291 | ||
278 | printk(KERN_DEBUG PFX "CIS: "); | ||
279 | for (i = 0; i < 16; i++) { | ||
280 | printk("%02X:", readb(attr_mem + 2*i)); | ||
281 | } | ||
282 | printk("\n"); | ||
283 | |||
284 | /* Verify whether a supported PC card is present */ | ||
285 | /* FIXME: we probably need to be smarted about this */ | ||
286 | for (i = 0; i < sizeof(cis_magic); i++) { | ||
287 | if (cis_magic[i] != readb(attr_mem +2*i)) { | ||
288 | printk(KERN_ERR PFX "The CIS value of Prism2 PC " | ||
289 | "card is unexpected\n"); | ||
290 | err = -EIO; | ||
291 | goto fail; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | err = register_netdev(dev); | 292 | err = register_netdev(dev); |
296 | if (err) { | 293 | if (err) { |
297 | printk(KERN_ERR PFX "Cannot register network device\n"); | 294 | printk(KERN_ERR PFX "Cannot register network device\n"); |
@@ -310,12 +307,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, | |||
310 | free_orinocodev(dev); | 307 | free_orinocodev(dev); |
311 | 308 | ||
312 | fail_alloc: | 309 | fail_alloc: |
313 | pci_iounmap(pdev, mem); | 310 | pci_iounmap(pdev, hermes_io); |
314 | 311 | ||
315 | fail_map_io: | 312 | fail_map_hermes: |
316 | iounmap(attr_mem); | 313 | pci_iounmap(pdev, attr_io); |
317 | 314 | ||
318 | fail_map_attr: | 315 | fail_map_attr: |
316 | pci_iounmap(pdev, bridge_io); | ||
317 | |||
318 | fail_map_bridge: | ||
319 | pci_release_regions(pdev); | 319 | pci_release_regions(pdev); |
320 | 320 | ||
321 | fail_resources: | 321 | fail_resources: |
@@ -328,100 +328,20 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) | |||
328 | { | 328 | { |
329 | struct net_device *dev = pci_get_drvdata(pdev); | 329 | struct net_device *dev = pci_get_drvdata(pdev); |
330 | struct orinoco_private *priv = netdev_priv(dev); | 330 | struct orinoco_private *priv = netdev_priv(dev); |
331 | struct orinoco_plx_card *card = priv->card; | 331 | struct orinoco_pci_card *card = priv->card; |
332 | u8 __iomem *attr_mem = card->attr_mem; | ||
333 | |||
334 | BUG_ON(! dev); | ||
335 | 332 | ||
336 | unregister_netdev(dev); | 333 | unregister_netdev(dev); |
337 | free_irq(dev->irq, dev); | 334 | free_irq(dev->irq, dev); |
338 | pci_set_drvdata(pdev, NULL); | 335 | pci_set_drvdata(pdev, NULL); |
339 | free_orinocodev(dev); | 336 | free_orinocodev(dev); |
340 | pci_iounmap(pdev, priv->hw.iobase); | 337 | pci_iounmap(pdev, priv->hw.iobase); |
341 | iounmap(attr_mem); | 338 | pci_iounmap(pdev, card->attr_io); |
339 | pci_iounmap(pdev, card->bridge_io); | ||
342 | pci_release_regions(pdev); | 340 | pci_release_regions(pdev); |
343 | pci_disable_device(pdev); | 341 | pci_disable_device(pdev); |
344 | } | 342 | } |
345 | 343 | ||
346 | static int orinoco_plx_suspend(struct pci_dev *pdev, pm_message_t state) | 344 | static struct pci_device_id orinoco_plx_id_table[] = { |
347 | { | ||
348 | struct net_device *dev = pci_get_drvdata(pdev); | ||
349 | struct orinoco_private *priv = netdev_priv(dev); | ||
350 | unsigned long flags; | ||
351 | int err; | ||
352 | |||
353 | err = orinoco_lock(priv, &flags); | ||
354 | if (err) { | ||
355 | printk(KERN_ERR "%s: cannot lock hardware for suspend\n", | ||
356 | dev->name); | ||
357 | return err; | ||
358 | } | ||
359 | |||
360 | err = __orinoco_down(dev); | ||
361 | if (err) | ||
362 | printk(KERN_WARNING "%s: error %d bringing interface down " | ||
363 | "for suspend\n", dev->name, err); | ||
364 | |||
365 | netif_device_detach(dev); | ||
366 | |||
367 | priv->hw_unavailable++; | ||
368 | |||
369 | orinoco_unlock(priv, &flags); | ||
370 | |||
371 | free_irq(pdev->irq, dev); | ||
372 | pci_save_state(pdev); | ||
373 | pci_disable_device(pdev); | ||
374 | pci_set_power_state(pdev, PCI_D3hot); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int orinoco_plx_resume(struct pci_dev *pdev) | ||
380 | { | ||
381 | struct net_device *dev = pci_get_drvdata(pdev); | ||
382 | struct orinoco_private *priv = netdev_priv(dev); | ||
383 | unsigned long flags; | ||
384 | int err; | ||
385 | |||
386 | pci_set_power_state(pdev, 0); | ||
387 | pci_enable_device(pdev); | ||
388 | pci_restore_state(pdev); | ||
389 | |||
390 | err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, | ||
391 | dev->name, dev); | ||
392 | if (err) { | ||
393 | printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", | ||
394 | dev->name); | ||
395 | pci_disable_device(pdev); | ||
396 | return -EBUSY; | ||
397 | } | ||
398 | |||
399 | err = orinoco_reinit_firmware(dev); | ||
400 | if (err) { | ||
401 | printk(KERN_ERR "%s: error %d re-initializing firmware " | ||
402 | "on resume\n", dev->name, err); | ||
403 | return err; | ||
404 | } | ||
405 | |||
406 | spin_lock_irqsave(&priv->lock, flags); | ||
407 | |||
408 | netif_device_attach(dev); | ||
409 | |||
410 | priv->hw_unavailable--; | ||
411 | |||
412 | if (priv->open && (! priv->hw_unavailable)) { | ||
413 | err = __orinoco_up(dev); | ||
414 | if (err) | ||
415 | printk(KERN_ERR "%s: Error %d restarting card on resume\n", | ||
416 | dev->name, err); | ||
417 | } | ||
418 | |||
419 | spin_unlock_irqrestore(&priv->lock, flags); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static struct pci_device_id orinoco_plx_pci_id_table[] = { | ||
425 | {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ | 345 | {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ |
426 | {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ | 346 | {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ |
427 | {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ | 347 | {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ |
@@ -439,15 +359,15 @@ static struct pci_device_id orinoco_plx_pci_id_table[] = { | |||
439 | {0,}, | 359 | {0,}, |
440 | }; | 360 | }; |
441 | 361 | ||
442 | MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table); | 362 | MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); |
443 | 363 | ||
444 | static struct pci_driver orinoco_plx_driver = { | 364 | static struct pci_driver orinoco_plx_driver = { |
445 | .name = DRIVER_NAME, | 365 | .name = DRIVER_NAME, |
446 | .id_table = orinoco_plx_pci_id_table, | 366 | .id_table = orinoco_plx_id_table, |
447 | .probe = orinoco_plx_init_one, | 367 | .probe = orinoco_plx_init_one, |
448 | .remove = __devexit_p(orinoco_plx_remove_one), | 368 | .remove = __devexit_p(orinoco_plx_remove_one), |
449 | .suspend = orinoco_plx_suspend, | 369 | .suspend = orinoco_pci_suspend, |
450 | .resume = orinoco_plx_resume, | 370 | .resume = orinoco_pci_resume, |
451 | }; | 371 | }; |
452 | 372 | ||
453 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | 373 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION |
@@ -467,7 +387,6 @@ static int __init orinoco_plx_init(void) | |||
467 | static void __exit orinoco_plx_exit(void) | 387 | static void __exit orinoco_plx_exit(void) |
468 | { | 388 | { |
469 | pci_unregister_driver(&orinoco_plx_driver); | 389 | pci_unregister_driver(&orinoco_plx_driver); |
470 | ssleep(1); | ||
471 | } | 390 | } |
472 | 391 | ||
473 | module_init(orinoco_plx_init); | 392 | module_init(orinoco_plx_init); |