aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-02-27 15:03:56 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-03-08 19:10:09 -0500
commitc8c29b38fbb9448f2a25484348dd5aec9a2a9671 (patch)
tree614537c3f2b1e3e8202d8aff0d300c58489cc257 /arch/powerpc
parent8fb8f709025c13ae72968a66a1ade24431a342b2 (diff)
powerpc/eeh: pseries platform EEH PE address retrieval
There're 2 types of addresses used for EEH operations. The first one would be BDF (Bus/Device/Function) address which is retrieved from the reg property of the corresponding FDT node. Another one is PE address that should be enquired from firmware through RTAS call on pSeries platform. When issuing EEH operation, the PE address has precedence over BDF address. The patch implements retrieving PE address according to the given BDF address on pSeries platform. Also, the struct eeh_early_enable_info has been removed since the information can be figured out from dn->pdn->phb->buid directly and that simplifies the code. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c67
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c46
2 files changed, 48 insertions, 65 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 70a9617cc6c0..00797e079f49 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -91,8 +91,6 @@ static int ibm_set_slot_reset;
91static int ibm_read_slot_reset_state; 91static int ibm_read_slot_reset_state;
92static int ibm_read_slot_reset_state2; 92static int ibm_read_slot_reset_state2;
93static int ibm_slot_error_detail; 93static int ibm_slot_error_detail;
94static int ibm_get_config_addr_info;
95static int ibm_get_config_addr_info2;
96static int ibm_configure_bridge; 94static int ibm_configure_bridge;
97static int ibm_configure_pe; 95static int ibm_configure_pe;
98 96
@@ -1048,56 +1046,6 @@ void eeh_configure_bridge(struct pci_dn *pdn)
1048 } 1046 }
1049} 1047}
1050 1048
1051#define EEH_ENABLE 1
1052
1053struct eeh_early_enable_info {
1054 unsigned int buid_hi;
1055 unsigned int buid_lo;
1056};
1057
1058/**
1059 * eeh_get_pe_addr - Retrieve PE address with given BDF address
1060 * @config_addr: BDF address
1061 * @info: BUID of the associated PHB
1062 *
1063 * There're 2 kinds of addresses existing in EEH core components:
1064 * BDF address and PE address. Besides, there has dedicated platform
1065 * dependent function call to retrieve the PE address according to
1066 * the given BDF address. Further more, we prefer PE address on BDF
1067 * address in EEH core components.
1068 */
1069static int eeh_get_pe_addr(int config_addr,
1070 struct eeh_early_enable_info *info)
1071{
1072 unsigned int rets[3];
1073 int ret;
1074
1075 /* Use latest config-addr token on power6 */
1076 if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
1077 /* Make sure we have a PE in hand */
1078 ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
1079 config_addr, info->buid_hi, info->buid_lo, 1);
1080 if (ret || (rets[0]==0))
1081 return 0;
1082
1083 ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
1084 config_addr, info->buid_hi, info->buid_lo, 0);
1085 if (ret)
1086 return 0;
1087 return rets[0];
1088 }
1089
1090 /* Use older config-addr token on power5 */
1091 if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
1092 ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets,
1093 config_addr, info->buid_hi, info->buid_lo, 0);
1094 if (ret)
1095 return 0;
1096 return rets[0];
1097 }
1098 return 0;
1099}
1100
1101/** 1049/**
1102 * eeh_early_enable - Early enable EEH on the indicated device 1050 * eeh_early_enable - Early enable EEH on the indicated device
1103 * @dn: device node 1051 * @dn: device node
@@ -1110,7 +1058,6 @@ static int eeh_get_pe_addr(int config_addr,
1110static void *eeh_early_enable(struct device_node *dn, void *data) 1058static void *eeh_early_enable(struct device_node *dn, void *data)
1111{ 1059{
1112 unsigned int rets[3]; 1060 unsigned int rets[3];
1113 struct eeh_early_enable_info *info = data;
1114 int ret; 1061 int ret;
1115 const u32 *class_code = of_get_property(dn, "class-code", NULL); 1062 const u32 *class_code = of_get_property(dn, "class-code", NULL);
1116 const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); 1063 const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
@@ -1155,7 +1102,7 @@ static void *eeh_early_enable(struct device_node *dn, void *data)
1155 /* If the newer, better, ibm,get-config-addr-info is supported, 1102 /* If the newer, better, ibm,get-config-addr-info is supported,
1156 * then use that instead. 1103 * then use that instead.
1157 */ 1104 */
1158 pdn->eeh_pe_config_addr = eeh_get_pe_addr(pdn->eeh_config_addr, info); 1105 pdn->eeh_pe_config_addr = eeh_ops->get_pe_addr(dn);
1159 1106
1160 /* Some older systems (Power4) allow the 1107 /* Some older systems (Power4) allow the
1161 * ibm,set-eeh-option call to succeed even on nodes 1108 * ibm,set-eeh-option call to succeed even on nodes
@@ -1264,7 +1211,6 @@ int __exit eeh_ops_unregister(const char *name)
1264void __init eeh_init(void) 1211void __init eeh_init(void)
1265{ 1212{
1266 struct device_node *phb, *np; 1213 struct device_node *phb, *np;
1267 struct eeh_early_enable_info info;
1268 int ret; 1214 int ret;
1269 1215
1270 /* call platform initialization function */ 1216 /* call platform initialization function */
@@ -1289,8 +1235,6 @@ void __init eeh_init(void)
1289 ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); 1235 ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2");
1290 ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); 1236 ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
1291 ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); 1237 ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
1292 ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
1293 ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
1294 ibm_configure_bridge = rtas_token("ibm,configure-bridge"); 1238 ibm_configure_bridge = rtas_token("ibm,configure-bridge");
1295 ibm_configure_pe = rtas_token("ibm,configure-pe"); 1239 ibm_configure_pe = rtas_token("ibm,configure-pe");
1296 1240
@@ -1313,9 +1257,7 @@ void __init eeh_init(void)
1313 if (buid == 0 || PCI_DN(phb) == NULL) 1257 if (buid == 0 || PCI_DN(phb) == NULL)
1314 continue; 1258 continue;
1315 1259
1316 info.buid_lo = BUID_LO(buid); 1260 traverse_pci_devices(phb, eeh_early_enable, NULL);
1317 info.buid_hi = BUID_HI(buid);
1318 traverse_pci_devices(phb, eeh_early_enable, &info);
1319 } 1261 }
1320 1262
1321 if (eeh_subsystem_enabled) 1263 if (eeh_subsystem_enabled)
@@ -1339,7 +1281,6 @@ void __init eeh_init(void)
1339static void eeh_add_device_early(struct device_node *dn) 1281static void eeh_add_device_early(struct device_node *dn)
1340{ 1282{
1341 struct pci_controller *phb; 1283 struct pci_controller *phb;
1342 struct eeh_early_enable_info info;
1343 1284
1344 if (!dn || !PCI_DN(dn)) 1285 if (!dn || !PCI_DN(dn))
1345 return; 1286 return;
@@ -1349,9 +1290,7 @@ static void eeh_add_device_early(struct device_node *dn)
1349 if (NULL == phb || 0 == phb->buid) 1290 if (NULL == phb || 0 == phb->buid)
1350 return; 1291 return;
1351 1292
1352 info.buid_hi = BUID_HI(phb->buid); 1293 eeh_early_enable(dn, NULL);
1353 info.buid_lo = BUID_LO(phb->buid);
1354 eeh_early_enable(dn, &info);
1355} 1294}
1356 1295
1357/** 1296/**
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index c48a9e6ecdd6..2b9543a78236 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -176,7 +176,51 @@ static int pseries_eeh_set_option(struct device_node *dn, int option)
176 */ 176 */
177static int pseries_eeh_get_pe_addr(struct device_node *dn) 177static int pseries_eeh_get_pe_addr(struct device_node *dn)
178{ 178{
179 return 0; 179 struct pci_dn *pdn;
180 int ret = 0;
181 int rets[3];
182
183 pdn = PCI_DN(dn);
184
185 if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
186 /*
187 * First of all, we need to make sure there has one PE
188 * associated with the device. Otherwise, PE address is
189 * meaningless.
190 */
191 ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
192 pdn->eeh_config_addr, BUID_HI(pdn->phb->buid),
193 BUID_LO(pdn->phb->buid), 1);
194 if (ret || (rets[0] == 0))
195 return 0;
196
197 /* Retrieve the associated PE config address */
198 ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
199 pdn->eeh_config_addr, BUID_HI(pdn->phb->buid),
200 BUID_LO(pdn->phb->buid), 0);
201 if (ret) {
202 pr_warning("%s: Failed to get PE address for %s\n",
203 __func__, dn->full_name);
204 return 0;
205 }
206
207 return rets[0];
208 }
209
210 if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
211 ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets,
212 pdn->eeh_config_addr, BUID_HI(pdn->phb->buid),
213 BUID_LO(pdn->phb->buid), 0);
214 if (ret) {
215 pr_warning("%s: Failed to get PE address for %s\n",
216 __func__, dn->full_name);
217 return 0;
218 }
219
220 return rets[0];
221 }
222
223 return ret;
180} 224}
181 225
182/** 226/**