}
 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)
                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);