aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_hpc.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-04-25 17:39:05 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-04-25 17:39:05 -0400
commitc27fb883dffe11aa4cb35ecea1fa1832ba45d4da (patch)
tree456adc0fe0b909acdf8382387c2ebfc6c2b8bfa9 /drivers/pci/hotplug/pciehp_hpc.c
parent2d32a9aed2e335d110fbb11985a9545b1f7219ab (diff)
pciehp: Fix wrong slot control register access
Current pciehp implementaion clears hotplug events without waiting for command completion. Because of this, events might not be cleared properly. To prevent this problem, we must use pciehp_write_cmd() to write to Slot Control register. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug/pciehp_hpc.c')
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c150
1 files changed, 38 insertions, 112 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 19eba2a2f746..7104a15e2661 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -242,13 +242,12 @@ static inline int pcie_wait_cmd(struct controller *ctrl)
242 242
243/** 243/**
244 * pcie_write_cmd - Issue controller command 244 * pcie_write_cmd - Issue controller command
245 * @slot: slot to which the command is issued 245 * @ctrl: controller to which the command is issued
246 * @cmd: command value written to slot control register 246 * @cmd: command value written to slot control register
247 * @mask: bitmask of slot control register to be modified 247 * @mask: bitmask of slot control register to be modified
248 */ 248 */
249static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) 249static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
250{ 250{
251 struct controller *ctrl = slot->ctrl;
252 int retval = 0; 251 int retval = 0;
253 u16 slot_status; 252 u16 slot_status;
254 u16 slot_ctrl; 253 u16 slot_ctrl;
@@ -468,7 +467,7 @@ static int hpc_toggle_emi(struct slot *slot)
468 cmd_mask = cmd_mask | HP_INTR_ENABLE; 467 cmd_mask = cmd_mask | HP_INTR_ENABLE;
469 } 468 }
470 469
471 rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); 470 rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);
472 slot->last_emi_toggle = get_seconds(); 471 slot->last_emi_toggle = get_seconds();
473 472
474 return rc; 473 return rc;
@@ -500,7 +499,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
500 cmd_mask = cmd_mask | HP_INTR_ENABLE; 499 cmd_mask = cmd_mask | HP_INTR_ENABLE;
501 } 500 }
502 501
503 rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); 502 rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
504 dbg("%s: SLOTCTRL %x write cmd %x\n", 503 dbg("%s: SLOTCTRL %x write cmd %x\n",
505 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); 504 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
506 505
@@ -520,7 +519,7 @@ static void hpc_set_green_led_on(struct slot *slot)
520 cmd_mask = cmd_mask | HP_INTR_ENABLE; 519 cmd_mask = cmd_mask | HP_INTR_ENABLE;
521 } 520 }
522 521
523 pcie_write_cmd(slot, slot_cmd, cmd_mask); 522 pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
524 523
525 dbg("%s: SLOTCTRL %x write cmd %x\n", 524 dbg("%s: SLOTCTRL %x write cmd %x\n",
526 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); 525 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -539,7 +538,7 @@ static void hpc_set_green_led_off(struct slot *slot)
539 cmd_mask = cmd_mask | HP_INTR_ENABLE; 538 cmd_mask = cmd_mask | HP_INTR_ENABLE;
540 } 539 }
541 540
542 pcie_write_cmd(slot, slot_cmd, cmd_mask); 541 pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
543 dbg("%s: SLOTCTRL %x write cmd %x\n", 542 dbg("%s: SLOTCTRL %x write cmd %x\n",
544 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); 543 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
545} 544}
@@ -557,7 +556,7 @@ static void hpc_set_green_led_blink(struct slot *slot)
557 cmd_mask = cmd_mask | HP_INTR_ENABLE; 556 cmd_mask = cmd_mask | HP_INTR_ENABLE;
558 } 557 }
559 558
560 pcie_write_cmd(slot, slot_cmd, cmd_mask); 559 pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
561 560
562 dbg("%s: SLOTCTRL %x write cmd %x\n", 561 dbg("%s: SLOTCTRL %x write cmd %x\n",
563 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); 562 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -620,7 +619,7 @@ static int hpc_power_on_slot(struct slot * slot)
620 HP_INTR_ENABLE; 619 HP_INTR_ENABLE;
621 } 620 }
622 621
623 retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); 622 retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
624 623
625 if (retval) { 624 if (retval) {
626 err("%s: Write %x command failed!\n", __func__, slot_cmd); 625 err("%s: Write %x command failed!\n", __func__, slot_cmd);
@@ -704,7 +703,7 @@ static int hpc_power_off_slot(struct slot * slot)
704 HP_INTR_ENABLE; 703 HP_INTR_ENABLE;
705 } 704 }
706 705
707 retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); 706 retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
708 if (retval) { 707 if (retval) {
709 err("%s: Write command failed!\n", __func__); 708 err("%s: Write command failed!\n", __func__);
710 retval = -1; 709 retval = -1;
@@ -1036,45 +1035,9 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
1036static int pcie_init_hardware_part1(struct controller *ctrl, 1035static int pcie_init_hardware_part1(struct controller *ctrl,
1037 struct pcie_device *dev) 1036 struct pcie_device *dev)
1038{ 1037{
1039 int rc;
1040 u16 temp_word;
1041 u32 slot_cap;
1042 u16 slot_status;
1043
1044 rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
1045 if (rc) {
1046 err("%s: Cannot read SLOTCAP register\n", __func__);
1047 return -1;
1048 }
1049
1050 /* Mask Hot-plug Interrupt Enable */ 1038 /* Mask Hot-plug Interrupt Enable */
1051 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 1039 if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
1052 if (rc) { 1040 err("%s: Cannot mask hotplug interrupt enable\n", __func__);
1053 err("%s: Cannot read SLOTCTRL register\n", __func__);
1054 return -1;
1055 }
1056
1057 dbg("%s: SLOTCTRL %x value read %x\n",
1058 __func__, ctrl->cap_base + SLOTCTRL, temp_word);
1059 temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
1060 0x00;
1061
1062 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
1063 if (rc) {
1064 err("%s: Cannot write to SLOTCTRL register\n", __func__);
1065 return -1;
1066 }
1067
1068 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
1069 if (rc) {
1070 err("%s: Cannot read SLOTSTATUS register\n", __func__);
1071 return -1;
1072 }
1073
1074 temp_word = 0x1F; /* Clear all events */
1075 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
1076 if (rc) {
1077 err("%s: Cannot write to SLOTSTATUS register\n", __func__);
1078 return -1; 1041 return -1;
1079 } 1042 }
1080 return 0; 1043 return 0;
@@ -1082,84 +1045,47 @@ static int pcie_init_hardware_part1(struct controller *ctrl,
1082 1045
1083int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) 1046int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
1084{ 1047{
1085 int rc; 1048 u16 cmd, mask;
1086 u16 temp_word;
1087 u16 intr_enable = 0;
1088 u32 slot_cap;
1089 u16 slot_status;
1090
1091 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
1092 if (rc) {
1093 err("%s: Cannot read SLOTCTRL register\n", __func__);
1094 goto abort;
1095 }
1096
1097 intr_enable = intr_enable | PRSN_DETECT_ENABLE;
1098
1099 rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
1100 if (rc) {
1101 err("%s: Cannot read SLOTCAP register\n", __func__);
1102 goto abort;
1103 }
1104
1105 if (ATTN_BUTTN(slot_cap))
1106 intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
1107
1108 if (POWER_CTRL(slot_cap))
1109 intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
1110
1111 if (MRL_SENS(slot_cap))
1112 intr_enable = intr_enable | MRL_DETECT_ENABLE;
1113
1114 temp_word = (temp_word & ~intr_enable) | intr_enable;
1115
1116 if (pciehp_poll_mode) {
1117 temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
1118 } else {
1119 temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
1120 }
1121 1049
1122 /* 1050 /*
1123 * Unmask Hot-plug Interrupt Enable for the interrupt 1051 * We need to clear all events before enabling hotplug interrupt
1124 * notification mechanism case. 1052 * notification mechanism in order for hotplug controler to
1053 * generate interrupts.
1125 */ 1054 */
1126 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); 1055 if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
1127 if (rc) { 1056 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
1128 err("%s: Cannot write to SLOTCTRL register\n", __func__); 1057 return -1;
1129 goto abort;
1130 }
1131 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
1132 if (rc) {
1133 err("%s: Cannot read SLOTSTATUS register\n", __func__);
1134 goto abort_disable_intr;
1135 } 1058 }
1136 1059
1137 temp_word = 0x1F; /* Clear all events */ 1060 cmd = PRSN_DETECT_ENABLE;
1138 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); 1061 if (ATTN_BUTTN(ctrl->ctrlcap))
1139 if (rc) { 1062 cmd |= ATTN_BUTTN_ENABLE;
1140 err("%s: Cannot write to SLOTSTATUS register\n", __func__); 1063 if (POWER_CTRL(ctrl->ctrlcap))
1141 goto abort_disable_intr; 1064 cmd |= PWR_FAULT_DETECT_ENABLE;
1065 if (MRL_SENS(ctrl->ctrlcap))
1066 cmd |= MRL_DETECT_ENABLE;
1067 if (!pciehp_poll_mode)
1068 cmd |= HP_INTR_ENABLE;
1069
1070 mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE |
1071 PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE;
1072
1073 if (pcie_write_cmd(ctrl, cmd, mask)) {
1074 err("%s: Cannot enable software notification\n", __func__);
1075 goto abort;
1142 } 1076 }
1143 1077
1144 if (pciehp_force) { 1078 if (pciehp_force)
1145 dbg("Bypassing BIOS check for pciehp use on %s\n", 1079 dbg("Bypassing BIOS check for pciehp use on %s\n",
1146 pci_name(ctrl->pci_dev)); 1080 pci_name(ctrl->pci_dev));
1147 } else { 1081 else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev))
1148 rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); 1082 goto abort_disable_intr;
1149 if (rc)
1150 goto abort_disable_intr;
1151 }
1152 1083
1153 return 0; 1084 return 0;
1154 1085
1155 /* We end up here for the many possible ways to fail this API. */ 1086 /* We end up here for the many possible ways to fail this API. */
1156abort_disable_intr: 1087abort_disable_intr:
1157 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 1088 if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE))
1158 if (!rc) {
1159 temp_word &= ~(intr_enable | HP_INTR_ENABLE);
1160 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
1161 }
1162 if (rc)
1163 err("%s : disabling interrupts failed\n", __func__); 1089 err("%s : disabling interrupts failed\n", __func__);
1164abort: 1090abort:
1165 return -1; 1091 return -1;