diff options
author | Gavin Shan <gwshan@linux.vnet.ibm.com> | 2014-09-29 22:39:01 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2014-09-30 03:15:14 -0400 |
commit | 4eeeff0ebcdeabf3f76c4eece0593e98c6619be8 (patch) | |
tree | cf0760e5efe03913afa52375b037f50734907124 | |
parent | 4d4f577e4b5ee1299096438bbcf743bbe14f33ab (diff) |
powerpc/eeh: Unfreeze PE on enabling EEH functionality
When passing through PE to guest, that's possibly in frozen
state. The driver for the pass-through devices on guest side
can't be loaded successfully as reported. We already had one
gate in eeh_dev_open() to clear PE frozen state accordingly,
but that's not enough because the function is only called at
QEMU startup for once.
The patch adds another gate in eeh_pe_set_option() so that the
PE frozen state can be cleared at QEMU restart time.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/include/asm/eeh.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh.c | 60 |
2 files changed, 33 insertions, 28 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 4fa15796537a..b793fdfb37f3 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
@@ -286,6 +286,7 @@ void eeh_add_device_late(struct pci_dev *); | |||
286 | void eeh_add_device_tree_late(struct pci_bus *); | 286 | void eeh_add_device_tree_late(struct pci_bus *); |
287 | void eeh_add_sysfs_files(struct pci_bus *); | 287 | void eeh_add_sysfs_files(struct pci_bus *); |
288 | void eeh_remove_device(struct pci_dev *); | 288 | void eeh_remove_device(struct pci_dev *); |
289 | int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state); | ||
289 | int eeh_dev_open(struct pci_dev *pdev); | 290 | int eeh_dev_open(struct pci_dev *pdev); |
290 | void eeh_dev_release(struct pci_dev *pdev); | 291 | void eeh_dev_release(struct pci_dev *pdev); |
291 | struct eeh_pe *eeh_iommu_group_to_pe(struct iommu_group *group); | 292 | struct eeh_pe *eeh_iommu_group_to_pe(struct iommu_group *group); |
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index b79a8331965f..b569ce2a8037 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c | |||
@@ -1164,6 +1164,31 @@ void eeh_remove_device(struct pci_dev *dev) | |||
1164 | edev->mode &= ~EEH_DEV_SYSFS; | 1164 | edev->mode &= ~EEH_DEV_SYSFS; |
1165 | } | 1165 | } |
1166 | 1166 | ||
1167 | int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state) | ||
1168 | { | ||
1169 | int ret; | ||
1170 | |||
1171 | ret = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); | ||
1172 | if (ret) { | ||
1173 | pr_warn("%s: Failure %d enabling IO on PHB#%x-PE#%x\n", | ||
1174 | __func__, ret, pe->phb->global_number, pe->addr); | ||
1175 | return ret; | ||
1176 | } | ||
1177 | |||
1178 | ret = eeh_pci_enable(pe, EEH_OPT_THAW_DMA); | ||
1179 | if (ret) { | ||
1180 | pr_warn("%s: Failure %d enabling DMA on PHB#%x-PE#%x\n", | ||
1181 | __func__, ret, pe->phb->global_number, pe->addr); | ||
1182 | return ret; | ||
1183 | } | ||
1184 | |||
1185 | /* Clear software isolated state */ | ||
1186 | if (sw_state && (pe->state & EEH_PE_ISOLATED)) | ||
1187 | eeh_pe_state_clear(pe, EEH_PE_ISOLATED); | ||
1188 | |||
1189 | return ret; | ||
1190 | } | ||
1191 | |||
1167 | /** | 1192 | /** |
1168 | * eeh_dev_open - Increase count of pass through devices for PE | 1193 | * eeh_dev_open - Increase count of pass through devices for PE |
1169 | * @pdev: PCI device | 1194 | * @pdev: PCI device |
@@ -1176,7 +1201,6 @@ void eeh_remove_device(struct pci_dev *dev) | |||
1176 | int eeh_dev_open(struct pci_dev *pdev) | 1201 | int eeh_dev_open(struct pci_dev *pdev) |
1177 | { | 1202 | { |
1178 | struct eeh_dev *edev; | 1203 | struct eeh_dev *edev; |
1179 | int flag = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); | ||
1180 | int ret = -ENODEV; | 1204 | int ret = -ENODEV; |
1181 | 1205 | ||
1182 | mutex_lock(&eeh_dev_mutex); | 1206 | mutex_lock(&eeh_dev_mutex); |
@@ -1196,31 +1220,9 @@ int eeh_dev_open(struct pci_dev *pdev) | |||
1196 | * in frozen PE won't work properly. Clear the frozen state | 1220 | * in frozen PE won't work properly. Clear the frozen state |
1197 | * in advance. | 1221 | * in advance. |
1198 | */ | 1222 | */ |
1199 | ret = eeh_ops->get_state(edev->pe, NULL); | 1223 | ret = eeh_unfreeze_pe(edev->pe, true); |
1200 | if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT && | 1224 | if (ret) |
1201 | (ret & flag) != flag) { | 1225 | goto out; |
1202 | ret = eeh_ops->set_option(edev->pe, EEH_OPT_THAW_MMIO); | ||
1203 | if (ret) { | ||
1204 | pr_warn("%s: Failure %d enabling MMIO " | ||
1205 | "for PHB#%x-PE#%x\n", | ||
1206 | __func__, ret, edev->phb->global_number, | ||
1207 | edev->pe->addr); | ||
1208 | goto out; | ||
1209 | } | ||
1210 | |||
1211 | ret = eeh_ops->set_option(edev->pe, EEH_OPT_THAW_DMA); | ||
1212 | if (ret) { | ||
1213 | pr_warn("%s: Failure %d enabling DMA " | ||
1214 | "for PHB#%x-PE#%x\n", | ||
1215 | __func__, ret, edev->phb->global_number, | ||
1216 | edev->pe->addr); | ||
1217 | goto out; | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | /* Clear software isolated state */ | ||
1222 | if (edev->pe->state & EEH_PE_ISOLATED) | ||
1223 | eeh_pe_state_clear(edev->pe, EEH_PE_ISOLATED); | ||
1224 | 1226 | ||
1225 | /* Increase PE's pass through count */ | 1227 | /* Increase PE's pass through count */ |
1226 | atomic_inc(&edev->pe->pass_dev_cnt); | 1228 | atomic_inc(&edev->pe->pass_dev_cnt); |
@@ -1338,8 +1340,10 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option) | |||
1338 | */ | 1340 | */ |
1339 | switch (option) { | 1341 | switch (option) { |
1340 | case EEH_OPT_ENABLE: | 1342 | case EEH_OPT_ENABLE: |
1341 | if (eeh_enabled()) | 1343 | if (eeh_enabled()) { |
1344 | ret = eeh_unfreeze_pe(pe, true); | ||
1342 | break; | 1345 | break; |
1346 | } | ||
1343 | ret = -EIO; | 1347 | ret = -EIO; |
1344 | break; | 1348 | break; |
1345 | case EEH_OPT_DISABLE: | 1349 | case EEH_OPT_DISABLE: |
@@ -1351,7 +1355,7 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option) | |||
1351 | break; | 1355 | break; |
1352 | } | 1356 | } |
1353 | 1357 | ||
1354 | ret = eeh_ops->set_option(pe, option); | 1358 | ret = eeh_pci_enable(pe, option); |
1355 | break; | 1359 | break; |
1356 | default: | 1360 | default: |
1357 | pr_debug("%s: Option %d out of range (%d, %d)\n", | 1361 | pr_debug("%s: Option %d out of range (%d, %d)\n", |