aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorScott Murray <scottm@somanetworks.com>2005-05-09 17:31:50 -0400
committerGreg KH <gregkh@suse.de>2005-05-17 17:31:11 -0400
commit43b7d7cfb157b5c8c5cc0933f4e96fd81adc81ca (patch)
tree2af3b43ed8ee9468b1e0418c10275f33d23ced19 /drivers/pci/hotplug
parent8b245e45f34280ec61e3c8d643d4613b9e0eb7a4 (diff)
[PATCH] PCI Hotplug: CPCI update
[PATCH] CPCI: update I have finally done some work to update the CompactPCI hotplug driver to fix some of the outstanding issues in 2.6: - Added adapter and latch status ops so that those files will get created by the current PCI hotplug core. This used to not be required, but seems to be now after some of the sysfs rework in the core. - Replaced slot list spinlock with a r/w semaphore to avoid any potential issues with sleeping. This quiets all of the runtime warnings. - Reworked interrupt driven hot extraction handling to remove need for a polling operator for ENUM# status. There are a lot of boards that only have an interrupt driven by ENUM#, so this lowers the bar to entry. - Replaced pci_visit_dev usage with better use of the PCI core functions. The new code is functionally equivalent to the previous code, but the use of pci_enable_device on insert needs to be investigated further, as I need to do some more testing to see if it is still necessary. Signed-off-by: Scott Murray <scottm@somanetworks.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug')
-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}