in dfl-afu-error.c [50:113]
static int afu_port_err_clear(struct device *dev, u64 err)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
struct platform_device *pdev = to_platform_device(dev);
void __iomem *base_err, *base_hdr;
int enable_ret = 0, ret = -EBUSY;
u64 v;
base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
base_hdr = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
mutex_lock(&pdata->lock);
/*
* clear Port Errors
*
* - Check for AP6 State
* - Halt Port by keeping Port in reset
* - Set PORT Error mask to all 1 to mask errors
* - Clear all errors
* - Set Port mask to all 0 to enable errors
* - All errors start capturing new errors
* - Enable Port by pulling the port out of reset
*/
/* if device is still in AP6 power state, can not clear any error. */
v = readq(base_hdr + PORT_HDR_STS);
if (FIELD_GET(PORT_STS_PWR_STATE, v) == PORT_STS_PWR_STATE_AP6) {
dev_err(dev, "Could not clear errors, device in AP6 state.\n");
goto done;
}
/* Halt Port by keeping Port in reset */
ret = __afu_port_disable(pdev);
if (ret)
goto done;
/* Mask all errors */
__afu_port_err_mask(dev, true);
/* Clear errors if err input matches with current port errors.*/
v = readq(base_err + PORT_ERROR);
if (v == err) {
writeq(v, base_err + PORT_ERROR);
v = readq(base_err + PORT_FIRST_ERROR);
writeq(v, base_err + PORT_FIRST_ERROR);
} else {
dev_warn(dev, "%s: received 0x%llx, expected 0x%llx\n",
__func__, v, err);
ret = -EINVAL;
}
/* Clear mask */
__afu_port_err_mask(dev, false);
/* Enable the Port by clearing the reset */
enable_ret = __afu_port_enable(pdev);
done:
mutex_unlock(&pdata->lock);
return enable_ret ? enable_ret : ret;
}