greybus: svc: Read and clear module's boot status
authorViresh Kumar <viresh.kumar@linaro.org>
Thu, 24 Sep 2015 21:40:29 +0000 (14:40 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Thu, 24 Sep 2015 22:17:45 +0000 (15:17 -0700)
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 <viresh.kumar@linaro.org>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/greybus_protocols.h
drivers/staging/greybus/svc.c

index b3d0c57ea0730f20c3b52ba092290a7e67c821b5..117f55e4463dcaf4fb013559f87fe1497f233090 100644 (file)
@@ -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;
index 0e029ce4037989e66cc780e279f2417a1be5562b..b59d76fcc40581020f4a39d6b269f20228f8476f 100644 (file)
@@ -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);