|
@@ -1807,7 +1807,7 @@ static pci_ers_result_t cxl_vphb_error_detected(struct cxl_afu *afu,
|
|
|
/* There should only be one entry, but go through the list
|
|
/* There should only be one entry, but go through the list
|
|
|
* anyway
|
|
* anyway
|
|
|
*/
|
|
*/
|
|
|
- if (afu->phb == NULL)
|
|
|
|
|
|
|
+ if (afu == NULL || afu->phb == NULL)
|
|
|
return result;
|
|
return result;
|
|
|
|
|
|
|
|
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
|
|
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
|
|
@@ -1834,7 +1834,8 @@ static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
|
|
|
{
|
|
{
|
|
|
struct cxl *adapter = pci_get_drvdata(pdev);
|
|
struct cxl *adapter = pci_get_drvdata(pdev);
|
|
|
struct cxl_afu *afu;
|
|
struct cxl_afu *afu;
|
|
|
- pci_ers_result_t result = PCI_ERS_RESULT_NEED_RESET, afu_result;
|
|
|
|
|
|
|
+ pci_ers_result_t result = PCI_ERS_RESULT_NEED_RESET;
|
|
|
|
|
+ pci_ers_result_t afu_result = PCI_ERS_RESULT_NEED_RESET;
|
|
|
int i;
|
|
int i;
|
|
|
|
|
|
|
|
/* At this point, we could still have an interrupt pending.
|
|
/* At this point, we could still have an interrupt pending.
|
|
@@ -1845,6 +1846,7 @@ static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
|
|
|
|
|
|
|
|
/* If we're permanently dead, give up. */
|
|
/* If we're permanently dead, give up. */
|
|
|
if (state == pci_channel_io_perm_failure) {
|
|
if (state == pci_channel_io_perm_failure) {
|
|
|
|
|
+ spin_lock(&adapter->afu_list_lock);
|
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
|
afu = adapter->afu[i];
|
|
afu = adapter->afu[i];
|
|
|
/*
|
|
/*
|
|
@@ -1853,6 +1855,7 @@ static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
|
|
|
*/
|
|
*/
|
|
|
cxl_vphb_error_detected(afu, state);
|
|
cxl_vphb_error_detected(afu, state);
|
|
|
}
|
|
}
|
|
|
|
|
+ spin_unlock(&adapter->afu_list_lock);
|
|
|
return PCI_ERS_RESULT_DISCONNECT;
|
|
return PCI_ERS_RESULT_DISCONNECT;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1934,11 +1937,17 @@ static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
|
|
|
* * In slot_reset, free the old resources and allocate new ones.
|
|
* * In slot_reset, free the old resources and allocate new ones.
|
|
|
* * In resume, clear the flag to allow things to start.
|
|
* * In resume, clear the flag to allow things to start.
|
|
|
*/
|
|
*/
|
|
|
|
|
+
|
|
|
|
|
+ /* Make sure no one else changes the afu list */
|
|
|
|
|
+ spin_lock(&adapter->afu_list_lock);
|
|
|
|
|
+
|
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
|
afu = adapter->afu[i];
|
|
afu = adapter->afu[i];
|
|
|
|
|
|
|
|
- afu_result = cxl_vphb_error_detected(afu, state);
|
|
|
|
|
|
|
+ if (afu == NULL)
|
|
|
|
|
+ continue;
|
|
|
|
|
|
|
|
|
|
+ afu_result = cxl_vphb_error_detected(afu, state);
|
|
|
cxl_context_detach_all(afu);
|
|
cxl_context_detach_all(afu);
|
|
|
cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
|
|
cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
|
|
|
pci_deconfigure_afu(afu);
|
|
pci_deconfigure_afu(afu);
|
|
@@ -1950,6 +1959,7 @@ static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
|
|
|
(result == PCI_ERS_RESULT_NEED_RESET))
|
|
(result == PCI_ERS_RESULT_NEED_RESET))
|
|
|
result = PCI_ERS_RESULT_NONE;
|
|
result = PCI_ERS_RESULT_NONE;
|
|
|
}
|
|
}
|
|
|
|
|
+ spin_unlock(&adapter->afu_list_lock);
|
|
|
|
|
|
|
|
/* should take the context lock here */
|
|
/* should take the context lock here */
|
|
|
if (cxl_adapter_context_lock(adapter) != 0)
|
|
if (cxl_adapter_context_lock(adapter) != 0)
|
|
@@ -1982,14 +1992,18 @@ static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev)
|
|
|
*/
|
|
*/
|
|
|
cxl_adapter_context_unlock(adapter);
|
|
cxl_adapter_context_unlock(adapter);
|
|
|
|
|
|
|
|
|
|
+ spin_lock(&adapter->afu_list_lock);
|
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
|
afu = adapter->afu[i];
|
|
afu = adapter->afu[i];
|
|
|
|
|
|
|
|
|
|
+ if (afu == NULL)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
if (pci_configure_afu(afu, adapter, pdev))
|
|
if (pci_configure_afu(afu, adapter, pdev))
|
|
|
- goto err;
|
|
|
|
|
|
|
+ goto err_unlock;
|
|
|
|
|
|
|
|
if (cxl_afu_select_best_mode(afu))
|
|
if (cxl_afu_select_best_mode(afu))
|
|
|
- goto err;
|
|
|
|
|
|
|
+ goto err_unlock;
|
|
|
|
|
|
|
|
if (afu->phb == NULL)
|
|
if (afu->phb == NULL)
|
|
|
continue;
|
|
continue;
|
|
@@ -2001,16 +2015,16 @@ static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev)
|
|
|
ctx = cxl_get_context(afu_dev);
|
|
ctx = cxl_get_context(afu_dev);
|
|
|
|
|
|
|
|
if (ctx && cxl_release_context(ctx))
|
|
if (ctx && cxl_release_context(ctx))
|
|
|
- goto err;
|
|
|
|
|
|
|
+ goto err_unlock;
|
|
|
|
|
|
|
|
ctx = cxl_dev_context_init(afu_dev);
|
|
ctx = cxl_dev_context_init(afu_dev);
|
|
|
if (IS_ERR(ctx))
|
|
if (IS_ERR(ctx))
|
|
|
- goto err;
|
|
|
|
|
|
|
+ goto err_unlock;
|
|
|
|
|
|
|
|
afu_dev->dev.archdata.cxl_ctx = ctx;
|
|
afu_dev->dev.archdata.cxl_ctx = ctx;
|
|
|
|
|
|
|
|
if (cxl_ops->afu_check_and_enable(afu))
|
|
if (cxl_ops->afu_check_and_enable(afu))
|
|
|
- goto err;
|
|
|
|
|
|
|
+ goto err_unlock;
|
|
|
|
|
|
|
|
afu_dev->error_state = pci_channel_io_normal;
|
|
afu_dev->error_state = pci_channel_io_normal;
|
|
|
|
|
|
|
@@ -2031,8 +2045,13 @@ static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev)
|
|
|
result = PCI_ERS_RESULT_DISCONNECT;
|
|
result = PCI_ERS_RESULT_DISCONNECT;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ spin_unlock(&adapter->afu_list_lock);
|
|
|
return result;
|
|
return result;
|
|
|
|
|
|
|
|
|
|
+err_unlock:
|
|
|
|
|
+ spin_unlock(&adapter->afu_list_lock);
|
|
|
|
|
+
|
|
|
err:
|
|
err:
|
|
|
/* All the bits that happen in both error_detected and cxl_remove
|
|
/* All the bits that happen in both error_detected and cxl_remove
|
|
|
* should be idempotent, so we don't need to worry about leaving a mix
|
|
* should be idempotent, so we don't need to worry about leaving a mix
|
|
@@ -2053,10 +2072,11 @@ static void cxl_pci_resume(struct pci_dev *pdev)
|
|
|
* This is not the place to be checking if everything came back up
|
|
* This is not the place to be checking if everything came back up
|
|
|
* properly, because there's no return value: do that in slot_reset.
|
|
* properly, because there's no return value: do that in slot_reset.
|
|
|
*/
|
|
*/
|
|
|
|
|
+ spin_lock(&adapter->afu_list_lock);
|
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
for (i = 0; i < adapter->slices; i++) {
|
|
|
afu = adapter->afu[i];
|
|
afu = adapter->afu[i];
|
|
|
|
|
|
|
|
- if (afu->phb == NULL)
|
|
|
|
|
|
|
+ if (afu == NULL || afu->phb == NULL)
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
|
|
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
|
|
@@ -2065,6 +2085,7 @@ static void cxl_pci_resume(struct pci_dev *pdev)
|
|
|
afu_dev->driver->err_handler->resume(afu_dev);
|
|
afu_dev->driver->err_handler->resume(afu_dev);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ spin_unlock(&adapter->afu_list_lock);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static const struct pci_error_handlers cxl_err_handler = {
|
|
static const struct pci_error_handlers cxl_err_handler = {
|