aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2007-05-31 12:43:34 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:02:08 -0400
commitf477836457730a2b925f625023ec4e5bf11015be (patch)
tree178c8e7efd7a3f8f0220d3da537d649f4cb1278f
parentadf809d01043d8808e47db2d35fc07b53062884e (diff)
PCI: hotplug: pciehp: Fix possible race condition in writing slot
The slot control register is modified as follows: (1) Read the register value (2) Change the value (3) Write the value to the register Those must be done atomically, otherwise writing to control register would cause an unexpected result. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/pci/hotplug/pciehp.h1
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c191
2 files changed, 102 insertions, 90 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index ccc57627201e..7959c222dc24 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -103,6 +103,7 @@ struct controller {
103 u8 cap_base; 103 u8 cap_base;
104 struct timer_list poll_timer; 104 struct timer_list poll_timer;
105 volatile int cmd_busy; 105 volatile int cmd_busy;
106 spinlock_t lock;
106}; 107};
107 108
108#define INT_BUTTON_IGNORE 0 109#define INT_BUTTON_IGNORE 0
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 9aac6a87eb53..016eea94a8a5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -275,11 +275,19 @@ static inline int pcie_wait_cmd(struct controller *ctrl)
275 return retval; 275 return retval;
276} 276}
277 277
278static int pcie_write_cmd(struct slot *slot, u16 cmd) 278/**
279 * pcie_write_cmd - Issue controller command
280 * @slot: slot to which the command is issued
281 * @cmd: command value written to slot control register
282 * @mask: bitmask of slot control register to be modified
283 */
284static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
279{ 285{
280 struct controller *ctrl = slot->ctrl; 286 struct controller *ctrl = slot->ctrl;
281 int retval = 0; 287 int retval = 0;
282 u16 slot_status; 288 u16 slot_status;
289 u16 slot_ctrl;
290 unsigned long flags;
283 291
284 DBG_ENTER_ROUTINE 292 DBG_ENTER_ROUTINE
285 293
@@ -299,17 +307,29 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd)
299 __FUNCTION__); 307 __FUNCTION__);
300 } 308 }
301 309
302 ctrl->cmd_busy = 1; 310 spin_lock_irqsave(&ctrl->lock, flags);
303 retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE)); 311 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
304 if (retval) { 312 if (retval) {
305 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); 313 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
306 goto out; 314 goto out_spin_unlock;
307 } 315 }
308 316
317 slot_ctrl &= ~mask;
318 slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE);
319
320 ctrl->cmd_busy = 1;
321 retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
322 if (retval)
323 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
324
325 out_spin_unlock:
326 spin_unlock_irqrestore(&ctrl->lock, flags);
327
309 /* 328 /*
310 * Wait for command completion. 329 * Wait for command completion.
311 */ 330 */
312 retval = pcie_wait_cmd(ctrl); 331 if (!retval)
332 retval = pcie_wait_cmd(ctrl);
313 out: 333 out:
314 mutex_unlock(&ctrl->ctrl_lock); 334 mutex_unlock(&ctrl->ctrl_lock);
315 DBG_LEAVE_ROUTINE 335 DBG_LEAVE_ROUTINE
@@ -502,25 +522,20 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
502 522
503static int hpc_toggle_emi(struct slot *slot) 523static int hpc_toggle_emi(struct slot *slot)
504{ 524{
505 struct controller *ctrl = slot->ctrl; 525 u16 slot_cmd;
506 u16 slot_cmd = 0; 526 u16 cmd_mask;
507 u16 slot_ctrl; 527 int rc;
508 int rc = 0;
509 528
510 DBG_ENTER_ROUTINE 529 DBG_ENTER_ROUTINE
511 530
512 rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 531 slot_cmd = EMI_CTRL;
513 if (rc) { 532 cmd_mask = EMI_CTRL;
514 err("%s : hp_register_read_word SLOT_CTRL failed\n", 533 if (!pciehp_poll_mode) {
515 __FUNCTION__);
516 return rc;
517 }
518
519 slot_cmd = (slot_ctrl | EMI_CTRL);
520 if (!pciehp_poll_mode)
521 slot_cmd = slot_cmd | HP_INTR_ENABLE; 534 slot_cmd = slot_cmd | HP_INTR_ENABLE;
535 cmd_mask = cmd_mask | HP_INTR_ENABLE;
536 }
522 537
523 pcie_write_cmd(slot, slot_cmd); 538 rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
524 slot->last_emi_toggle = get_seconds(); 539 slot->last_emi_toggle = get_seconds();
525 DBG_LEAVE_ROUTINE 540 DBG_LEAVE_ROUTINE
526 return rc; 541 return rc;
@@ -529,35 +544,32 @@ static int hpc_toggle_emi(struct slot *slot)
529static int hpc_set_attention_status(struct slot *slot, u8 value) 544static int hpc_set_attention_status(struct slot *slot, u8 value)
530{ 545{
531 struct controller *ctrl = slot->ctrl; 546 struct controller *ctrl = slot->ctrl;
532 u16 slot_cmd = 0; 547 u16 slot_cmd;
533 u16 slot_ctrl; 548 u16 cmd_mask;
534 int rc = 0; 549 int rc;
535 550
536 DBG_ENTER_ROUTINE 551 DBG_ENTER_ROUTINE
537 552
538 rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 553 cmd_mask = ATTN_LED_CTRL;
539 if (rc) {
540 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
541 return rc;
542 }
543
544 switch (value) { 554 switch (value) {
545 case 0 : /* turn off */ 555 case 0 : /* turn off */
546 slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0; 556 slot_cmd = 0x00C0;
547 break; 557 break;
548 case 1: /* turn on */ 558 case 1: /* turn on */
549 slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040; 559 slot_cmd = 0x0040;
550 break; 560 break;
551 case 2: /* turn blink */ 561 case 2: /* turn blink */
552 slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080; 562 slot_cmd = 0x0080;
553 break; 563 break;
554 default: 564 default:
555 return -1; 565 return -1;
556 } 566 }
557 if (!pciehp_poll_mode) 567 if (!pciehp_poll_mode) {
558 slot_cmd = slot_cmd | HP_INTR_ENABLE; 568 slot_cmd = slot_cmd | HP_INTR_ENABLE;
569 cmd_mask = cmd_mask | HP_INTR_ENABLE;
570 }
559 571
560 pcie_write_cmd(slot, slot_cmd); 572 rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
561 dbg("%s: SLOTCTRL %x write cmd %x\n", 573 dbg("%s: SLOTCTRL %x write cmd %x\n",
562 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); 574 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
563 575
@@ -570,21 +582,18 @@ static void hpc_set_green_led_on(struct slot *slot)
570{ 582{
571 struct controller *ctrl = slot->ctrl; 583 struct controller *ctrl = slot->ctrl;
572 u16 slot_cmd; 584 u16 slot_cmd;
573 u16 slot_ctrl; 585 u16 cmd_mask;
574 int rc = 0;
575 586
576 DBG_ENTER_ROUTINE 587 DBG_ENTER_ROUTINE
577 588
578 rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 589 slot_cmd = 0x0100;
579 if (rc) { 590 cmd_mask = PWR_LED_CTRL;
580 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 591 if (!pciehp_poll_mode) {
581 return; 592 slot_cmd = slot_cmd | HP_INTR_ENABLE;
593 cmd_mask = cmd_mask | HP_INTR_ENABLE;
582 } 594 }
583 slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
584 if (!pciehp_poll_mode)
585 slot_cmd = slot_cmd | HP_INTR_ENABLE;
586 595
587 pcie_write_cmd(slot, slot_cmd); 596 pcie_write_cmd(slot, slot_cmd, cmd_mask);
588 597
589 dbg("%s: SLOTCTRL %x write cmd %x\n", 598 dbg("%s: SLOTCTRL %x write cmd %x\n",
590 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); 599 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -596,22 +605,18 @@ static void hpc_set_green_led_off(struct slot *slot)
596{ 605{
597 struct controller *ctrl = slot->ctrl; 606 struct controller *ctrl = slot->ctrl;
598 u16 slot_cmd; 607 u16 slot_cmd;
599 u16 slot_ctrl; 608 u16 cmd_mask;
600 int rc = 0;
601 609
602 DBG_ENTER_ROUTINE 610 DBG_ENTER_ROUTINE
603 611
604 rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 612 slot_cmd = 0x0300;
605 if (rc) { 613 cmd_mask = PWR_LED_CTRL;
606 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 614 if (!pciehp_poll_mode) {
607 return; 615 slot_cmd = slot_cmd | HP_INTR_ENABLE;
616 cmd_mask = cmd_mask | HP_INTR_ENABLE;
608 } 617 }
609 618
610 slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300; 619 pcie_write_cmd(slot, slot_cmd, cmd_mask);
611
612 if (!pciehp_poll_mode)
613 slot_cmd = slot_cmd | HP_INTR_ENABLE;
614 pcie_write_cmd(slot, slot_cmd);
615 dbg("%s: SLOTCTRL %x write cmd %x\n", 620 dbg("%s: SLOTCTRL %x write cmd %x\n",
616 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); 621 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
617 622
@@ -623,22 +628,18 @@ static void hpc_set_green_led_blink(struct slot *slot)
623{ 628{
624 struct controller *ctrl = slot->ctrl; 629 struct controller *ctrl = slot->ctrl;
625 u16 slot_cmd; 630 u16 slot_cmd;
626 u16 slot_ctrl; 631 u16 cmd_mask;
627 int rc = 0;
628 632
629 DBG_ENTER_ROUTINE 633 DBG_ENTER_ROUTINE
630 634
631 rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 635 slot_cmd = 0x0200;
632 if (rc) { 636 cmd_mask = PWR_LED_CTRL;
633 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 637 if (!pciehp_poll_mode) {
634 return; 638 slot_cmd = slot_cmd | HP_INTR_ENABLE;
639 cmd_mask = cmd_mask | HP_INTR_ENABLE;
635 } 640 }
636 641
637 slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; 642 pcie_write_cmd(slot, slot_cmd, cmd_mask);
638
639 if (!pciehp_poll_mode)
640 slot_cmd = slot_cmd | HP_INTR_ENABLE;
641 pcie_write_cmd(slot, slot_cmd);
642 643
643 dbg("%s: SLOTCTRL %x write cmd %x\n", 644 dbg("%s: SLOTCTRL %x write cmd %x\n",
644 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); 645 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -669,7 +670,8 @@ static int hpc_power_on_slot(struct slot * slot)
669{ 670{
670 struct controller *ctrl = slot->ctrl; 671 struct controller *ctrl = slot->ctrl;
671 u16 slot_cmd; 672 u16 slot_cmd;
672 u16 slot_ctrl, slot_status; 673 u16 cmd_mask;
674 u16 slot_status;
673 int retval = 0; 675 int retval = 0;
674 676
675 DBG_ENTER_ROUTINE 677 DBG_ENTER_ROUTINE
@@ -692,23 +694,23 @@ static int hpc_power_on_slot(struct slot * slot)
692 } 694 }
693 } 695 }
694 696
695 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 697 slot_cmd = POWER_ON;
696 if (retval) { 698 cmd_mask = PWR_CTRL;
697 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
698 return retval;
699 }
700
701 slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
702
703 /* Enable detection that we turned off at slot power-off time */ 699 /* Enable detection that we turned off at slot power-off time */
704 if (!pciehp_poll_mode) 700 if (!pciehp_poll_mode) {
705 slot_cmd = slot_cmd | 701 slot_cmd = slot_cmd |
706 PWR_FAULT_DETECT_ENABLE | 702 PWR_FAULT_DETECT_ENABLE |
707 MRL_DETECT_ENABLE | 703 MRL_DETECT_ENABLE |
708 PRSN_DETECT_ENABLE | 704 PRSN_DETECT_ENABLE |
709 HP_INTR_ENABLE; 705 HP_INTR_ENABLE;
706 cmd_mask = cmd_mask |
707 PWR_FAULT_DETECT_ENABLE |
708 MRL_DETECT_ENABLE |
709 PRSN_DETECT_ENABLE |
710 HP_INTR_ENABLE;
711 }
710 712
711 retval = pcie_write_cmd(slot, slot_cmd); 713 retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
712 714
713 if (retval) { 715 if (retval) {
714 err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); 716 err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
@@ -726,21 +728,15 @@ static int hpc_power_off_slot(struct slot * slot)
726{ 728{
727 struct controller *ctrl = slot->ctrl; 729 struct controller *ctrl = slot->ctrl;
728 u16 slot_cmd; 730 u16 slot_cmd;
729 u16 slot_ctrl; 731 u16 cmd_mask;
730 int retval = 0; 732 int retval = 0;
731 733
732 DBG_ENTER_ROUTINE 734 DBG_ENTER_ROUTINE
733 735
734 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); 736 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
735 737
736 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 738 slot_cmd = POWER_OFF;
737 if (retval) { 739 cmd_mask = PWR_CTRL;
738 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
739 return retval;
740 }
741
742 slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
743
744 /* 740 /*
745 * If we get MRL or presence detect interrupts now, the isr 741 * If we get MRL or presence detect interrupts now, the isr
746 * will notice the sticky power-fault bit too and issue power 742 * will notice the sticky power-fault bit too and issue power
@@ -748,14 +744,19 @@ static int hpc_power_off_slot(struct slot * slot)
748 * of command completions, since the power-fault bit remains on 744 * of command completions, since the power-fault bit remains on
749 * till the slot is powered on again. 745 * till the slot is powered on again.
750 */ 746 */
751 if (!pciehp_poll_mode) 747 if (!pciehp_poll_mode) {
752 slot_cmd = (slot_cmd & 748 slot_cmd = (slot_cmd &
753 ~PWR_FAULT_DETECT_ENABLE & 749 ~PWR_FAULT_DETECT_ENABLE &
754 ~MRL_DETECT_ENABLE & 750 ~MRL_DETECT_ENABLE &
755 ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE; 751 ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
752 cmd_mask = cmd_mask |
753 PWR_FAULT_DETECT_ENABLE |
754 MRL_DETECT_ENABLE |
755 PRSN_DETECT_ENABLE |
756 HP_INTR_ENABLE;
757 }
756 758
757 retval = pcie_write_cmd(slot, slot_cmd); 759 retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
758
759 if (retval) { 760 if (retval) {
760 err("%s: Write command failed!\n", __FUNCTION__); 761 err("%s: Write command failed!\n", __FUNCTION__);
761 return -1; 762 return -1;
@@ -775,6 +776,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
775 u16 temp_word; 776 u16 temp_word;
776 int hp_slot = 0; /* only 1 slot per PCI Express port */ 777 int hp_slot = 0; /* only 1 slot per PCI Express port */
777 int rc = 0; 778 int rc = 0;
779 unsigned long flags;
778 780
779 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 781 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
780 if (rc) { 782 if (rc) {
@@ -794,10 +796,12 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
794 dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); 796 dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
795 /* Mask Hot-plug Interrupt Enable */ 797 /* Mask Hot-plug Interrupt Enable */
796 if (!pciehp_poll_mode) { 798 if (!pciehp_poll_mode) {
799 spin_lock_irqsave(&ctrl->lock, flags);
797 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 800 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
798 if (rc) { 801 if (rc) {
799 err("%s: Cannot read SLOT_CTRL register\n", 802 err("%s: Cannot read SLOT_CTRL register\n",
800 __FUNCTION__); 803 __FUNCTION__);
804 spin_unlock_irqrestore(&ctrl->lock, flags);
801 return IRQ_NONE; 805 return IRQ_NONE;
802 } 806 }
803 807
@@ -808,8 +812,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
808 if (rc) { 812 if (rc) {
809 err("%s: Cannot write to SLOTCTRL register\n", 813 err("%s: Cannot write to SLOTCTRL register\n",
810 __FUNCTION__); 814 __FUNCTION__);
815 spin_unlock_irqrestore(&ctrl->lock, flags);
811 return IRQ_NONE; 816 return IRQ_NONE;
812 } 817 }
818 spin_unlock_irqrestore(&ctrl->lock, flags);
813 819
814 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 820 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
815 if (rc) { 821 if (rc) {
@@ -859,10 +865,12 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
859 } 865 }
860 /* Unmask Hot-plug Interrupt Enable */ 866 /* Unmask Hot-plug Interrupt Enable */
861 if (!pciehp_poll_mode) { 867 if (!pciehp_poll_mode) {
868 spin_lock_irqsave(&ctrl->lock, flags);
862 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 869 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
863 if (rc) { 870 if (rc) {
864 err("%s: Cannot read SLOTCTRL register\n", 871 err("%s: Cannot read SLOTCTRL register\n",
865 __FUNCTION__); 872 __FUNCTION__);
873 spin_unlock_irqrestore(&ctrl->lock, flags);
866 return IRQ_NONE; 874 return IRQ_NONE;
867 } 875 }
868 876
@@ -873,8 +881,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
873 if (rc) { 881 if (rc) {
874 err("%s: Cannot write to SLOTCTRL register\n", 882 err("%s: Cannot write to SLOTCTRL register\n",
875 __FUNCTION__); 883 __FUNCTION__);
884 spin_unlock_irqrestore(&ctrl->lock, flags);
876 return IRQ_NONE; 885 return IRQ_NONE;
877 } 886 }
887 spin_unlock_irqrestore(&ctrl->lock, flags);
878 888
879 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 889 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
880 if (rc) { 890 if (rc) {
@@ -1237,6 +1247,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
1237 1247
1238 mutex_init(&ctrl->crit_sect); 1248 mutex_init(&ctrl->crit_sect);
1239 mutex_init(&ctrl->ctrl_lock); 1249 mutex_init(&ctrl->ctrl_lock);
1250 spin_lock_init(&ctrl->lock);
1240 1251
1241 /* setup wait queue */ 1252 /* setup wait queue */
1242 init_waitqueue_head(&ctrl->queue); 1253 init_waitqueue_head(&ctrl->queue);