greybus: svc: reconfig APBridgeA-Switch link to handle required load
authorMitchell Tasman <tasman@leaflabs.com>
Wed, 4 May 2016 21:30:23 +0000 (17:30 -0400)
committerGreg Kroah-Hartman <gregkh@google.com>
Thu, 5 May 2016 01:41:05 +0000 (18:41 -0700)
SW-4894, SW-4389, and share a common root cause, namely that
the power-on reset configuration of the APBridgeA-Switch link of PWM
Gear 1, 1 Lane, Slow Auto, is insufficient to handle some required
traffic loads, such as 3 audio streams plus boot-over-UniPro or 4 audio
streams.

The correct long-term solution is to implement a UniPro Power Mode
Manager as in that considers the demands placed on the network,
and adjusts power modes accordingly.

The present commit implements a short-term, brute-force hack to allow
continued system testing:
- Upon receiving an SVC HELLO request, schedule deferred work to
  reconfigure the APB1-Switch link to PWM G2, 1 lane, Slow Auto
- When the Camera driver transitions a White Camera module from active to
  inactive, return the APB1-Switch link to PWM G2, 1 lane, Slow Auto

The Camera driver already steps up the APBridgeA-Camera link speed while a
camera module is active, which affords sufficient margin for simultaneous
audio and hotplug activity, and the Camera driver already steps down the
link speed thereafter: the change made by the present patch is simply to
tweak the stepped-down power mode to match the new baseline configuration.

Signed-off-by: Mitchell Tasman <tasman@leaflabs.com>
Tested-by: Mark Greer <mgreer@animalcreek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/camera.c
drivers/staging/greybus/svc.c

index 956fbf0..ba76f56 100644 (file)
@@ -131,9 +131,9 @@ static int gb_camera_set_intf_power_mode(struct gb_camera *gcam, u8 intf_id,
                ret = gb_svc_intf_set_power_mode(svc, intf_id,
                                                 GB_SVC_UNIPRO_HS_SERIES_A,
                                                 GB_SVC_UNIPRO_SLOW_AUTO_MODE,
-                                                1, 2,
+                                                2, 1,
                                                 GB_SVC_UNIPRO_SLOW_AUTO_MODE,
-                                                1, 2,
+                                                2, 1,
                                                 0, 0);
 
        return ret;
index 577e680..f3ee94e 100644 (file)
@@ -23,6 +23,8 @@ struct gb_svc_deferred_request {
 };
 
 
+static int gb_svc_queue_deferred_request(struct gb_operation *operation);
+
 static ssize_t endo_id_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
@@ -695,7 +697,7 @@ static int gb_svc_hello(struct gb_operation *op)
 
        gb_svc_debugfs_init(svc);
 
-       return 0;
+       return gb_svc_queue_deferred_request(op);
 }
 
 static struct gb_interface *gb_svc_interface_lookup(struct gb_svc *svc,
@@ -754,6 +756,35 @@ static void gb_svc_intf_reenable(struct gb_svc *svc, struct gb_interface *intf)
        mutex_unlock(&intf->mutex);
 }
 
+static void gb_svc_process_hello_deferred(struct gb_operation *operation)
+{
+       struct gb_connection *connection = operation->connection;
+       struct gb_svc *svc = gb_connection_get_data(connection);
+       int ret;
+
+       /*
+        * XXX This is a hack/work-around to reconfigure the APBridgeA-Switch
+        * link to PWM G2, 1 Lane, Slow Auto, so that it has sufficient
+        * bandwidth for 3 audio streams plus boot-over-UniPro of a hot-plugged
+        * module.
+        *
+        * The code should be removed once SW-2217, Heuristic for UniPro
+        * Power Mode Changes is resolved.
+        */
+       ret = gb_svc_intf_set_power_mode(svc, svc->ap_intf_id,
+                                       GB_SVC_UNIPRO_HS_SERIES_A,
+                                       GB_SVC_UNIPRO_SLOW_AUTO_MODE,
+                                       2, 1,
+                                       GB_SVC_UNIPRO_SLOW_AUTO_MODE,
+                                       2, 1,
+                                       0, 0);
+
+       if (ret)
+               dev_warn(&svc->dev,
+                       "power mode change failed on AP to switch link: %d\n",
+                       ret);
+}
+
 static void gb_svc_process_intf_hotplug(struct gb_operation *operation)
 {
        struct gb_svc_intf_hotplug_request *request;
@@ -963,6 +994,9 @@ static void gb_svc_process_deferred_request(struct work_struct *work)
        type = operation->request->header->type;
 
        switch (type) {
+       case GB_SVC_TYPE_SVC_HELLO:
+               gb_svc_process_hello_deferred(operation);
+               break;
        case GB_SVC_TYPE_INTF_HOTPLUG:
                gb_svc_process_intf_hotplug(operation);
                break;