diff options
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 150 |
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 | */ |
249 | static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) | 249 | static 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) | |||
1036 | static int pcie_init_hardware_part1(struct controller *ctrl, | 1035 | static 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 | ||
1083 | int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) | 1046 | int 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. */ |
1156 | abort_disable_intr: | 1087 | abort_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__); |
1164 | abort: | 1090 | abort: |
1165 | return -1; | 1091 | return -1; |