staticint gb_interface_read_ara_dme(struct gb_interface *intf)
{
u32 sn0, sn1; int ret;
/* * Unless this is a Toshiba bridge, bail out until we have defined * standard GMP attributes.
*/ if (intf->ddbl1_manufacturer_id != TOSHIBA_DMID) {
dev_err(&intf->dev, "unknown manufacturer %08x\n",
intf->ddbl1_manufacturer_id); return -ENODEV;
}
ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_VID,
&intf->vendor_id); if (ret) return ret;
ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_PID,
&intf->product_id); if (ret) return ret;
ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN0, &sn0); if (ret) return ret;
ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN1, &sn1); if (ret) return ret;
intf->serial_number = (u64)sn1 << 32 | sn0;
return 0;
}
staticint gb_interface_read_dme(struct gb_interface *intf)
{ int ret;
/* DME attributes have already been read */ if (intf->dme_read) return 0;
ret = gb_interface_dme_attr_get(intf, DME_DDBL1_MANUFACTURERID,
&intf->ddbl1_manufacturer_id); if (ret) return ret;
ret = gb_interface_dme_attr_get(intf, DME_DDBL1_PRODUCTID,
&intf->ddbl1_product_id); if (ret) return ret;
/* Allocate an interface device id. */
ret = ida_alloc_range(&svc->device_id_map, GB_SVC_DEVICE_ID_MIN,
GB_SVC_DEVICE_ID_MAX, GFP_KERNEL); if (ret < 0) {
dev_err(&intf->dev, "failed to allocate device id: %d\n", ret); return ret;
}
device_id = ret;
ret = gb_svc_intf_device_id(svc, intf_id, device_id); if (ret) {
dev_err(&intf->dev, "failed to set device id %u: %d\n",
device_id, ret); goto err_ida_remove;
}
/* FIXME: Hard-coded AP device id. */
ret = gb_svc_route_create(svc, svc->ap_intf_id, GB_SVC_DEVICE_ID_AP,
intf_id, device_id); if (ret) {
dev_err(&intf->dev, "failed to create route: %d\n", ret); goto err_svc_id_free;
}
intf->device_id = device_id;
return 0;
err_svc_id_free: /* * XXX Should we tell SVC that this id doesn't belong to interface * XXX anymore.
*/
err_ida_remove:
ida_free(&svc->device_id_map, device_id);
mutex_lock(&intf->mutex); /* Make sure interface is still enabled. */ if (!intf->enabled) {
dev_dbg(&intf->dev, "mode switch aborted\n");
intf->mode_switch = false;
mutex_unlock(&intf->mutex); goto out_interface_put;
}
/* * Prepare the control device for mode switch and make sure to get an * extra reference before it goes away during interface disable.
*/
control = gb_control_get(intf->control);
gb_control_mode_switch_prepare(control);
gb_interface_disable(intf);
mutex_unlock(&intf->mutex);
timeout = msecs_to_jiffies(GB_INTERFACE_MODE_SWITCH_TIMEOUT);
ret = wait_for_completion_interruptible_timeout(
&intf->mode_switch_completion, timeout);
/* * T_TstSrcIncrement is written by the module on ES2 as a stand-in for the * init-status attribute DME_TOSHIBA_INIT_STATUS. The AP needs to read and * clear it after reading a non-zero value from it. * * FIXME: This is module-hardware dependent and needs to be extended for every * type of module we want to support.
*/ staticint gb_interface_read_and_clear_init_status(struct gb_interface *intf)
{ struct gb_host_device *hd = intf->hd; unsignedlong bootrom_quirks; unsignedlong s2l_quirks; int ret;
u32 value;
u16 attr;
u8 init_status;
/* * ES2 bridges use T_TstSrcIncrement for the init status. * * FIXME: Remove ES2 support
*/ if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)
attr = DME_T_TST_SRC_INCREMENT; else
attr = DME_TOSHIBA_GMP_INIT_STATUS;
ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id, attr,
DME_SELECTOR_INDEX_NULL, &value); if (ret) return ret;
/* * A nonzero init status indicates the module has finished * initializing.
*/ if (!value) {
dev_err(&intf->dev, "invalid init status\n"); return -ENODEV;
}
/* * Extract the init status. * * For ES2: We need to check lowest 8 bits of 'value'. * For ES3: We need to check highest 8 bits out of 32 of 'value'. * * FIXME: Remove ES2 support
*/ if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)
init_status = value & 0xff; else
init_status = value >> 24;
/* * Check if the interface is executing the quirky ES3 bootrom that, * for example, requires E2EFC, CSD and CSV to be disabled.
*/
bootrom_quirks = GB_INTERFACE_QUIRK_NO_CPORT_FEATURES |
GB_INTERFACE_QUIRK_FORCED_DISABLE |
GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH |
GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE;
s2l_quirks = GB_INTERFACE_QUIRK_NO_PM;
switch (init_status) { case GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED: case GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED:
intf->quirks |= bootrom_quirks; break; case GB_INIT_S2_LOADER_BOOT_STARTED: /* S2 Loader doesn't support runtime PM */
intf->quirks &= ~bootrom_quirks;
intf->quirks |= s2l_quirks; break; default:
intf->quirks &= ~bootrom_quirks;
intf->quirks &= ~s2l_quirks;
}
ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
GB_SVC_PWRMON_TYPE_VOL,
&measurement); if (ret) {
dev_err(&intf->dev, "failed to get voltage sample (%d)\n", ret); return ret;
}
ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
GB_SVC_PWRMON_TYPE_CURR,
&measurement); if (ret) {
dev_err(&intf->dev, "failed to get current sample (%d)\n", ret); return ret;
}
ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
GB_SVC_PWRMON_TYPE_PWR,
&measurement); if (ret) {
dev_err(&intf->dev, "failed to get power sample (%d)\n", ret); return ret;
}
/* * A Greybus module represents a user-replaceable component on a GMP * phone. An interface is the physical connection on that module. A * module may have more than one interface. * * Create a gb_interface structure to represent a discovered interface. * The position of interface within the Endo is encoded in "interface_id" * argument. * * Returns a pointer to the new interface or a null pointer if a * failure occurs due to memory exhaustion.
*/ struct gb_interface *gb_interface_create(struct gb_module *module,
u8 interface_id)
{ struct gb_host_device *hd = module->hd; struct gb_interface *intf;
intf = kzalloc(sizeof(*intf), GFP_KERNEL); if (!intf) return NULL;
ret = gb_svc_intf_activate(svc, intf->interface_id, &type); if (ret) {
dev_err(&intf->dev, "failed to activate: %d\n", ret); return ret;
}
switch (type) { case GB_SVC_INTF_TYPE_DUMMY:
*intf_type = GB_INTERFACE_TYPE_DUMMY; /* FIXME: handle as an error for now */ return -ENODEV; case GB_SVC_INTF_TYPE_UNIPRO:
*intf_type = GB_INTERFACE_TYPE_UNIPRO;
dev_err(&intf->dev, "interface type UniPro not supported\n"); /* FIXME: handle as an error for now */ return -ENODEV; case GB_SVC_INTF_TYPE_GREYBUS:
*intf_type = GB_INTERFACE_TYPE_GREYBUS; break; default:
dev_err(&intf->dev, "unknown interface type: %u\n", type);
*intf_type = GB_INTERFACE_TYPE_UNKNOWN; return -ENODEV;
}
/* * At present, we assume a UniPro-only module to be a Greybus module that * failed to send its mailbox poke. There is some reason to believe that this * is because of a bug in the ES3 bootrom. * * FIXME: Check if this is a Toshiba bridge before retrying?
*/ staticint _gb_interface_activate_es3_hack(struct gb_interface *intf, enum gb_interface_type *type)
{ int retries = 3; int ret;
while (retries--) {
ret = _gb_interface_activate(intf, type); if (ret == -ENODEV && *type == GB_INTERFACE_TYPE_UNIPRO) continue;
break;
}
return ret;
}
/* * Activate an interface. * * Locking: Caller holds the interface mutex.
*/ int gb_interface_activate(struct gb_interface *intf)
{ enum gb_interface_type type; int ret;
switch (intf->type) { case GB_INTERFACE_TYPE_INVALID: case GB_INTERFACE_TYPE_GREYBUS:
ret = _gb_interface_activate_es3_hack(intf, &type); break; default:
ret = _gb_interface_activate(intf, &type);
}
/* Make sure type is detected correctly during reactivation. */ if (intf->type != GB_INTERFACE_TYPE_INVALID) { if (type != intf->type) {
dev_err(&intf->dev, "failed to detect interface type\n");
if (!ret)
gb_interface_deactivate(intf);
return -EIO;
}
} else {
intf->type = type;
}
return ret;
}
/* * Deactivate an interface. * * Locking: Caller holds the interface mutex.
*/ void gb_interface_deactivate(struct gb_interface *intf)
{ if (!intf->active) return;
trace_gb_interface_deactivate(intf);
/* Abort any ongoing mode switch. */ if (intf->mode_switch)
complete(&intf->mode_switch_completion);
/* * Enable an interface by enabling its control connection, fetching the * manifest and other information over it, and finally registering its child * devices. * * Locking: Caller holds the interface mutex.
*/ int gb_interface_enable(struct gb_interface *intf)
{ struct gb_control *control; struct gb_bundle *bundle, *tmp; int ret, size; void *manifest;
ret = gb_interface_read_and_clear_init_status(intf); if (ret) {
dev_err(&intf->dev, "failed to clear init status: %d\n", ret); return ret;
}
/* Establish control connection */
control = gb_control_create(intf); if (IS_ERR(control)) {
dev_err(&intf->dev, "failed to create control device: %ld\n",
PTR_ERR(control)); return PTR_ERR(control);
}
intf->control = control;
ret = gb_control_enable(intf->control); if (ret) goto err_put_control;
/* Get manifest size using control protocol on CPort */
size = gb_control_get_manifest_size_operation(intf); if (size <= 0) {
dev_err(&intf->dev, "failed to get manifest size: %d\n", size);
if (size)
ret = size; else
ret = -EINVAL;
goto err_disable_control;
}
manifest = kmalloc(size, GFP_KERNEL); if (!manifest) {
ret = -ENOMEM; goto err_disable_control;
}
/* Get manifest using control protocol on CPort */
ret = gb_control_get_manifest_operation(intf, manifest, size); if (ret) {
dev_err(&intf->dev, "failed to get manifest: %d\n", ret); goto err_free_manifest;
}
/* * Parse the manifest and build up our data structures representing * what's in it.
*/ if (!gb_manifest_parse(intf, manifest, size)) {
dev_err(&intf->dev, "failed to parse manifest\n");
ret = -EINVAL; goto err_destroy_bundles;
}
ret = gb_control_get_bundle_versions(intf->control); if (ret) goto err_destroy_bundles;
/* Register the control device and any bundles */
ret = gb_control_add(intf->control); if (ret) goto err_destroy_bundles;
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.