/* Helper to verify status returned by PSP */ staticint check_i2c_req_sts(struct psp_i2c_req *req)
{
u32 status;
/* Status field in command-response buffer is updated by PSP */
status = READ_ONCE(req->hdr.status);
switch (status) { case PSP_I2C_REQ_STS_OK: return 0; case PSP_I2C_REQ_STS_BUS_BUSY: return -EBUSY; case PSP_I2C_REQ_STS_INV_PARAM: default: return -EIO;
}
}
/* * Errors in x86-PSP i2c-arbitration protocol may occur at two levels: * 1. mailbox communication - PSP is not operational or some IO errors with * basic communication had happened. * 2. i2c-requests - PSP refuses to grant i2c arbitration to x86 for too long. * * In order to distinguish between these in error handling code all mailbox * communication errors on the first level (from CCP symbols) will be passed * up and if -EIO is returned the second level will be checked.
*/ staticint psp_send_i2c_req_cezanne(struct psp_i2c_req *req)
{ int ret;
ret = psp_send_platform_access_msg(PSP_I2C_REQ_BUS_CMD, (struct psp_request *)req); if (ret == -EIO) return check_i2c_req_sts(req);
return ret;
}
staticint psp_send_i2c_req_doorbell(struct psp_i2c_req *req)
{ int ret;
ret = psp_ring_platform_doorbell(req->type, &req->hdr.status); if (ret == -EIO) return check_i2c_req_sts(req);
/* * If there is any pending transaction, cannot release the bus here. * psp_release_i2c_bus() will take care of this later.
*/ if (psp_i2c_access_count) return;
/* * In case of errors with PSP arbitrator psp_i2c_mbox_fail variable is * set above. As a consequence consecutive calls to acquire will bypass * communication with PSP. At any case i2c bus is granted to the caller, * thus always return success.
*/ return 0;
}
/* Return early if mailbox was malfunctioned */ if (psp_i2c_mbox_fail) return;
/* * If we are last owner of PSP semaphore, need to release arbitration * via mailbox.
*/
psp_i2c_access_count--; if (psp_i2c_access_count) return;
/* * Send a release command to PSP if the semaphore reservation timeout * elapsed but x86 still owns the controller.
*/ if (!delayed_work_pending(&release_queue))
release_bus();
}
/* * Locking methods are based on the default implementation from * drivers/i2c/i2c-core-base.c, but with PSP acquire and release operations * added. With this in place we can ensure that i2c clients on the bus shared * with PSP are able to lock HW access to the bus for arbitrary number of * operations - that is e.g. write-wait-read.
*/ staticvoid i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter, unsignedint flags)
{
psp_acquire_i2c_bus();
rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
}
staticint i2c_adapter_dw_psp_trylock_bus(struct i2c_adapter *adapter, unsignedint flags)
{ int ret;
ret = rt_mutex_trylock(&adapter->bus_lock); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.