/** * mei_hbm_start_wait - wait for start response message. * * @dev: the device structure * * Return: 0 on success and < 0 on failure
*/ int mei_hbm_start_wait(struct mei_device *dev)
{ int ret;
if (dev->hbm_state > MEI_HBM_STARTING) return0;
mutex_unlock(&dev->device_lock);
ret = wait_event_timeout(dev->wait_hbm_start,
dev->hbm_state != MEI_HBM_STARTING,
dev->timeouts.hbm);
mutex_lock(&dev->device_lock);
if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) {
dev->hbm_state = MEI_HBM_IDLE;
dev_err(dev->dev, "waiting for mei start failed\n"); return -ETIME;
} return0;
}
/** * mei_hbm_start_req - sends start request message. * * @dev: the device structure * * Return: 0 on success and < 0 on failure
*/ int mei_hbm_start_req(struct mei_device *dev)
{ struct mei_msg_hdr mei_hdr; struct hbm_host_version_request req; int ret;
ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) {
dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",
ret); return ret;
}
dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
dev->init_clients_timer = dev->timeouts.client_init;
mei_schedule_stall_timer(dev); return0;
}
/** * mei_hbm_me_cl_add - add new me client to the list * * @dev: the device structure * @res: hbm property response * * Return: 0 on success and -ENOMEM on allocation failure
*/
ret = mei_hbm_write_message(dev, &mei_hdr, &resp); if (ret)
dev_err(dev->dev, "add client response write failed: ret = %d\n",
ret); return ret;
}
/** * mei_hbm_fw_add_cl_req - request from the fw to add a client * * @dev: the device structure * @req: add client request * * Return: 0 on success and < 0 on failure
*/ staticint mei_hbm_fw_add_cl_req(struct mei_device *dev, struct hbm_add_client_request *req)
{ int ret;
u8 status = MEI_HBMS_SUCCESS;
/** * mei_hbm_cl_notify_req - send notification request * * @dev: the device structure * @cl: a client to disconnect from * @start: true for start false for stop * * Return: 0 on success and -EIO on write failure
*/ int mei_hbm_cl_notify_req(struct mei_device *dev, struct mei_cl *cl, u8 start)
{
struct mei_msg_hdr mei_hdr; struct hbm_notification_request req; int ret;
/** * mei_hbm_pg - sends pg command * * @dev: the device structure * @pg_cmd: the pg command code * * Return: -EIO on write failure * -EOPNOTSUPP if the operation is not supported by the protocol
*/ int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
{ struct mei_msg_hdr mei_hdr; struct hbm_power_gate req; int ret;
/** * mei_hbm_cl_connect_req - send connection request to specific me client * * @dev: the device structure * @cl: a client to connect to * * Return: -EIO on write failure
*/ int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
{ struct hbm_client_connect_request req;
/** * mei_hbm_pg_resume - process with PG resume * * @dev: the device structure.
*/ void mei_hbm_pg_resume(struct mei_device *dev)
{
pm_request_resume(dev->dev);
}
EXPORT_SYMBOL_GPL(mei_hbm_pg_resume);
/** * mei_hbm_pg_exit_res - PG exit response received * * @dev: the device structure. * * Return: 0 on success, -EPROTO on state mismatch
*/ staticint mei_hbm_pg_exit_res(struct mei_device *dev)
{ if (mei_pg_state(dev) != MEI_PG_ON ||
(dev->pg_event != MEI_PG_EVENT_WAIT &&
dev->pg_event != MEI_PG_EVENT_IDLE)) {
dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n",
mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); return -EPROTO;
}
switch (dev->pg_event) { case MEI_PG_EVENT_WAIT:
dev->pg_event = MEI_PG_EVENT_RECEIVED;
wake_up(&dev->wait_pg); break; case MEI_PG_EVENT_IDLE: /* * If the driver is not waiting on this then * this is HW initiated exit from PG. * Start runtime pm resume sequence to exit from PG.
*/
dev->pg_event = MEI_PG_EVENT_RECEIVED;
mei_hbm_pg_resume(dev); break; default:
WARN(1, "hbm: pg exit response: unexpected pg event = %d\n",
dev->pg_event); return -EPROTO;
}
return0;
}
/** * mei_hbm_config_features - check what hbm features and commands * are supported by the fw * * @dev: the device structure
*/ staticvoid mei_hbm_config_features(struct mei_device *dev)
{ /* Power Gating Isolation Support */
dev->hbm_f_pg_supported = 0; if (dev->version.major_version > HBM_MAJOR_VERSION_PGI)
dev->hbm_f_pg_supported = 1;
dev->hbm_f_dc_supported = 0; if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
dev->hbm_f_dc_supported = 1;
dev->hbm_f_ie_supported = 0; if (dev->version.major_version >= HBM_MAJOR_VERSION_IE)
dev->hbm_f_ie_supported = 1;
/* disconnect on connect timeout instead of link reset */
dev->hbm_f_dot_supported = 0; if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
dev->hbm_f_dot_supported = 1;
/* Notification Event Support */
dev->hbm_f_ev_supported = 0; if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
dev->hbm_f_ev_supported = 1;
/* Fixed Address Client Support */
dev->hbm_f_fa_supported = 0; if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
dev->hbm_f_fa_supported = 1;
/* OS ver message Support */
dev->hbm_f_os_supported = 0; if (dev->version.major_version >= HBM_MAJOR_VERSION_OS)
dev->hbm_f_os_supported = 1;
/* DMA Ring Support */
dev->hbm_f_dr_supported = 0; if (dev->version.major_version > HBM_MAJOR_VERSION_DR ||
(dev->version.major_version == HBM_MAJOR_VERSION_DR &&
dev->version.minor_version >= HBM_MINOR_VERSION_DR))
dev->hbm_f_dr_supported = 1;
/** * mei_hbm_version_is_supported - checks whether the driver can * support the hbm version of the device * * @dev: the device structure * Return: true if driver can support hbm version of the device
*/ bool mei_hbm_version_is_supported(struct mei_device *dev)
{ return (dev->version.major_version < HBM_MAJOR_VERSION) ||
(dev->version.major_version == HBM_MAJOR_VERSION &&
dev->version.minor_version <= HBM_MINOR_VERSION);
}
/** * mei_hbm_dispatch - bottom half read routine after ISR to * handle the read bus message cmd processing. * * @dev: the device structure * @hdr: header of bus message * * Return: 0 on success and < 0 on failure
*/ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
{ struct mei_bus_message *mei_msg; struct hbm_host_version_response *version_res; struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; struct hbm_dma_setup_response *dma_setup_res; struct hbm_add_client_request *add_cl_req; struct hbm_capability_response *capability_res; int ret;
/* ignore spurious message and prevent reset nesting * hbm is put to idle during system reset
*/ if (dev->hbm_state == MEI_HBM_IDLE) {
dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n"); return0;
}
if (!mei_hbm_version_is_supported(dev)) {
dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n");
dev->hbm_state = MEI_HBM_STOPPED; if (mei_hbm_stop_req(dev)) {
dev_err(dev->dev, "hbm: start: failed to send stop request\n"); return -EIO;
} break;
}
mei_hbm_config_features(dev);
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
dev->hbm_state != MEI_HBM_STARTING) { if (dev->dev_state == MEI_DEV_POWER_DOWN ||
dev->dev_state == MEI_DEV_POWERING_DOWN) {
dev_dbg(dev->dev, "hbm: start: on shutdown, ignoring\n"); return0;
}
dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n",
dev->dev_state, dev->hbm_state); return -EPROTO;
}
if (dev->hbm_f_cap_supported) { if (mei_hbm_capabilities_req(dev)) return -EIO;
wake_up(&dev->wait_hbm_start); break;
}
if (dev->hbm_f_dr_supported) { if (mei_dmam_ring_alloc(dev))
dev_info(dev->dev, "running w/o dma ring\n"); if (mei_dma_ring_is_allocated(dev)) { if (mei_hbm_dma_setup_req(dev)) return -EIO;
case MEI_HBM_CAPABILITIES_RES_CMD:
dev_dbg(dev->dev, "hbm: capabilities response: message received.\n");
dev->init_clients_timer = 0;
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
dev->hbm_state != MEI_HBM_CAP_SETUP) { if (dev->dev_state == MEI_DEV_POWER_DOWN ||
dev->dev_state == MEI_DEV_POWERING_DOWN) {
dev_dbg(dev->dev, "hbm: capabilities response: on shutdown, ignoring\n"); return0;
}
dev_err(dev->dev, "hbm: capabilities response: state mismatch, [%d, %d]\n",
dev->dev_state, dev->hbm_state); return -EPROTO;
}
capability_res = (struct hbm_capability_response *)mei_msg; if (!(capability_res->capability_granted[0] & HBM_CAP_VT))
dev->hbm_f_vt_supported = 0; if (!(capability_res->capability_granted[0] & HBM_CAP_CD))
dev->hbm_f_cd_supported = 0;
if (!(capability_res->capability_granted[0] & HBM_CAP_GSC))
dev->hbm_f_gsc_supported = 0;
if (dev->hbm_f_dr_supported) { if (mei_dmam_ring_alloc(dev))
dev_info(dev->dev, "running w/o dma ring\n"); if (mei_dma_ring_is_allocated(dev)) { if (mei_hbm_dma_setup_req(dev)) return -EIO; break;
}
}
case MEI_PG_ISOLATION_ENTRY_RES_CMD:
dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n");
ret = mei_hbm_pg_enter_res(dev); if (ret) return ret; break;
case MEI_PG_ISOLATION_EXIT_REQ_CMD:
dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n");
ret = mei_hbm_pg_exit_res(dev); if (ret) return ret; break;
case HOST_CLIENT_PROPERTIES_RES_CMD:
dev_dbg(dev->dev, "hbm: properties response: message received.\n");
dev->init_clients_timer = 0;
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { if (dev->dev_state == MEI_DEV_POWER_DOWN ||
dev->dev_state == MEI_DEV_POWERING_DOWN) {
dev_dbg(dev->dev, "hbm: properties response: on shutdown, ignoring\n"); return0;
}
dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
dev->dev_state, dev->hbm_state); return -EPROTO;
}
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.