in cadence_master.c [374:448]
static int cdns_parity_error_injection(void *data, u64 value)
{
struct sdw_cdns *cdns = data;
struct sdw_bus *bus;
int ret;
if (value != 1)
return -EINVAL;
bus = &cdns->bus;
/*
* Resume Master device. If this results in a bus reset, the
* Slave devices will re-attach and be re-enumerated.
*/
ret = pm_runtime_get_sync(bus->dev);
if (ret < 0 && ret != -EACCES) {
dev_err_ratelimited(cdns->dev,
"pm_runtime_get_sync failed in %s, ret %d\n",
__func__, ret);
pm_runtime_put_noidle(bus->dev);
return ret;
}
/*
* wait long enough for Slave(s) to be in steady state. This
* does not need to be super precise.
*/
msleep(200);
/*
* Take the bus lock here to make sure that any bus transactions
* will be queued while we inject a parity error on a dummy read
*/
mutex_lock(&bus->bus_lock);
/* program hardware to inject parity error */
cdns_updatel(cdns, CDNS_MCP_CMDCTRL,
CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR,
CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR);
/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT,
CDNS_MCP_CONFIG_UPDATE_BIT);
/* do a broadcast dummy read to avoid bus clashes */
ret = sdw_bread_no_pm_unlocked(&cdns->bus, 0xf, SDW_SCP_DEVID_0);
dev_info(cdns->dev, "parity error injection, read: %d\n", ret);
/* program hardware to disable parity error */
cdns_updatel(cdns, CDNS_MCP_CMDCTRL,
CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR,
0);
/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT,
CDNS_MCP_CONFIG_UPDATE_BIT);
/* Continue bus operation with parity error injection disabled */
mutex_unlock(&bus->bus_lock);
/* Userspace changed the hardware state behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
/*
* allow Master device to enter pm_runtime suspend. This may
* also result in Slave devices suspending.
*/
pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
return 0;
}