greybus: svc: Expose and retain VID/PID received from bootrom for ES2
authorViresh Kumar <viresh.kumar@linaro.org>
Fri, 22 Jan 2016 10:46:08 +0000 (16:16 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 22 Jan 2016 23:24:58 +0000 (15:24 -0800)
ES2 chips doesn't have efuses for storing module's vendor_id and
product_id and so we have hacked bootrom earlier using firmware
protocol, so that VID/PID can be received for fetching firmware
packages.

Another requirement is to expose them to sysfs, so that modules can be
identified properly.

That can be easily solved by updating interface's VID/PID, when fetched
using firmware protocol and later reusing them while the module switches
its identity from bootrom to firmware.

Do that only if the module is ES2 and the VID/PID sent during hotplug
are both 0.

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/firmware.c
drivers/staging/greybus/svc.c

index ee239a913e0c479f0e8a8faf32f407e9abdc98b6..37895107e427c38418b86dff3e46fd2b1fcc4e32 100644 (file)
@@ -14,8 +14,6 @@
 struct gb_firmware {
        struct gb_connection    *connection;
        const struct firmware   *fw;
-       u32                     vendor_id;
-       u32                     product_id;
 };
 
 static void free_firmware(struct gb_firmware *firmware)
@@ -31,7 +29,7 @@ static void free_firmware(struct gb_firmware *firmware)
  * This fetches VID/PID (over firmware protocol) for es2 chip only, when VID/PID
  * already sent during hotplug are 0.
  *
- * Otherwise, we keep firmware->vendor_id/product_id same as what's passed
+ * Otherwise, we keep intf->vendor_id/product_id same as what's passed
  * during hotplug.
  */
 static void firmware_es2_fixup_vid_pid(struct gb_firmware *firmware)
@@ -59,11 +57,18 @@ static void firmware_es2_fixup_vid_pid(struct gb_firmware *firmware)
                return;
        }
 
-       firmware->vendor_id = le32_to_cpu(response.vendor_id);
-       firmware->product_id = le32_to_cpu(response.product_id);
+       /*
+        * NOTE: This is hacked, so that the same values of VID/PID can be used
+        * by next firmware level as well. The uevent for bootrom will still
+        * have VID/PID as 0, though after this point the sysfs files will start
+        * showing the updated values. But yeah, that's a bit racy as the same
+        * sysfs files would be showing 0 before this point.
+        */
+       intf->vendor_id = le32_to_cpu(response.vendor_id);
+       intf->product_id = le32_to_cpu(response.product_id);
 
        dev_dbg(&connection->bundle->dev, "Firmware got vid (0x%x)/pid (0x%x)\n",
-               firmware->vendor_id, firmware->product_id);
+               intf->vendor_id, intf->product_id);
 }
 
 /* This returns path of the firmware blob on the disk */
@@ -86,7 +91,7 @@ static int download_firmware(struct gb_firmware *firmware, u8 stage)
        snprintf(firmware_name, sizeof(firmware_name),
                 "ara_%08x_%08x_%08x_%08x_%02x.tftf",
                 intf->ddbl1_manufacturer_id, intf->ddbl1_product_id,
-                firmware->vendor_id, firmware->product_id, stage);
+                intf->vendor_id, intf->product_id, stage);
 
        // FIXME:
        // Turn to dev_dbg later after everyone has valid bootloaders with good
@@ -246,9 +251,6 @@ static int gb_firmware_connection_init(struct gb_connection *connection)
        firmware->connection = connection;
        connection->private = firmware;
 
-       firmware->vendor_id = connection->intf->vendor_id;
-       firmware->product_id = connection->intf->product_id;
-
        firmware_es2_fixup_vid_pid(firmware);
 
        /* Tell bootrom we're ready. */
index feadb624cfd427adbf4dcba6e07298117730e902..85eb7eaae7374bba966f477860f8ad0057ba6e30 100644 (file)
@@ -464,6 +464,8 @@ static void gb_svc_process_intf_hotplug(struct gb_operation *operation)
        struct gb_host_device *hd = connection->hd;
        struct gb_interface *intf;
        u8 intf_id, device_id;
+       u32 vendor_id = 0;
+       u32 product_id = 0;
        int ret;
 
        /* The request message size has already been verified. */
@@ -474,6 +476,14 @@ static void gb_svc_process_intf_hotplug(struct gb_operation *operation)
 
        intf = gb_interface_find(hd, intf_id);
        if (intf) {
+               /*
+                * For ES2, we need to maintain the same vendor/product ids we
+                * got from bootrom, otherwise userspace can't distinguish
+                * between modules.
+                */
+               vendor_id = intf->vendor_id;
+               product_id = intf->product_id;
+
                /*
                 * We have received a hotplug request for an interface that
                 * already exists.
@@ -506,6 +516,20 @@ static void gb_svc_process_intf_hotplug(struct gb_operation *operation)
        intf->product_id = le32_to_cpu(request->data.ara_prod_id);
        intf->serial_number = le64_to_cpu(request->data.serial_number);
 
+       /*
+        * Use VID/PID specified at hotplug if:
+        * - Bridge ASIC chip isn't ES2
+        * - Received non-zero Vendor/Product ids
+        *
+        * Otherwise, use the ids we received from bootrom.
+        */
+       if (intf->ddbl1_manufacturer_id == ES2_DDBL1_MFR_ID &&
+           intf->ddbl1_product_id == ES2_DDBL1_PROD_ID &&
+           intf->vendor_id == 0 && intf->product_id == 0) {
+               intf->vendor_id = vendor_id;
+               intf->product_id = product_id;
+       }
+
        ret = gb_svc_read_and_clear_module_boot_status(intf);
        if (ret) {
                dev_err(&svc->dev, "failed to clear boot status of interface %u: %d\n",