// FIXME // This is a hack, we need to do this "right" and clean the interface up // properly, not just forcibly yank the thing out of the system and hope for the // best. But for now, people want their modules to come out without having to // throw the thing to the ground or get out a screwdriver. static ssize_t intf_eject_store(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t len)
{ struct gb_svc *svc = to_gb_svc(dev); unsignedshort intf_id; int ret;
ret = kstrtou16(buf, 10, &intf_id); if (ret < 0) return ret;
dev_warn(dev, "Forcibly trying to eject interface %d\n", intf_id);
ret = gb_svc_intf_eject(svc, intf_id); if (ret < 0) return ret;
int gb_svc_intf_eject(struct gb_svc *svc, u8 intf_id)
{ struct gb_svc_intf_eject_request request; int ret;
request.intf_id = intf_id;
/* * The pulse width for module release in svc is long so we need to * increase the timeout so the operation will not return to soon.
*/
ret = gb_operation_sync_timeout(svc->connection,
GB_SVC_TYPE_INTF_EJECT, &request, sizeof(request), NULL, 0,
SVC_INTF_EJECT_TIMEOUT); if (ret) {
dev_err(&svc->dev, "failed to eject interface %u\n", intf_id); return ret;
}
return 0;
}
int gb_svc_intf_vsys_set(struct gb_svc *svc, u8 intf_id, bool enable)
{ struct gb_svc_intf_vsys_request request; struct gb_svc_intf_vsys_response response; int type, ret;
request.intf_id = intf_id;
if (enable)
type = GB_SVC_TYPE_INTF_VSYS_ENABLE; else
type = GB_SVC_TYPE_INTF_VSYS_DISABLE;
ret = gb_operation_sync(svc->connection, type,
&request, sizeof(request),
&response, sizeof(response)); if (ret < 0) return ret; if (response.result_code != GB_SVC_INTF_VSYS_OK) return -EREMOTEIO; return 0;
}
int gb_svc_intf_refclk_set(struct gb_svc *svc, u8 intf_id, bool enable)
{ struct gb_svc_intf_refclk_request request; struct gb_svc_intf_refclk_response response; int type, ret;
request.intf_id = intf_id;
if (enable)
type = GB_SVC_TYPE_INTF_REFCLK_ENABLE; else
type = GB_SVC_TYPE_INTF_REFCLK_DISABLE;
ret = gb_operation_sync(svc->connection, type,
&request, sizeof(request),
&response, sizeof(response)); if (ret < 0) return ret; if (response.result_code != GB_SVC_INTF_REFCLK_OK) return -EREMOTEIO; return 0;
}
int gb_svc_intf_unipro_set(struct gb_svc *svc, u8 intf_id, bool enable)
{ struct gb_svc_intf_unipro_request request; struct gb_svc_intf_unipro_response response; int type, ret;
request.intf_id = intf_id;
if (enable)
type = GB_SVC_TYPE_INTF_UNIPRO_ENABLE; else
type = GB_SVC_TYPE_INTF_UNIPRO_DISABLE;
ret = gb_operation_sync(svc->connection, type,
&request, sizeof(request),
&response, sizeof(response)); if (ret < 0) return ret; if (response.result_code != GB_SVC_INTF_UNIPRO_OK) return -EREMOTEIO; return 0;
}
int gb_svc_intf_activate(struct gb_svc *svc, u8 intf_id, u8 *intf_type)
{ struct gb_svc_intf_activate_request request; struct gb_svc_intf_activate_response response; int ret;
request.intf_id = intf_id;
ret = gb_operation_sync_timeout(svc->connection,
GB_SVC_TYPE_INTF_ACTIVATE,
&request, sizeof(request),
&response, sizeof(response),
SVC_INTF_ACTIVATE_TIMEOUT); if (ret < 0) return ret; if (response.status != GB_SVC_OP_SUCCESS) {
dev_err(&svc->dev, "failed to activate interface %u: %u\n",
intf_id, response.status); return -EREMOTEIO;
}
*intf_type = response.intf_type;
return 0;
}
int gb_svc_intf_resume(struct gb_svc *svc, u8 intf_id)
{ struct gb_svc_intf_resume_request request; struct gb_svc_intf_resume_response response; int ret;
request.intf_id = intf_id;
ret = gb_operation_sync_timeout(svc->connection,
GB_SVC_TYPE_INTF_RESUME,
&request, sizeof(request),
&response, sizeof(response),
SVC_INTF_RESUME_TIMEOUT); if (ret < 0) {
dev_err(&svc->dev, "failed to send interface resume %u: %d\n",
intf_id, ret); return ret;
}
if (response.status != GB_SVC_OP_SUCCESS) {
dev_err(&svc->dev, "failed to resume interface %u: %u\n",
intf_id, response.status); return -EREMOTEIO;
}
ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
&request, sizeof(request),
&response, sizeof(response)); if (ret < 0) {
dev_err(&svc->dev, "failed to send set power mode operation to interface %u: %d\n",
intf_id, ret); return ret;
}
result_code = response.result_code; if (result_code != GB_SVC_SETPWRM_PWR_OK) {
dev_err(&svc->dev, "failed to hibernate the link for interface %u: %u\n",
intf_id, result_code); return -EIO;
}
ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
GB_SVC_PWRMON_TYPE_VOL, &value); if (ret) {
dev_err(&svc->dev, "failed to get voltage sample %u: %d\n",
pwrmon_rails->id, ret); return ret;
}
ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
GB_SVC_PWRMON_TYPE_CURR, &value); if (ret) {
dev_err(&svc->dev, "failed to get current sample %u: %d\n",
pwrmon_rails->id, ret); return ret;
}
ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
GB_SVC_PWRMON_TYPE_PWR, &value); if (ret) {
dev_err(&svc->dev, "failed to get power sample %u: %d\n",
pwrmon_rails->id, ret); return ret;
}
ret = device_add(&svc->dev); if (ret) {
dev_err(&svc->dev, "failed to register svc device: %d\n", ret); return ret;
}
ret = gb_svc_watchdog_create(svc); if (ret) {
dev_err(&svc->dev, "failed to create watchdog: %d\n", ret); goto err_deregister_svc;
}
/* * FIXME: This is a temporary hack to reconfigure the link at HELLO * (which abuses the deferred request processing mechanism).
*/
ret = gb_svc_queue_deferred_request(op); if (ret) goto err_destroy_watchdog;
/* * XXX This is a hack/work-around to reconfigure the APBridgeA-Switch * link to PWM G2, 1 Lane, Slow Auto, so that it has sufficient * bandwidth for 3 audio streams plus boot-over-UniPro of a hot-plugged * module. * * The code should be removed once SW-2217, Heuristic for UniPro * Power Mode Changes is resolved.
*/
ret = gb_svc_intf_set_power_mode(svc, svc->ap_intf_id,
GB_SVC_UNIPRO_HS_SERIES_A,
GB_SVC_UNIPRO_SLOW_AUTO_MODE,
2, 1,
GB_SVC_SMALL_AMPLITUDE,
GB_SVC_NO_DE_EMPHASIS,
GB_SVC_UNIPRO_SLOW_AUTO_MODE,
2, 1,
0, 0,
NULL, NULL);
if (ret)
dev_warn(&svc->dev, "power mode change failed on AP to switch link: %d\n",
ret);
}
if (op->request->payload_size < sizeof(*request)) {
dev_warn(&svc->dev, "short mailbox request received (%zu < %zu)\n",
op->request->payload_size, sizeof(*request)); return -EINVAL;
}
request = op->request->payload;
dev_dbg(&svc->dev, "%s - id = %u\n", __func__, request->intf_id);
return gb_svc_queue_deferred_request(op);
}
staticint gb_svc_request_handler(struct gb_operation *op)
{ struct gb_connection *connection = op->connection; struct gb_svc *svc = gb_connection_get_data(connection);
u8 type = op->type; int ret = 0;
/* * SVC requests need to follow a specific order (at least initially) and * below code takes care of enforcing that. The expected order is: * - PROTOCOL_VERSION * - SVC_HELLO * - Any other request, but the earlier two. * * Incoming requests are guaranteed to be serialized and so we don't * need to protect 'state' for any races.
*/ switch (type) { case GB_SVC_TYPE_PROTOCOL_VERSION: if (svc->state != GB_SVC_STATE_RESET)
ret = -EINVAL; break; case GB_SVC_TYPE_SVC_HELLO: if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
ret = -EINVAL; break; default: if (svc->state != GB_SVC_STATE_SVC_HELLO)
ret = -EINVAL; break;
}
if (ret) {
dev_warn(&svc->dev, "unexpected request 0x%02x received (state %u)\n",
type, svc->state); return ret;
}
switch (type) { case GB_SVC_TYPE_PROTOCOL_VERSION:
ret = gb_svc_version_request(op); if (!ret)
svc->state = GB_SVC_STATE_PROTOCOL_VERSION; return ret; case GB_SVC_TYPE_SVC_HELLO:
ret = gb_svc_hello(op); if (!ret)
svc->state = GB_SVC_STATE_SVC_HELLO; return ret; case GB_SVC_TYPE_INTF_RESET: return gb_svc_intf_reset_recv(op); case GB_SVC_TYPE_MODULE_INSERTED: return gb_svc_module_inserted_recv(op); case GB_SVC_TYPE_MODULE_REMOVED: return gb_svc_module_removed_recv(op); case GB_SVC_TYPE_INTF_MAILBOX_EVENT: return gb_svc_intf_mailbox_event_recv(op); case GB_SVC_TYPE_INTF_OOPS: return gb_svc_intf_oops_recv(op); default:
dev_warn(&svc->dev, "unsupported request 0x%02x\n", type); return -EINVAL;
}
}
/* * The SVC protocol is currently driven by the SVC, so the SVC device * is added from the connection request handler when enough * information has been received.
*/
ret = gb_connection_enable(svc->connection); if (ret) return ret;
/* * The SVC device may have been registered from the request handler.
*/ if (device_is_registered(&svc->dev)) {
gb_svc_debugfs_exit(svc);
gb_svc_watchdog_destroy(svc);
device_del(&svc->dev);
}
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.