aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h2
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c169
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c352
3 files changed, 112 insertions, 411 deletions
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index 3ddd75937a40..d9769b30be9a 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -31,7 +31,7 @@
31#include <linux/types.h> 31#include <linux/types.h>
32#include <linux/pci.h> 32#include <linux/pci.h>
33 33
34/* PICMG 2.12 R2.0 HS CSR bits: */ 34/* PICMG 2.1 R2.0 HS CSR bits: */
35#define HS_CSR_INS 0x0080 35#define HS_CSR_INS 0x0080
36#define HS_CSR_EXT 0x0040 36#define HS_CSR_EXT 0x0040
37#define HS_CSR_PI 0x0030 37#define HS_CSR_PI 0x0030
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index ed243605dc7b..9e9dab7fe86a 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -33,11 +33,11 @@
33#include <linux/init.h> 33#include <linux/init.h>
34#include <linux/interrupt.h> 34#include <linux/interrupt.h>
35#include <linux/smp_lock.h> 35#include <linux/smp_lock.h>
36#include <asm/atomic.h>
36#include <linux/delay.h> 37#include <linux/delay.h>
37#include "pci_hotplug.h" 38#include "pci_hotplug.h"
38#include "cpci_hotplug.h" 39#include "cpci_hotplug.h"
39 40
40#define DRIVER_VERSION "0.2"
41#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" 41#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
42#define DRIVER_DESC "CompactPCI Hot Plug Core" 42#define DRIVER_DESC "CompactPCI Hot Plug Core"
43 43
@@ -54,9 +54,10 @@
54#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) 54#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
55 55
56/* local variables */ 56/* local variables */
57static spinlock_t list_lock; 57static DECLARE_RWSEM(list_rwsem);
58static LIST_HEAD(slot_list); 58static LIST_HEAD(slot_list);
59static int slots; 59static int slots;
60static atomic_t extracting;
60int cpci_debug; 61int cpci_debug;
61static struct cpci_hp_controller *controller; 62static struct cpci_hp_controller *controller;
62static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ 63static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
@@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_slot *slot);
68static int set_attention_status(struct hotplug_slot *slot, u8 value); 69static int set_attention_status(struct hotplug_slot *slot, u8 value);
69static int get_power_status(struct hotplug_slot *slot, u8 * value); 70static int get_power_status(struct hotplug_slot *slot, u8 * value);
70static int get_attention_status(struct hotplug_slot *slot, u8 * value); 71static int get_attention_status(struct hotplug_slot *slot, u8 * value);
72static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
73static int get_latch_status(struct hotplug_slot *slot, u8 * value);
71 74
72static struct hotplug_slot_ops cpci_hotplug_slot_ops = { 75static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
73 .owner = THIS_MODULE, 76 .owner = THIS_MODULE,
@@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
76 .set_attention_status = set_attention_status, 79 .set_attention_status = set_attention_status,
77 .get_power_status = get_power_status, 80 .get_power_status = get_power_status,
78 .get_attention_status = get_attention_status, 81 .get_attention_status = get_attention_status,
82 .get_adapter_status = get_adapter_status,
83 .get_latch_status = get_latch_status,
79}; 84};
80 85
81static int 86static int
@@ -148,8 +153,10 @@ disable_slot(struct hotplug_slot *hotplug_slot)
148 warn("failure to update adapter file"); 153 warn("failure to update adapter file");
149 } 154 }
150 155
151 slot->extracting = 0; 156 if(slot->extracting) {
152 157 slot->extracting = 0;
158 atomic_dec(&extracting);
159 }
153 return retval; 160 return retval;
154} 161}
155 162
@@ -188,6 +195,20 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
188 return cpci_set_attention_status(hotplug_slot->private, status); 195 return cpci_set_attention_status(hotplug_slot->private, status);
189} 196}
190 197
198static int
199get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
200{
201 *value = hotplug_slot->info->adapter_status;
202 return 0;
203}
204
205static int
206get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
207{
208 *value = hotplug_slot->info->latch_status;
209 return 0;
210}
211
191static void release_slot(struct hotplug_slot *hotplug_slot) 212static void release_slot(struct hotplug_slot *hotplug_slot)
192{ 213{
193 struct slot *slot = hotplug_slot->private; 214 struct slot *slot = hotplug_slot->private;
@@ -273,10 +294,10 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
273 } 294 }
274 295
275 /* Add slot to our internal list */ 296 /* Add slot to our internal list */
276 spin_lock(&list_lock); 297 down_write(&list_rwsem);
277 list_add(&slot->slot_list, &slot_list); 298 list_add(&slot->slot_list, &slot_list);
278 slots++; 299 slots++;
279 spin_unlock(&list_lock); 300 up_write(&list_rwsem);
280 } 301 }
281 return 0; 302 return 0;
282error_name: 303error_name:
@@ -299,9 +320,9 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
299 struct list_head *next; 320 struct list_head *next;
300 int status; 321 int status;
301 322
302 spin_lock(&list_lock); 323 down_write(&list_rwsem);
303 if(!slots) { 324 if(!slots) {
304 spin_unlock(&list_lock); 325 up_write(&list_rwsem);
305 return -1; 326 return -1;
306 } 327 }
307 list_for_each_safe(tmp, next, &slot_list) { 328 list_for_each_safe(tmp, next, &slot_list) {
@@ -319,7 +340,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
319 slots--; 340 slots--;
320 } 341 }
321 } 342 }
322 spin_unlock(&list_lock); 343 up_write(&list_rwsem);
323 return 0; 344 return 0;
324} 345}
325 346
@@ -347,7 +368,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
347} 368}
348 369
349/* 370/*
350 * According to PICMG 2.12 R2.0, section 6.3.2, upon 371 * According to PICMG 2.1 R2.0, section 6.3.2, upon
351 * initialization, the system driver shall clear the 372 * initialization, the system driver shall clear the
352 * INS bits of the cold-inserted devices. 373 * INS bits of the cold-inserted devices.
353 */ 374 */
@@ -359,9 +380,9 @@ init_slots(void)
359 struct pci_dev* dev; 380 struct pci_dev* dev;
360 381
361 dbg("%s - enter", __FUNCTION__); 382 dbg("%s - enter", __FUNCTION__);
362 spin_lock(&list_lock); 383 down_read(&list_rwsem);
363 if(!slots) { 384 if(!slots) {
364 spin_unlock(&list_lock); 385 up_read(&list_rwsem);
365 return -1; 386 return -1;
366 } 387 }
367 list_for_each(tmp, &slot_list) { 388 list_for_each(tmp, &slot_list) {
@@ -386,7 +407,7 @@ init_slots(void)
386 } 407 }
387 } 408 }
388 } 409 }
389 spin_unlock(&list_lock); 410 up_read(&list_rwsem);
390 dbg("%s - exit", __FUNCTION__); 411 dbg("%s - exit", __FUNCTION__);
391 return 0; 412 return 0;
392} 413}
@@ -398,10 +419,11 @@ check_slots(void)
398 struct list_head *tmp; 419 struct list_head *tmp;
399 int extracted; 420 int extracted;
400 int inserted; 421 int inserted;
422 u16 hs_csr;
401 423
402 spin_lock(&list_lock); 424 down_read(&list_rwsem);
403 if(!slots) { 425 if(!slots) {
404 spin_unlock(&list_lock); 426 up_read(&list_rwsem);
405 err("no slots registered, shutting down"); 427 err("no slots registered, shutting down");
406 return -1; 428 return -1;
407 } 429 }
@@ -411,8 +433,6 @@ check_slots(void)
411 dbg("%s - looking at slot %s", 433 dbg("%s - looking at slot %s",
412 __FUNCTION__, slot->hotplug_slot->name); 434 __FUNCTION__, slot->hotplug_slot->name);
413 if(cpci_check_and_clear_ins(slot)) { 435 if(cpci_check_and_clear_ins(slot)) {
414 u16 hs_csr;
415
416 /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ 436 /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
417 if(slot->dev) { 437 if(slot->dev) {
418 warn("slot %s already inserted", slot->hotplug_slot->name); 438 warn("slot %s already inserted", slot->hotplug_slot->name);
@@ -462,8 +482,6 @@ check_slots(void)
462 482
463 inserted++; 483 inserted++;
464 } else if(cpci_check_ext(slot)) { 484 } else if(cpci_check_ext(slot)) {
465 u16 hs_csr;
466
467 /* Process extraction request */ 485 /* Process extraction request */
468 dbg("%s - slot %s extracted", 486 dbg("%s - slot %s extracted",
469 __FUNCTION__, slot->hotplug_slot->name); 487 __FUNCTION__, slot->hotplug_slot->name);
@@ -476,20 +494,40 @@ check_slots(void)
476 if(!slot->extracting) { 494 if(!slot->extracting) {
477 if(update_latch_status(slot->hotplug_slot, 0)) { 495 if(update_latch_status(slot->hotplug_slot, 0)) {
478 warn("failure to update latch file"); 496 warn("failure to update latch file");
497
479 } 498 }
499 atomic_inc(&extracting);
480 slot->extracting = 1; 500 slot->extracting = 1;
481 } 501 }
482 extracted++; 502 extracted++;
503 } else if(slot->extracting) {
504 hs_csr = cpci_get_hs_csr(slot);
505 if(hs_csr == 0xffff) {
506 /*
507 * Hmmm, we're likely hosed at this point, should we
508 * bother trying to tell the driver or not?
509 */
510 err("card in slot %s was improperly removed",
511 slot->hotplug_slot->name);
512 if(update_adapter_status(slot->hotplug_slot, 0)) {
513 warn("failure to update adapter file");
514 }
515 slot->extracting = 0;
516 atomic_dec(&extracting);
517 }
483 } 518 }
484 } 519 }
485 spin_unlock(&list_lock); 520 up_read(&list_rwsem);
521 dbg("inserted=%d, extracted=%d, extracting=%d",
522 inserted, extracted, atomic_read(&extracting));
486 if(inserted || extracted) { 523 if(inserted || extracted) {
487 return extracted; 524 return extracted;
488 } 525 }
489 else { 526 else if(!atomic_read(&extracting)) {
490 err("cannot find ENUM# source, shutting down"); 527 err("cannot find ENUM# source, shutting down");
491 return -1; 528 return -1;
492 } 529 }
530 return 0;
493} 531}
494 532
495/* This is the interrupt mode worker thread body */ 533/* This is the interrupt mode worker thread body */
@@ -497,8 +535,6 @@ static int
497event_thread(void *data) 535event_thread(void *data)
498{ 536{
499 int rc; 537 int rc;
500 struct slot *slot;
501 struct list_head *tmp;
502 538
503 lock_kernel(); 539 lock_kernel();
504 daemonize("cpci_hp_eventd"); 540 daemonize("cpci_hp_eventd");
@@ -512,39 +548,22 @@ event_thread(void *data)
512 thread_finished); 548 thread_finished);
513 if(thread_finished || signal_pending(current)) 549 if(thread_finished || signal_pending(current))
514 break; 550 break;
515 while(controller->ops->query_enum()) { 551 do {
516 rc = check_slots(); 552 rc = check_slots();
517 if (rc > 0) 553 if (rc > 0) {
518 /* Give userspace a chance to handle extraction */ 554 /* Give userspace a chance to handle extraction */
519 msleep(500); 555 msleep(500);
520 else if (rc < 0) { 556 } else if (rc < 0) {
521 dbg("%s - error checking slots", __FUNCTION__); 557 dbg("%s - error checking slots", __FUNCTION__);
522 thread_finished = 1; 558 thread_finished = 1;
523 break; 559 break;
524 } 560 }
525 } 561 } while(atomic_read(&extracting) != 0);
526 /* Check for someone yanking out a board */
527 list_for_each(tmp, &slot_list) {
528 slot = list_entry(tmp, struct slot, slot_list);
529 if(slot->extracting) {
530 /*
531 * Hmmm, we're likely hosed at this point, should we
532 * bother trying to tell the driver or not?
533 */
534 err("card in slot %s was improperly removed",
535 slot->hotplug_slot->name);
536 if(update_adapter_status(slot->hotplug_slot, 0)) {
537 warn("failure to update adapter file");
538 }
539 slot->extracting = 0;
540 }
541 }
542 562
543 /* Re-enable ENUM# interrupt */ 563 /* Re-enable ENUM# interrupt */
544 dbg("%s - re-enabling irq", __FUNCTION__); 564 dbg("%s - re-enabling irq", __FUNCTION__);
545 controller->ops->enable_irq(); 565 controller->ops->enable_irq();
546 } 566 }
547
548 dbg("%s - event thread signals exit", __FUNCTION__); 567 dbg("%s - event thread signals exit", __FUNCTION__);
549 up(&thread_exit); 568 up(&thread_exit);
550 return 0; 569 return 0;
@@ -555,8 +574,6 @@ static int
555poll_thread(void *data) 574poll_thread(void *data)
556{ 575{
557 int rc; 576 int rc;
558 struct slot *slot;
559 struct list_head *tmp;
560 577
561 lock_kernel(); 578 lock_kernel();
562 daemonize("cpci_hp_polld"); 579 daemonize("cpci_hp_polld");
@@ -565,35 +582,19 @@ poll_thread(void *data)
565 while(1) { 582 while(1) {
566 if(thread_finished || signal_pending(current)) 583 if(thread_finished || signal_pending(current))
567 break; 584 break;
568 585 if(controller->ops->query_enum()) {
569 while(controller->ops->query_enum()) { 586 do {
570 rc = check_slots(); 587 rc = check_slots();
571 if(rc > 0) 588 if(rc > 0) {
572 /* Give userspace a chance to handle extraction */ 589 /* Give userspace a chance to handle extraction */
573 msleep(500); 590 msleep(500);
574 else if (rc < 0) { 591 } else if(rc < 0) {
575 dbg("%s - error checking slots", __FUNCTION__); 592 dbg("%s - error checking slots", __FUNCTION__);
576 thread_finished = 1; 593 thread_finished = 1;
577 break; 594 break;
578 }
579 }
580 /* Check for someone yanking out a board */
581 list_for_each(tmp, &slot_list) {
582 slot = list_entry(tmp, struct slot, slot_list);
583 if(slot->extracting) {
584 /*
585 * Hmmm, we're likely hosed at this point, should we
586 * bother trying to tell the driver or not?
587 */
588 err("card in slot %s was improperly removed",
589 slot->hotplug_slot->name);
590 if(update_adapter_status(slot->hotplug_slot, 0)) {
591 warn("failure to update adapter file");
592 } 595 }
593 slot->extracting = 0; 596 } while(atomic_read(&extracting) != 0);
594 }
595 } 597 }
596
597 msleep(100); 598 msleep(100);
598 } 599 }
599 dbg("poll thread signals exit"); 600 dbg("poll thread signals exit");
@@ -667,6 +668,9 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
667 int status = 0; 668 int status = 0;
668 669
669 if(controller) { 670 if(controller) {
671 if(atomic_read(&extracting) != 0) {
672 return -EBUSY;
673 }
670 if(!thread_finished) { 674 if(!thread_finished) {
671 cpci_stop_thread(); 675 cpci_stop_thread();
672 } 676 }
@@ -691,12 +695,12 @@ cpci_hp_start(void)
691 return -ENODEV; 695 return -ENODEV;
692 } 696 }
693 697
694 spin_lock(&list_lock); 698 down_read(&list_rwsem);
695 if(!slots) { 699 if(list_empty(&slot_list)) {
696 spin_unlock(&list_lock); 700 up_read(&list_rwsem);
697 return -ENODEV; 701 return -ENODEV;
698 } 702 }
699 spin_unlock(&list_lock); 703 up_read(&list_rwsem);
700 704
701 if(first) { 705 if(first) {
702 status = init_slots(); 706 status = init_slots();
@@ -727,7 +731,9 @@ cpci_hp_stop(void)
727 if(!controller) { 731 if(!controller) {
728 return -ENODEV; 732 return -ENODEV;
729 } 733 }
730 734 if(atomic_read(&extracting) != 0) {
735 return -EBUSY;
736 }
731 if(controller->irq) { 737 if(controller->irq) {
732 /* Stop enum interrupt processing */ 738 /* Stop enum interrupt processing */
733 dbg("%s - disabling irq", __FUNCTION__); 739 dbg("%s - disabling irq", __FUNCTION__);
@@ -747,7 +753,7 @@ cleanup_slots(void)
747 * Unregister all of our slots with the pci_hotplug subsystem, 753 * Unregister all of our slots with the pci_hotplug subsystem,
748 * and free up all memory that we had allocated. 754 * and free up all memory that we had allocated.
749 */ 755 */
750 spin_lock(&list_lock); 756 down_write(&list_rwsem);
751 if(!slots) { 757 if(!slots) {
752 goto null_cleanup; 758 goto null_cleanup;
753 } 759 }
@@ -761,17 +767,14 @@ cleanup_slots(void)
761 kfree(slot); 767 kfree(slot);
762 } 768 }
763 null_cleanup: 769 null_cleanup:
764 spin_unlock(&list_lock); 770 up_write(&list_rwsem);
765 return; 771 return;
766} 772}
767 773
768int __init 774int __init
769cpci_hotplug_init(int debug) 775cpci_hotplug_init(int debug)
770{ 776{
771 spin_lock_init(&list_lock);
772 cpci_debug = debug; 777 cpci_debug = debug;
773
774 info(DRIVER_DESC " version: " DRIVER_VERSION);
775 return 0; 778 return 0;
776} 779}
777 780
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 2e969616f298..69eb4fc54f2f 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -32,11 +32,7 @@
32#include "pci_hotplug.h" 32#include "pci_hotplug.h"
33#include "cpci_hotplug.h" 33#include "cpci_hotplug.h"
34 34
35#if !defined(MODULE)
36#define MY_NAME "cpci_hotplug" 35#define MY_NAME "cpci_hotplug"
37#else
38#define MY_NAME THIS_MODULE->name
39#endif
40 36
41extern int cpci_debug; 37extern int cpci_debug;
42 38
@@ -127,38 +123,6 @@ u16 cpci_get_hs_csr(struct slot* slot)
127 return hs_csr; 123 return hs_csr;
128} 124}
129 125
130#if 0
131u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr)
132{
133 int hs_cap;
134 u16 new_hs_csr;
135
136 hs_cap = pci_bus_find_capability(slot->bus,
137 slot->devfn,
138 PCI_CAP_ID_CHSWP);
139 if(!hs_cap) {
140 return 0xFFFF;
141 }
142
143 /* Write out the new value */
144 if(pci_bus_write_config_word(slot->bus,
145 slot->devfn,
146 hs_cap + 2,
147 hs_csr)) {
148 return 0xFFFF;
149 }
150
151 /* Read back what we just wrote out */
152 if(pci_bus_read_config_word(slot->bus,
153 slot->devfn,
154 hs_cap + 2,
155 &new_hs_csr)) {
156 return 0xFFFF;
157 }
158 return new_hs_csr;
159}
160#endif
161
162int cpci_check_and_clear_ins(struct slot* slot) 126int cpci_check_and_clear_ins(struct slot* slot)
163{ 127{
164 int hs_cap; 128 int hs_cap;
@@ -261,7 +225,6 @@ int cpci_led_on(struct slot* slot)
261 return -ENODEV; 225 return -ENODEV;
262 } 226 }
263 if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { 227 if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
264 /* Set LOO */
265 hs_csr |= HS_CSR_LOO; 228 hs_csr |= HS_CSR_LOO;
266 if(pci_bus_write_config_word(slot->bus, 229 if(pci_bus_write_config_word(slot->bus,
267 slot->devfn, 230 slot->devfn,
@@ -293,7 +256,6 @@ int cpci_led_off(struct slot* slot)
293 return -ENODEV; 256 return -ENODEV;
294 } 257 }
295 if(hs_csr & HS_CSR_LOO) { 258 if(hs_csr & HS_CSR_LOO) {
296 /* Clear LOO */
297 hs_csr &= ~HS_CSR_LOO; 259 hs_csr &= ~HS_CSR_LOO;
298 if(pci_bus_write_config_word(slot->bus, 260 if(pci_bus_write_config_word(slot->bus,
299 slot->devfn, 261 slot->devfn,
@@ -312,257 +274,23 @@ int cpci_led_off(struct slot* slot)
312 * Device configuration functions 274 * Device configuration functions
313 */ 275 */
314 276
315static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) 277static void cpci_enable_device(struct pci_dev *dev)
316{
317 u8 irq_pin;
318 int r;
319
320 dbg("%s - enter", __FUNCTION__);
321
322 /* NOTE: device already setup from prior scan */
323
324 /* FIXME: How would we know if we need to enable the expansion ROM? */
325 pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L);
326
327 /* Assign resources */
328 dbg("assigning resources for %02x:%02x.%x",
329 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
330 for (r = 0; r < 6; r++) {
331 struct resource *res = dev->resource + r;
332 if(res->flags)
333 pci_assign_resource(dev, r);
334 }
335 dbg("finished assigning resources for %02x:%02x.%x",
336 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
337
338 /* Does this function have an interrupt at all? */
339 dbg("checking for function interrupt");
340 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
341 if(irq_pin) {
342 dbg("function uses interrupt pin %d", irq_pin);
343 }
344
345 /*
346 * Need to explicitly set irq field to 0 so that it'll get assigned
347 * by the pcibios platform dependent code called by pci_enable_device.
348 */
349 dev->irq = 0;
350
351 dbg("enabling device");
352 pci_enable_device(dev); /* XXX check return */
353 dbg("now dev->irq = %d", dev->irq);
354 if(irq_pin && dev->irq) {
355 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
356 }
357
358 /* Can't use pci_insert_device at the moment, do it manually for now */
359 pci_proc_attach_device(dev);
360 dbg("notifying drivers");
361 //pci_announce_device_to_drivers(dev);
362 dbg("%s - exit", __FUNCTION__);
363 return 0;
364}
365
366static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
367{ 278{
368 int rc; 279 struct pci_bus *bus;
369 struct pci_bus* child;
370 struct resource* r;
371 u8 max, n;
372 u16 command;
373
374 dbg("%s - enter", __FUNCTION__);
375 280
376 /* Do basic bridge initialization */ 281 pci_enable_device(dev);
377 rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
378 if(rc) {
379 printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__);
380 }
381 rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
382 if(rc) {
383 printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__);
384 }
385 rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
386 if(rc) {
387 printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__);
388 }
389
390 /*
391 * Set parent bridge's subordinate field so that configuration space
392 * access will work in pci_scan_bridge and friends.
393 */
394 max = pci_max_busnr();
395 bus->subordinate = max + 1;
396 pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1);
397
398 /* Scan behind bridge */
399 n = pci_scan_bridge(bus, dev, max, 2);
400 child = pci_find_bus(0, max + 1);
401 if (!child)
402 return -ENODEV;
403 pci_proc_attach_bus(child);
404
405 /*
406 * Update parent bridge's subordinate field if there were more bridges
407 * behind the bridge that was scanned.
408 */
409 if(n > max) {
410 bus->subordinate = n;
411 pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n);
412 }
413
414 /*
415 * Update the bridge resources of the bridge to accommodate devices
416 * behind it.
417 */
418 pci_bus_size_bridges(child);
419 pci_bus_assign_resources(child);
420
421 /* Enable resource mapping via command register */
422 command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
423 r = child->resource[0];
424 if(r && r->start) {
425 command |= PCI_COMMAND_IO;
426 }
427 r = child->resource[1];
428 if(r && r->start) {
429 command |= PCI_COMMAND_MEMORY;
430 }
431 r = child->resource[2];
432 if(r && r->start) {
433 command |= PCI_COMMAND_MEMORY;
434 }
435 rc = pci_write_config_word(dev, PCI_COMMAND, command);
436 if(rc) {
437 err("Error setting command register");
438 return rc;
439 }
440
441 /* Set bridge control register */
442 command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA;
443 rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command);
444 if(rc) {
445 err("Error setting bridge control register");
446 return rc;
447 }
448 dbg("%s - exit", __FUNCTION__);
449 return 0;
450}
451
452static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev,
453 struct pci_bus_wrapped *wrapped_bus)
454{
455 int rc;
456 struct pci_dev *dev = wrapped_dev->dev;
457 struct pci_bus *bus = wrapped_bus->bus;
458 struct slot* slot;
459
460 dbg("%s - enter", __FUNCTION__);
461
462 /*
463 * We need to fix up the hotplug representation with the Linux
464 * representation.
465 */
466 if(wrapped_dev->data) {
467 slot = (struct slot*) wrapped_dev->data;
468 slot->dev = dev;
469 }
470
471 /* If it's a bridge, scan behind it for devices */
472 if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 282 if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
473 rc = cpci_configure_bridge(bus, dev); 283 bus = dev->subordinate;
474 if(rc) 284 list_for_each_entry(dev, &bus->devices, bus_list) {
475 return rc; 285 cpci_enable_device(dev);
476 }
477
478 /* Actually configure device */
479 if(dev) {
480 rc = cpci_configure_dev(bus, dev);
481 if(rc)
482 return rc;
483 }
484 dbg("%s - exit", __FUNCTION__);
485 return 0;
486}
487
488static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev,
489 struct pci_bus_wrapped *wrapped_bus)
490{
491 struct pci_dev *dev = wrapped_dev->dev;
492 struct slot* slot;
493
494 dbg("%s - enter", __FUNCTION__);
495 if(!dev)
496 return -ENODEV;
497
498 /* Remove the Linux representation */
499 if(pci_remove_device_safe(dev)) {
500 err("Could not remove device\n");
501 return -1;
502 }
503
504 /*
505 * Now remove the hotplug representation.
506 */
507 if(wrapped_dev->data) {
508 slot = (struct slot*) wrapped_dev->data;
509 slot->dev = NULL;
510 } else {
511 dbg("No hotplug representation for %02x:%02x.%x",
512 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
513 }
514 dbg("%s - exit", __FUNCTION__);
515 return 0;
516}
517
518static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus,
519 struct pci_dev_wrapped *wrapped_dev)
520{
521 struct pci_bus *bus = wrapped_bus->bus;
522 struct pci_bus *parent = bus->self->bus;
523
524 dbg("%s - enter", __FUNCTION__);
525
526 /* The cleanup code for proc entries regarding buses should be in the kernel... */
527 if(bus->procdir)
528 dbg("detach_pci_bus %s", bus->procdir->name);
529 pci_proc_detach_bus(bus);
530
531 /* The cleanup code should live in the kernel... */
532 bus->self->subordinate = NULL;
533
534 /* unlink from parent bus */
535 list_del(&bus->node);
536
537 /* Now, remove */
538 if(bus)
539 kfree(bus);
540
541 /* Update parent's subordinate field */
542 if(parent) {
543 u8 n = pci_bus_max_busnr(parent);
544 if(n < parent->subordinate) {
545 parent->subordinate = n;
546 pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n);
547 } 286 }
548 } 287 }
549 dbg("%s - exit", __FUNCTION__);
550 return 0;
551} 288}
552 289
553static struct pci_visit configure_functions = {
554 .visit_pci_dev = configure_visit_pci_dev,
555};
556
557static struct pci_visit unconfigure_functions_phase2 = {
558 .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2,
559 .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2
560};
561
562
563int cpci_configure_slot(struct slot* slot) 290int cpci_configure_slot(struct slot* slot)
564{ 291{
565 int rc = 0; 292 unsigned char busnr;
293 struct pci_bus *child;
566 294
567 dbg("%s - enter", __FUNCTION__); 295 dbg("%s - enter", __FUNCTION__);
568 296
@@ -588,74 +316,44 @@ int cpci_configure_slot(struct slot* slot)
588 slot->dev = pci_find_slot(slot->bus->number, slot->devfn); 316 slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
589 if(slot->dev == NULL) { 317 if(slot->dev == NULL) {
590 err("Could not find PCI device for slot %02x", slot->number); 318 err("Could not find PCI device for slot %02x", slot->number);
591 return 0; 319 return 1;
592 } 320 }
593 } 321 }
594 dbg("slot->dev = %p", slot->dev); 322
595 if(slot->dev) { 323 if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
596 struct pci_dev *dev; 324 pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr);
597 struct pci_dev_wrapped wrapped_dev; 325 child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr);
598 struct pci_bus_wrapped wrapped_bus; 326 pci_do_scan_bus(child);
599 int i; 327 pci_bus_size_bridges(child);
600
601 memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
602 memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
603
604 for (i = 0; i < 8; i++) {
605 dev = pci_find_slot(slot->bus->number,
606 PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i));
607 if(!dev)
608 continue;
609 wrapped_dev.dev = dev;
610 wrapped_bus.bus = slot->dev->bus;
611 if(i)
612 wrapped_dev.data = NULL;
613 else
614 wrapped_dev.data = (void*) slot;
615 rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
616 }
617 } 328 }
618 329
619 dbg("%s - exit, rc = %d", __FUNCTION__, rc); 330 pci_bus_assign_resources(slot->dev->bus);
620 return rc; 331
332 cpci_enable_device(slot->dev);
333
334 dbg("%s - exit", __FUNCTION__);
335 return 0;
621} 336}
622 337
623int cpci_unconfigure_slot(struct slot* slot) 338int cpci_unconfigure_slot(struct slot* slot)
624{ 339{
625 int rc = 0;
626 int i; 340 int i;
627 struct pci_dev_wrapped wrapped_dev;
628 struct pci_bus_wrapped wrapped_bus;
629 struct pci_dev *dev; 341 struct pci_dev *dev;
630 342
631 dbg("%s - enter", __FUNCTION__); 343 dbg("%s - enter", __FUNCTION__);
632
633 if(!slot->dev) { 344 if(!slot->dev) {
634 err("No device for slot %02x\n", slot->number); 345 err("No device for slot %02x\n", slot->number);
635 return -ENODEV; 346 return -ENODEV;
636 } 347 }
637 348
638 memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
639 memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
640
641 for (i = 0; i < 8; i++) { 349 for (i = 0; i < 8; i++) {
642 dev = pci_find_slot(slot->bus->number, 350 dev = pci_find_slot(slot->bus->number,
643 PCI_DEVFN(PCI_SLOT(slot->devfn), i)); 351 PCI_DEVFN(PCI_SLOT(slot->devfn), i));
644 if(dev) { 352 if(dev) {
645 wrapped_dev.dev = dev; 353 pci_remove_bus_device(dev);
646 wrapped_bus.bus = dev->bus; 354 slot->dev = NULL;
647 if(i)
648 wrapped_dev.data = NULL;
649 else
650 wrapped_dev.data = (void*) slot;
651 dbg("%s - unconfigure phase 2", __FUNCTION__);
652 rc = pci_visit_dev(&unconfigure_functions_phase2,
653 &wrapped_dev,
654 &wrapped_bus);
655 if(rc)
656 break;
657 } 355 }
658 } 356 }
659 dbg("%s - exit, rc = %d", __FUNCTION__, rc); 357 dbg("%s - exit", __FUNCTION__);
660 return rc; 358 return 0;
661} 359}