Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kenji Kaneshige and committed by
Greg Kroah-Hartman
f4778364 adf809d0

+102 -90
+1
drivers/pci/hotplug/pciehp.h
··· 103 103 u8 cap_base; 104 104 struct timer_list poll_timer; 105 105 volatile int cmd_busy; 106 + spinlock_t lock; 106 107 }; 107 108 108 109 #define INT_BUTTON_IGNORE 0
+101 -90
drivers/pci/hotplug/pciehp_hpc.c
··· 275 275 return retval; 276 276 } 277 277 278 - static 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 + */ 284 + static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) 279 285 { 280 286 struct controller *ctrl = slot->ctrl; 281 287 int retval = 0; 282 288 u16 slot_status; 289 + u16 slot_ctrl; 290 + unsigned long flags; 283 291 284 292 DBG_ENTER_ROUTINE 285 293 ··· 307 299 __FUNCTION__); 308 300 } 309 301 310 - ctrl->cmd_busy = 1; 311 - retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE)); 302 + spin_lock_irqsave(&ctrl->lock, flags); 303 + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 312 304 if (retval) { 313 - err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); 314 - goto out; 305 + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 306 + goto out_spin_unlock; 315 307 } 308 + 309 + slot_ctrl &= ~mask; 310 + slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE); 311 + 312 + ctrl->cmd_busy = 1; 313 + retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); 314 + if (retval) 315 + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); 316 + 317 + out_spin_unlock: 318 + spin_unlock_irqrestore(&ctrl->lock, flags); 316 319 317 320 /* 318 321 * Wait for command completion. 319 322 */ 320 - retval = pcie_wait_cmd(ctrl); 323 + if (!retval) 324 + retval = pcie_wait_cmd(ctrl); 321 325 out: 322 326 mutex_unlock(&ctrl->ctrl_lock); 323 327 DBG_LEAVE_ROUTINE ··· 522 502 523 503 static int hpc_toggle_emi(struct slot *slot) 524 504 { 525 - struct controller *ctrl = slot->ctrl; 526 - u16 slot_cmd = 0; 527 - u16 slot_ctrl; 528 - int rc = 0; 505 + u16 slot_cmd; 506 + u16 cmd_mask; 507 + int rc; 529 508 530 509 DBG_ENTER_ROUTINE 531 510 532 - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 533 - if (rc) { 534 - err("%s : hp_register_read_word SLOT_CTRL failed\n", 535 - __FUNCTION__); 536 - return rc; 511 + slot_cmd = EMI_CTRL; 512 + cmd_mask = EMI_CTRL; 513 + if (!pciehp_poll_mode) { 514 + slot_cmd = slot_cmd | HP_INTR_ENABLE; 515 + cmd_mask = cmd_mask | HP_INTR_ENABLE; 537 516 } 538 517 539 - slot_cmd = (slot_ctrl | EMI_CTRL); 540 - if (!pciehp_poll_mode) 541 - slot_cmd = slot_cmd | HP_INTR_ENABLE; 542 - 543 - pcie_write_cmd(slot, slot_cmd); 518 + rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); 544 519 slot->last_emi_toggle = get_seconds(); 545 520 DBG_LEAVE_ROUTINE 546 521 return rc; ··· 544 529 static int hpc_set_attention_status(struct slot *slot, u8 value) 545 530 { 546 531 struct controller *ctrl = slot->ctrl; 547 - u16 slot_cmd = 0; 548 - u16 slot_ctrl; 549 - int rc = 0; 532 + u16 slot_cmd; 533 + u16 cmd_mask; 534 + int rc; 550 535 551 536 DBG_ENTER_ROUTINE 552 537 553 - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 554 - if (rc) { 555 - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 556 - return rc; 557 - } 558 - 538 + cmd_mask = ATTN_LED_CTRL; 559 539 switch (value) { 560 540 case 0 : /* turn off */ 561 - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0; 541 + slot_cmd = 0x00C0; 562 542 break; 563 543 case 1: /* turn on */ 564 - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040; 544 + slot_cmd = 0x0040; 565 545 break; 566 546 case 2: /* turn blink */ 567 - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080; 547 + slot_cmd = 0x0080; 568 548 break; 569 549 default: 570 550 return -1; 571 551 } 572 - if (!pciehp_poll_mode) 573 - slot_cmd = slot_cmd | HP_INTR_ENABLE; 552 + if (!pciehp_poll_mode) { 553 + slot_cmd = slot_cmd | HP_INTR_ENABLE; 554 + cmd_mask = cmd_mask | HP_INTR_ENABLE; 555 + } 574 556 575 - pcie_write_cmd(slot, slot_cmd); 557 + rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); 576 558 dbg("%s: SLOTCTRL %x write cmd %x\n", 577 559 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); 578 560 ··· 582 570 { 583 571 struct controller *ctrl = slot->ctrl; 584 572 u16 slot_cmd; 585 - u16 slot_ctrl; 586 - int rc = 0; 573 + u16 cmd_mask; 587 574 588 575 DBG_ENTER_ROUTINE 589 576 590 - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 591 - if (rc) { 592 - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 593 - return; 577 + slot_cmd = 0x0100; 578 + cmd_mask = PWR_LED_CTRL; 579 + if (!pciehp_poll_mode) { 580 + slot_cmd = slot_cmd | HP_INTR_ENABLE; 581 + cmd_mask = cmd_mask | HP_INTR_ENABLE; 594 582 } 595 - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; 596 - if (!pciehp_poll_mode) 597 - slot_cmd = slot_cmd | HP_INTR_ENABLE; 598 583 599 - pcie_write_cmd(slot, slot_cmd); 584 + pcie_write_cmd(slot, slot_cmd, cmd_mask); 600 585 601 586 dbg("%s: SLOTCTRL %x write cmd %x\n", 602 587 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); ··· 605 596 { 606 597 struct controller *ctrl = slot->ctrl; 607 598 u16 slot_cmd; 608 - u16 slot_ctrl; 609 - int rc = 0; 599 + u16 cmd_mask; 610 600 611 601 DBG_ENTER_ROUTINE 612 602 613 - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 614 - if (rc) { 615 - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 616 - return; 603 + slot_cmd = 0x0300; 604 + cmd_mask = PWR_LED_CTRL; 605 + if (!pciehp_poll_mode) { 606 + slot_cmd = slot_cmd | HP_INTR_ENABLE; 607 + cmd_mask = cmd_mask | HP_INTR_ENABLE; 617 608 } 618 609 619 - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300; 620 - 621 - if (!pciehp_poll_mode) 622 - slot_cmd = slot_cmd | HP_INTR_ENABLE; 623 - pcie_write_cmd(slot, slot_cmd); 610 + pcie_write_cmd(slot, slot_cmd, cmd_mask); 624 611 dbg("%s: SLOTCTRL %x write cmd %x\n", 625 612 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); 626 613 ··· 628 623 { 629 624 struct controller *ctrl = slot->ctrl; 630 625 u16 slot_cmd; 631 - u16 slot_ctrl; 632 - int rc = 0; 626 + u16 cmd_mask; 633 627 634 628 DBG_ENTER_ROUTINE 635 629 636 - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 637 - if (rc) { 638 - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 639 - return; 630 + slot_cmd = 0x0200; 631 + cmd_mask = PWR_LED_CTRL; 632 + if (!pciehp_poll_mode) { 633 + slot_cmd = slot_cmd | HP_INTR_ENABLE; 634 + cmd_mask = cmd_mask | HP_INTR_ENABLE; 640 635 } 641 636 642 - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; 643 - 644 - if (!pciehp_poll_mode) 645 - slot_cmd = slot_cmd | HP_INTR_ENABLE; 646 - pcie_write_cmd(slot, slot_cmd); 637 + pcie_write_cmd(slot, slot_cmd, cmd_mask); 647 638 648 639 dbg("%s: SLOTCTRL %x write cmd %x\n", 649 640 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); ··· 670 669 { 671 670 struct controller *ctrl = slot->ctrl; 672 671 u16 slot_cmd; 673 - u16 slot_ctrl, slot_status; 672 + u16 cmd_mask; 673 + u16 slot_status; 674 674 int retval = 0; 675 675 676 676 DBG_ENTER_ROUTINE ··· 694 692 } 695 693 } 696 694 697 - retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 698 - if (retval) { 699 - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 700 - return retval; 701 - } 702 - 703 - slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; 704 - 695 + slot_cmd = POWER_ON; 696 + cmd_mask = PWR_CTRL; 705 697 /* Enable detection that we turned off at slot power-off time */ 706 - if (!pciehp_poll_mode) 698 + if (!pciehp_poll_mode) { 707 699 slot_cmd = slot_cmd | 708 700 PWR_FAULT_DETECT_ENABLE | 709 701 MRL_DETECT_ENABLE | 710 702 PRSN_DETECT_ENABLE | 711 703 HP_INTR_ENABLE; 704 + cmd_mask = cmd_mask | 705 + PWR_FAULT_DETECT_ENABLE | 706 + MRL_DETECT_ENABLE | 707 + PRSN_DETECT_ENABLE | 708 + HP_INTR_ENABLE; 709 + } 712 710 713 - retval = pcie_write_cmd(slot, slot_cmd); 711 + retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); 714 712 715 713 if (retval) { 716 714 err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); ··· 728 726 { 729 727 struct controller *ctrl = slot->ctrl; 730 728 u16 slot_cmd; 731 - u16 slot_ctrl; 729 + u16 cmd_mask; 732 730 int retval = 0; 733 731 734 732 DBG_ENTER_ROUTINE 735 733 736 734 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); 737 735 738 - retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 739 - if (retval) { 740 - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 741 - return retval; 742 - } 743 - 744 - slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; 745 - 736 + slot_cmd = POWER_OFF; 737 + cmd_mask = PWR_CTRL; 746 738 /* 747 739 * If we get MRL or presence detect interrupts now, the isr 748 740 * will notice the sticky power-fault bit too and issue power ··· 744 748 * of command completions, since the power-fault bit remains on 745 749 * till the slot is powered on again. 746 750 */ 747 - if (!pciehp_poll_mode) 751 + if (!pciehp_poll_mode) { 748 752 slot_cmd = (slot_cmd & 749 753 ~PWR_FAULT_DETECT_ENABLE & 750 754 ~MRL_DETECT_ENABLE & 751 755 ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE; 756 + cmd_mask = cmd_mask | 757 + PWR_FAULT_DETECT_ENABLE | 758 + MRL_DETECT_ENABLE | 759 + PRSN_DETECT_ENABLE | 760 + HP_INTR_ENABLE; 761 + } 752 762 753 - retval = pcie_write_cmd(slot, slot_cmd); 754 - 763 + retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); 755 764 if (retval) { 756 765 err("%s: Write command failed!\n", __FUNCTION__); 757 766 return -1; ··· 776 775 u16 temp_word; 777 776 int hp_slot = 0; /* only 1 slot per PCI Express port */ 778 777 int rc = 0; 778 + unsigned long flags; 779 779 780 780 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 781 781 if (rc) { ··· 796 794 dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); 797 795 /* Mask Hot-plug Interrupt Enable */ 798 796 if (!pciehp_poll_mode) { 797 + spin_lock_irqsave(&ctrl->lock, flags); 799 798 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 800 799 if (rc) { 801 800 err("%s: Cannot read SLOT_CTRL register\n", 802 801 __FUNCTION__); 802 + spin_unlock_irqrestore(&ctrl->lock, flags); 803 803 return IRQ_NONE; 804 804 } 805 805 ··· 812 808 if (rc) { 813 809 err("%s: Cannot write to SLOTCTRL register\n", 814 810 __FUNCTION__); 811 + spin_unlock_irqrestore(&ctrl->lock, flags); 815 812 return IRQ_NONE; 816 813 } 814 + spin_unlock_irqrestore(&ctrl->lock, flags); 817 815 818 816 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 819 817 if (rc) { ··· 865 859 } 866 860 /* Unmask Hot-plug Interrupt Enable */ 867 861 if (!pciehp_poll_mode) { 862 + spin_lock_irqsave(&ctrl->lock, flags); 868 863 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 869 864 if (rc) { 870 865 err("%s: Cannot read SLOTCTRL register\n", 871 866 __FUNCTION__); 867 + spin_unlock_irqrestore(&ctrl->lock, flags); 872 868 return IRQ_NONE; 873 869 } 874 870 ··· 881 873 if (rc) { 882 874 err("%s: Cannot write to SLOTCTRL register\n", 883 875 __FUNCTION__); 876 + spin_unlock_irqrestore(&ctrl->lock, flags); 884 877 return IRQ_NONE; 885 878 } 879 + spin_unlock_irqrestore(&ctrl->lock, flags); 886 880 887 881 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 888 882 if (rc) { ··· 1247 1237 1248 1238 mutex_init(&ctrl->crit_sect); 1249 1239 mutex_init(&ctrl->ctrl_lock); 1240 + spin_lock_init(&ctrl->lock); 1250 1241 1251 1242 /* setup wait queue */ 1252 1243 init_waitqueue_head(&ctrl->queue);