greybus: loopback: Add asynchronous backoff
authorBryan O'Donoghue <bryan.odonoghue@linaro.org>
Fri, 11 Dec 2015 13:46:53 +0000 (13:46 +0000)
committerGreg Kroah-Hartman <gregkh@google.com>
Sat, 12 Dec 2015 00:18:40 +0000 (16:18 -0800)
A specific request from the firmware people is the ability to back-off from
sending more asynchronous operations once a specific number of operations
are in-flight.

This patch adds that ability - with a new sysfs parameter
'outstanding_operations_max' which controls the maximum number of
operations that can be outstanding/in-flight at any time.

When outstanding_operations_max contains a non-zero value and asynchronous
operations are being used - we will back-off until the completion counter
is < outstanding_operations_max. Tested in both synchronous and
asynchronous mode and with gb_loopback_connection_exit() interrupting
in-flight operations.

Suggested-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/loopback.c

index 4814f948eea3516f396e9c0688e8968634ba82cb..c35d22733a36fbc0172d9e8202d71e38d08b1242 100644 (file)
@@ -98,6 +98,7 @@ struct gb_loopback {
        u32 jiffy_timeout;
        u32 timeout_min;
        u32 timeout_max;
+       u32 outstanding_operations_max;
        u32 lbid;
        u64 elapsed_nsecs;
        u32 apbridge_latency_ts;
@@ -311,6 +312,8 @@ gb_dev_loopback_ro_attr(iteration_count, false);
 gb_dev_loopback_rw_attr(async, u);
 /* Timeout of an individual asynchronous request */
 gb_dev_loopback_rw_attr(timeout, u);
+/* Maximum number of in-flight operations before back-off */
+gb_dev_loopback_rw_attr(outstanding_operations_max, u);
 
 static struct attribute *loopback_attrs[] = {
        &dev_attr_latency_min.attr,
@@ -338,6 +341,7 @@ static struct attribute *loopback_attrs[] = {
        &dev_attr_requests_completed.attr,
        &dev_attr_requests_timedout.attr,
        &dev_attr_timeout.attr,
+       &dev_attr_outstanding_operations_max.attr,
        &dev_attr_timeout_min.attr,
        &dev_attr_timeout_max.attr,
        NULL,
@@ -911,6 +915,16 @@ static void gb_loopback_calculate_stats(struct gb_loopback *gb)
                                 gb->gpbridge_latency_ts);
 }
 
+static void gb_loopback_async_wait_to_send(struct gb_loopback *gb)
+{
+       if (!(gb->async && gb->outstanding_operations_max))
+               return;
+       wait_event_interruptible(gb->wq_completion,
+                                (atomic_read(&gb->outstanding_operations) <
+                                 gb->outstanding_operations_max) ||
+                                 kthread_should_stop());
+}
+
 static int gb_loopback_fn(void *data)
 {
        int error = 0;
@@ -924,7 +938,11 @@ static int gb_loopback_fn(void *data)
                if (!gb->type)
                        wait_event_interruptible(gb->wq, gb->type ||
                                                 kthread_should_stop());
+               if (kthread_should_stop())
+                       break;
 
+               /* Limit the maximum number of in-flight async operations */
+               gb_loopback_async_wait_to_send(gb);
                if (kthread_should_stop())
                        break;