aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/shpchp.h7
-rw-r--r--drivers/pci/hotplug/shpchp_core.c8
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c227
3 files changed, 181 insertions, 61 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 87db07cfebdf..dd449512cf68 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -72,6 +72,7 @@ struct slot {
72 struct list_head slot_list; 72 struct list_head slot_list;
73 char name[SLOT_NAME_SIZE]; 73 char name[SLOT_NAME_SIZE];
74 struct work_struct work; /* work for button event */ 74 struct work_struct work; /* work for button event */
75 struct mutex lock;
75}; 76};
76 77
77struct event_info { 78struct event_info {
@@ -181,8 +182,8 @@ struct hotplug_params {
181/* sysfs functions for the hotplug controller info */ 182/* sysfs functions for the hotplug controller info */
182extern void shpchp_create_ctrl_files (struct controller *ctrl); 183extern void shpchp_create_ctrl_files (struct controller *ctrl);
183 184
184extern int shpchp_enable_slot(struct slot *slot); 185extern int shpchp_sysfs_enable_slot(struct slot *slot);
185extern int shpchp_disable_slot(struct slot *slot); 186extern int shpchp_sysfs_disable_slot(struct slot *slot);
186 187
187extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id); 188extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id);
188extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); 189extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
@@ -200,7 +201,7 @@ extern int shpchprm_get_physical_slot_number(struct controller *ctrl,
200 u32 *sun, u8 busnum, u8 devnum); 201 u32 *sun, u8 busnum, u8 devnum);
201extern void shpchp_remove_ctrl_files(struct controller *ctrl); 202extern void shpchp_remove_ctrl_files(struct controller *ctrl);
202extern void cleanup_slots(struct controller *ctrl); 203extern void cleanup_slots(struct controller *ctrl);
203extern void shpchp_pushbutton_thread(void *data); 204extern void queue_pushbutton_work(void *data);
204 205
205/* Global variables */ 206/* Global variables */
206extern struct list_head shpchp_ctrl_list; 207extern struct list_head shpchp_ctrl_list;
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 5de659d23d1a..fa60ae47d91d 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -136,13 +136,14 @@ static int init_slots(struct controller *ctrl)
136 slot->bus = ctrl->slot_bus; 136 slot->bus = ctrl->slot_bus;
137 slot->device = ctrl->slot_device_offset + i; 137 slot->device = ctrl->slot_device_offset + i;
138 slot->hpc_ops = ctrl->hpc_ops; 138 slot->hpc_ops = ctrl->hpc_ops;
139 mutex_init(&slot->lock);
139 140
140 if (shpchprm_get_physical_slot_number(ctrl, &sun, 141 if (shpchprm_get_physical_slot_number(ctrl, &sun,
141 slot->bus, slot->device)) 142 slot->bus, slot->device))
142 goto error_info; 143 goto error_info;
143 144
144 slot->number = sun; 145 slot->number = sun;
145 INIT_WORK(&slot->work, shpchp_pushbutton_thread, slot); 146 INIT_WORK(&slot->work, queue_pushbutton_work, slot);
146 147
147 /* register this slot with the hotplug pci core */ 148 /* register this slot with the hotplug pci core */
148 hotplug_slot->private = slot; 149 hotplug_slot->private = slot;
@@ -188,6 +189,7 @@ void cleanup_slots(struct controller *ctrl)
188 slot = list_entry(tmp, struct slot, slot_list); 189 slot = list_entry(tmp, struct slot, slot_list);
189 list_del(&slot->slot_list); 190 list_del(&slot->slot_list);
190 cancel_delayed_work(&slot->work); 191 cancel_delayed_work(&slot->work);
192 flush_scheduled_work();
191 flush_workqueue(shpchp_wq); 193 flush_workqueue(shpchp_wq);
192 pci_hp_deregister(slot->hotplug_slot); 194 pci_hp_deregister(slot->hotplug_slot);
193 } 195 }
@@ -244,7 +246,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot)
244 246
245 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); 247 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
246 248
247 return shpchp_enable_slot(slot); 249 return shpchp_sysfs_enable_slot(slot);
248} 250}
249 251
250static int disable_slot (struct hotplug_slot *hotplug_slot) 252static int disable_slot (struct hotplug_slot *hotplug_slot)
@@ -253,7 +255,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot)
253 255
254 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); 256 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
255 257
256 return shpchp_disable_slot(slot); 258 return shpchp_sysfs_disable_slot(slot);
257} 259}
258 260
259static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) 261static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 2411f3bd08da..10f3257b18a7 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -37,6 +37,8 @@
37#include "shpchp.h" 37#include "shpchp.h"
38 38
39static void interrupt_event_handler(void *data); 39static void interrupt_event_handler(void *data);
40static int shpchp_enable_slot(struct slot *p_slot);
41static int shpchp_disable_slot(struct slot *p_slot);
40 42
41static int queue_interrupt_event(struct slot *p_slot, u32 event_type) 43static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
42{ 44{
@@ -50,7 +52,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
50 info->p_slot = p_slot; 52 info->p_slot = p_slot;
51 INIT_WORK(&info->work, interrupt_event_handler, info); 53 INIT_WORK(&info->work, interrupt_event_handler, info);
52 54
53 queue_work(shpchp_wq, &info->work); 55 schedule_work(&info->work);
54 56
55 return 0; 57 return 0;
56} 58}
@@ -73,24 +75,6 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
73 info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); 75 info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
74 event_type = INT_BUTTON_PRESS; 76 event_type = INT_BUTTON_PRESS;
75 77
76 if ((p_slot->state == BLINKINGON_STATE)
77 || (p_slot->state == BLINKINGOFF_STATE)) {
78 /* Cancel if we are still blinking; this means that we press the
79 * attention again before the 5 sec. limit expires to cancel hot-add
80 * or hot-remove
81 */
82 event_type = INT_BUTTON_CANCEL;
83 info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
84 } else if ((p_slot->state == POWERON_STATE)
85 || (p_slot->state == POWEROFF_STATE)) {
86 /* Ignore if the slot is on power-on or power-off state; this
87 * means that the previous attention button action to hot-add or
88 * hot-remove is undergoing
89 */
90 event_type = INT_BUTTON_IGNORE;
91 info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
92 }
93
94 queue_interrupt_event(p_slot, event_type); 78 queue_interrupt_event(p_slot, event_type);
95 79
96 return 0; 80 return 0;
@@ -492,6 +476,11 @@ static int remove_board(struct slot *p_slot)
492} 476}
493 477
494 478
479struct pushbutton_work_info {
480 struct slot *p_slot;
481 struct work_struct work;
482};
483
495/** 484/**
496 * shpchp_pushbutton_thread 485 * shpchp_pushbutton_thread
497 * 486 *
@@ -499,22 +488,61 @@ static int remove_board(struct slot *p_slot)
499 * Handles all pending events and exits. 488 * Handles all pending events and exits.
500 * 489 *
501 */ 490 */
502void shpchp_pushbutton_thread(void *data) 491static void shpchp_pushbutton_thread(void *data)
503{ 492{
504 struct slot *p_slot = data; 493 struct pushbutton_work_info *info = data;
505 u8 getstatus; 494 struct slot *p_slot = info->p_slot;
506 495
507 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 496 mutex_lock(&p_slot->lock);
508 if (getstatus) { 497 switch (p_slot->state) {
509 p_slot->state = POWEROFF_STATE; 498 case POWEROFF_STATE:
499 mutex_unlock(&p_slot->lock);
510 shpchp_disable_slot(p_slot); 500 shpchp_disable_slot(p_slot);
501 mutex_lock(&p_slot->lock);
511 p_slot->state = STATIC_STATE; 502 p_slot->state = STATIC_STATE;
512 } else { 503 break;
513 p_slot->state = POWERON_STATE; 504 case POWERON_STATE:
505 mutex_unlock(&p_slot->lock);
514 if (shpchp_enable_slot(p_slot)) 506 if (shpchp_enable_slot(p_slot))
515 p_slot->hpc_ops->green_led_off(p_slot); 507 p_slot->hpc_ops->green_led_off(p_slot);
508 mutex_lock(&p_slot->lock);
516 p_slot->state = STATIC_STATE; 509 p_slot->state = STATIC_STATE;
510 break;
511 default:
512 break;
513 }
514 mutex_unlock(&p_slot->lock);
515
516 kfree(info);
517}
518
519void queue_pushbutton_work(void *data)
520{
521 struct slot *p_slot = data;
522 struct pushbutton_work_info *info;
523
524 info = kmalloc(sizeof(*info), GFP_KERNEL);
525 if (!info) {
526 err("%s: Cannot allocate memory\n", __FUNCTION__);
527 return;
528 }
529 info->p_slot = p_slot;
530 INIT_WORK(&info->work, shpchp_pushbutton_thread, info);
531
532 mutex_lock(&p_slot->lock);
533 switch (p_slot->state) {
534 case BLINKINGOFF_STATE:
535 p_slot->state = POWEROFF_STATE;
536 break;
537 case BLINKINGON_STATE:
538 p_slot->state = POWERON_STATE;
539 break;
540 default:
541 goto out;
517 } 542 }
543 queue_work(shpchp_wq, &info->work);
544 out:
545 mutex_unlock(&p_slot->lock);
518} 546}
519 547
520static int update_slot_info (struct slot *slot) 548static int update_slot_info (struct slot *slot)
@@ -536,34 +564,15 @@ static int update_slot_info (struct slot *slot)
536 return result; 564 return result;
537} 565}
538 566
539static void interrupt_event_handler(void *data) 567/*
568 * Note: This function must be called with slot->lock held
569 */
570static void handle_button_press_event(struct slot *p_slot)
540{ 571{
541 struct event_info *info = data;
542 struct slot *p_slot = info->p_slot;
543 u8 getstatus; 572 u8 getstatus;
544 573
545 switch (info->event_type) { 574 switch (p_slot->state) {
546 case INT_BUTTON_CANCEL: 575 case STATIC_STATE:
547 dbg("%s: button cancel\n", __FUNCTION__);
548 cancel_delayed_work(&p_slot->work);
549 switch (p_slot->state) {
550 case BLINKINGOFF_STATE:
551 p_slot->hpc_ops->green_led_on(p_slot);
552 p_slot->hpc_ops->set_attention_status(p_slot, 0);
553 break;
554 case BLINKINGON_STATE:
555 p_slot->hpc_ops->green_led_off(p_slot);
556 p_slot->hpc_ops->set_attention_status(p_slot, 0);
557 break;
558 default:
559 warn("Not a valid state\n");
560 return;
561 }
562 info(msg_button_cancel, p_slot->number);
563 p_slot->state = STATIC_STATE;
564 break;
565 case INT_BUTTON_PRESS:
566 dbg("%s: Button pressed\n", __FUNCTION__);
567 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 576 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
568 if (getstatus) { 577 if (getstatus) {
569 p_slot->state = BLINKINGOFF_STATE; 578 p_slot->state = BLINKINGOFF_STATE;
@@ -576,7 +585,51 @@ static void interrupt_event_handler(void *data)
576 p_slot->hpc_ops->green_led_blink(p_slot); 585 p_slot->hpc_ops->green_led_blink(p_slot);
577 p_slot->hpc_ops->set_attention_status(p_slot, 0); 586 p_slot->hpc_ops->set_attention_status(p_slot, 0);
578 587
579 queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ); 588 schedule_delayed_work(&p_slot->work, 5*HZ);
589 break;
590 case BLINKINGOFF_STATE:
591 case BLINKINGON_STATE:
592 /*
593 * Cancel if we are still blinking; this means that we
594 * press the attention again before the 5 sec. limit
595 * expires to cancel hot-add or hot-remove
596 */
597 info("Button cancel on Slot(%s)\n", p_slot->name);
598 dbg("%s: button cancel\n", __FUNCTION__);
599 cancel_delayed_work(&p_slot->work);
600 if (p_slot->state == BLINKINGOFF_STATE)
601 p_slot->hpc_ops->green_led_on(p_slot);
602 else
603 p_slot->hpc_ops->green_led_off(p_slot);
604 p_slot->hpc_ops->set_attention_status(p_slot, 0);
605 info(msg_button_cancel, p_slot->number);
606 p_slot->state = STATIC_STATE;
607 break;
608 case POWEROFF_STATE:
609 case POWERON_STATE:
610 /*
611 * Ignore if the slot is on power-on or power-off state;
612 * this means that the previous attention button action
613 * to hot-add or hot-remove is undergoing
614 */
615 info("Button ignore on Slot(%s)\n", p_slot->name);
616 update_slot_info(p_slot);
617 break;
618 default:
619 warn("Not a valid state\n");
620 break;
621 }
622}
623
624static void interrupt_event_handler(void *data)
625{
626 struct event_info *info = data;
627 struct slot *p_slot = info->p_slot;
628
629 mutex_lock(&p_slot->lock);
630 switch (info->event_type) {
631 case INT_BUTTON_PRESS:
632 handle_button_press_event(p_slot);
580 break; 633 break;
581 case INT_POWER_FAULT: 634 case INT_POWER_FAULT:
582 dbg("%s: power fault\n", __FUNCTION__); 635 dbg("%s: power fault\n", __FUNCTION__);
@@ -587,12 +640,13 @@ static void interrupt_event_handler(void *data)
587 update_slot_info(p_slot); 640 update_slot_info(p_slot);
588 break; 641 break;
589 } 642 }
643 mutex_unlock(&p_slot->lock);
590 644
591 kfree(info); 645 kfree(info);
592} 646}
593 647
594 648
595int shpchp_enable_slot (struct slot *p_slot) 649static int shpchp_enable_slot (struct slot *p_slot)
596{ 650{
597 u8 getstatus = 0; 651 u8 getstatus = 0;
598 int rc, retval = -ENODEV; 652 int rc, retval = -ENODEV;
@@ -647,7 +701,7 @@ int shpchp_enable_slot (struct slot *p_slot)
647} 701}
648 702
649 703
650int shpchp_disable_slot (struct slot *p_slot) 704static int shpchp_disable_slot (struct slot *p_slot)
651{ 705{
652 u8 getstatus = 0; 706 u8 getstatus = 0;
653 int rc, retval = -ENODEV; 707 int rc, retval = -ENODEV;
@@ -681,3 +735,66 @@ int shpchp_disable_slot (struct slot *p_slot)
681 return retval; 735 return retval;
682} 736}
683 737
738int shpchp_sysfs_enable_slot(struct slot *p_slot)
739{
740 int retval = -ENODEV;
741
742 mutex_lock(&p_slot->lock);
743 switch (p_slot->state) {
744 case BLINKINGON_STATE:
745 cancel_delayed_work(&p_slot->work);
746 case STATIC_STATE:
747 p_slot->state = POWERON_STATE;
748 mutex_unlock(&p_slot->lock);
749 retval = shpchp_enable_slot(p_slot);
750 mutex_lock(&p_slot->lock);
751 p_slot->state = STATIC_STATE;
752 break;
753 case POWERON_STATE:
754 info("Slot %s is already in powering on state\n",
755 p_slot->name);
756 break;
757 case BLINKINGOFF_STATE:
758 case POWEROFF_STATE:
759 info("Already enabled on slot %s\n", p_slot->name);
760 break;
761 default:
762 err("Not a valid state on slot %s\n", p_slot->name);
763 break;
764 }
765 mutex_unlock(&p_slot->lock);
766
767 return retval;
768}
769
770int shpchp_sysfs_disable_slot(struct slot *p_slot)
771{
772 int retval = -ENODEV;
773
774 mutex_lock(&p_slot->lock);
775 switch (p_slot->state) {
776 case BLINKINGOFF_STATE:
777 cancel_delayed_work(&p_slot->work);
778 case STATIC_STATE:
779 p_slot->state = POWEROFF_STATE;
780 mutex_unlock(&p_slot->lock);
781 retval = shpchp_disable_slot(p_slot);
782 mutex_lock(&p_slot->lock);
783 p_slot->state = STATIC_STATE;
784 break;
785 case POWEROFF_STATE:
786 info("Slot %s is already in powering off state\n",
787 p_slot->name);
788 break;
789 case BLINKINGON_STATE:
790 case POWERON_STATE:
791 info("Already disabled on slot %s\n", p_slot->name);
792 break;
793 default:
794 err("Not a valid state on slot %s\n", p_slot->name);
795 break;
796 }
797 mutex_unlock(&p_slot->lock);
798
799 return retval;
800}