From: Viresh Kumar Date: Thu, 24 Sep 2015 21:40:29 +0000 (-0700) Subject: greybus: svc: Read and clear module's boot status X-Git-Tag: v4.14-rc1~2366^2~378^2~21^2~1161 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6bec5c78e59dd847c095f4a868baf14be871c8bb;p=platform%2Fkernel%2Flinux-rpi.git greybus: svc: Read and clear module's boot status As per the module's boot sequence diagram, the AP needs to read/clear T_TstSrcIncrement attribute on hotplug (svc) events. Implement that. FIXME: This is module-hardware dependent and needs to be extended for every type of module we want to support. [ Based on work by Marti & Eli to clear the attribute with DME set] Signed-off-by: Viresh Kumar Reviewed-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h index b3d0c57..117f55e 100644 --- a/drivers/staging/greybus/greybus_protocols.h +++ b/drivers/staging/greybus/greybus_protocols.h @@ -829,6 +829,10 @@ struct gb_svc_dme_peer_set_response { __le16 result_code; } __packed; +/* Attributes for peer get/set operations */ +#define DME_ATTR_SELECTOR_INDEX 0 +#define DME_ATTR_T_TST_SRC_INCREMENT 0x4083 + struct gb_svc_route_create_request { __u8 intf1_id; __u8 dev1_id; diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c index 0e029ce..b59d76f 100644 --- a/drivers/staging/greybus/svc.c +++ b/drivers/staging/greybus/svc.c @@ -176,6 +176,42 @@ int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector, } EXPORT_SYMBOL_GPL(gb_svc_dme_peer_set); +/* + * T_TstSrcIncrement is written by the module on ES2 as a stand-in for boot + * status attribute. 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. + */ +static int gb_svc_read_and_clear_module_boot_status(struct gb_interface *intf) +{ + struct greybus_host_device *hd = intf->hd; + int ret; + u32 value; + + /* Read and clear boot status in T_TstSrcIncrement */ + ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id, + DME_ATTR_T_TST_SRC_INCREMENT, + DME_ATTR_SELECTOR_INDEX, &value); + + if (ret) + return ret; + + /* + * A nonzero boot status indicates the module has finished + * booting. Clear it. + */ + if (!value) { + dev_err(&intf->dev, "Module not ready yet\n"); + return -ENODEV; + } + + return gb_svc_dme_peer_set(hd->svc, intf->interface_id, + DME_ATTR_T_TST_SRC_INCREMENT, + DME_ATTR_SELECTOR_INDEX, 0); +} + int gb_svc_connection_create(struct gb_svc *svc, u8 intf1_id, u16 cport1_id, u8 intf2_id, u16 cport2_id) @@ -398,6 +434,10 @@ static void svc_process_hotplug(struct work_struct *work) goto free_svc_hotplug; } + ret = gb_svc_read_and_clear_module_boot_status(intf); + if (ret) + goto destroy_interface; + intf->unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id); intf->unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id); intf->ara_vend_id = le32_to_cpu(hotplug->data.ara_vend_id);