WiFi-HAL: Write and read data to/from ring buffers record wise

Currently, ring buffer writes and reads happens with byte
boundary. Add support to write only records and do not split any
records.

BUG=23783279
Change-Id: I2342f86cc4c3a678f21f1595b81e0cdf6d24b2c0
diff --git a/qcwcn/wifi_hal/rb_wrapper.cpp b/qcwcn/wifi_hal/rb_wrapper.cpp
index 02338c0..3a9b109 100644
--- a/qcwcn/wifi_hal/rb_wrapper.cpp
+++ b/qcwcn/wifi_hal/rb_wrapper.cpp
@@ -88,13 +88,22 @@
 wifi_error ring_buffer_write(struct rb_info *rb_info, u8 *buf, size_t length,
                              int no_of_records)
 {
-    if (rb_write(rb_info->rb_ctx, buf, length, 0) != RB_SUCCESS) {
-        push_out_rb_data(rb_info);
-        /* Try writing the data after reading it out */
-        if (rb_write(rb_info->rb_ctx, buf, length, 0) != RB_SUCCESS) {
-            ALOGE("Failed to write %zu bytes to rb %s", length, rb_info->name);
-            return WIFI_ERROR_OUT_OF_MEMORY;
+    enum rb_status status;
+
+    status = rb_write(rb_info->rb_ctx, buf, length, 0);
+    if ((status == RB_FULL) || (status == RB_RETRY)) {
+         push_out_rb_data(rb_info);
+         /* Try writing the data after reading it out */
+        status = rb_write(rb_info->rb_ctx, buf, length, 0);
+        if (status != RB_SUCCESS) {
+            ALOGE("Failed to rewrite %zu bytes to rb %s with error %d", length,
+                  rb_info->name, status);
+            return WIFI_ERROR_UNKNOWN;
         }
+    } else if (status == RB_FAILURE) {
+        ALOGE("Failed to write %zu bytes to rb %s with error %d", length,
+              rb_info->name, status);
+        return WIFI_ERROR_UNKNOWN;
     }
 
     rb_info->written_records += no_of_records;
diff --git a/qcwcn/wifi_hal/ring_buffer.cpp b/qcwcn/wifi_hal/ring_buffer.cpp
index 771de1a..fa90de1 100644
--- a/qcwcn/wifi_hal/ring_buffer.cpp
+++ b/qcwcn/wifi_hal/ring_buffer.cpp
@@ -46,12 +46,18 @@
     RB_FALSE = 1
 };
 
+typedef struct rb_entry_s {
+    u8 *data;
+    unsigned int last_wr_index;
+    u8 full;
+} rb_entry_t;
+
 typedef struct ring_buf_cb {
     unsigned int rd_buf_no; // Current buffer number to be read from
     unsigned int wr_buf_no; // Current buffer number to be written into
     unsigned int cur_rd_buf_idx; // Read index within the current read buffer
     unsigned int cur_wr_buf_idx; // Write index within the current write buffer
-    u8 **bufs; // Array of buffer pointers
+    rb_entry_t *bufs; // Array of buffer pointers
 
     unsigned int max_num_bufs; // Maximum number of buffers that should be used
     size_t each_buf_size; // Size of each buffer in bytes
@@ -102,13 +108,13 @@
     }
     memset(rbc, 0, sizeof(struct ring_buf_cb));
 
-    rbc->bufs = (u8 **)malloc(num_bufs * sizeof(void *));
+    rbc->bufs = (rb_entry_t *)malloc(num_bufs * sizeof(rb_entry_t));
     if (rbc->bufs == NULL) {
         free(rbc);
         ALOGE("Failed to alloc rbc->bufs");
         return NULL;
     }
-    memset(rbc->bufs, 0, (num_bufs * sizeof(void *)));
+    memset(rbc->bufs, 0, (num_bufs * sizeof(rb_entry_t)));
 
     rbc->each_buf_size = size_of_buf;
     rbc->max_num_bufs = num_bufs;
@@ -134,7 +140,7 @@
         // TODO handle the lock destroy failure
     }
     for (buf_no = 0; buf_no < rbc->max_num_bufs; buf_no++) {
-        free(rbc->bufs[buf_no]);
+        free(rbc->bufs[buf_no].data);
     }
     free(rbc->bufs);
     free(rbc);
@@ -147,25 +153,83 @@
     unsigned int push_in_rd_ptr = 0; // push required in read pointer because of
                                      // write in current buffer
     unsigned int total_push_in_rd_ptr = 0; // Total amount of push in read pointer in this write
+    size_t record_length = length;
 
-    /* Check if this write fits into remaining ring buffer */
-    if ((overwrite == 0) &&
-        (length >
-         ((rbc->max_num_bufs * rbc->each_buf_size) - rbc->cur_valid_bytes))) {
+    if (record_length > rbc->each_buf_size) {
         return RB_FAILURE;
     }
 
+    if (overwrite == 0) {
+        /* Check if the complete RB is full. If the current wr_buf is also
+         * full, it indicates that the complete RB is full
+         */
+        if (rbc->bufs[rbc->wr_buf_no].full == 1)
+            return RB_FULL;
+        /* Check whether record fits in current buffer */
+        if (rbc->wr_buf_no == rbc->rd_buf_no) {
+            if ((rbc->cur_wr_buf_idx == rbc->cur_rd_buf_idx) &&
+                rbc->cur_valid_bytes) {
+                return RB_FULL;
+            } else if (rbc->cur_wr_buf_idx < rbc->cur_rd_buf_idx) {
+                if (record_length >
+                    (rbc->cur_rd_buf_idx - rbc->cur_wr_buf_idx)) {
+                    return RB_FULL;
+                }
+            } else {
+                if (record_length > (rbc->each_buf_size - rbc->cur_wr_buf_idx)) {
+                    /* Check if the next buffer is not full to write this record into
+                     * next buffer
+                     */
+                    unsigned int next_buf_no = rbc->wr_buf_no + 1;
+
+                    if (next_buf_no >= rbc->max_num_bufs) {
+                        next_buf_no = 0;
+                    }
+                    if (rbc->bufs[next_buf_no].full == 1) {
+                        return RB_FULL;
+                    }
+                }
+            }
+        } else if (record_length > (rbc->each_buf_size - rbc->cur_wr_buf_idx)) {
+            /* Check if the next buffer is not full to write this record into
+             * next buffer
+             */
+            unsigned int next_buf_no = rbc->wr_buf_no + 1;
+
+            if (next_buf_no >= rbc->max_num_bufs) {
+                next_buf_no = 0;
+            }
+            if (rbc->bufs[next_buf_no].full == 1) {
+                return RB_FULL;
+            }
+        }
+    }
+
+    /* Go to next buffer if the current buffer is not enough to write the
+     * complete record
+     */
+    if (record_length > (rbc->each_buf_size - rbc->cur_wr_buf_idx)) {
+        rbc->bufs[rbc->wr_buf_no].full = 1;
+        rbc->bufs[rbc->wr_buf_no].last_wr_index = rbc->cur_wr_buf_idx;
+        rbc->wr_buf_no++;
+        if (rbc->wr_buf_no == rbc->max_num_bufs) {
+            rbc->wr_buf_no = 0;
+        }
+        rbc->cur_wr_buf_idx = 0;
+    }
+
+
     /* In each iteration of below loop, the data that can be fit into
      * buffer @wr_buf_no will be copied from input buf */
     while (bytes_written < length) {
         unsigned int cur_copy_len;
 
         /* Allocate a buffer if no buf available @ wr_buf_no */
-        if (rbc->bufs[rbc->wr_buf_no] == NULL) {
-            rbc->bufs[rbc->wr_buf_no] = (u8 *)malloc(rbc->each_buf_size);
-            if (rbc->bufs[rbc->wr_buf_no] == NULL) {
+        if (rbc->bufs[rbc->wr_buf_no].data == NULL) {
+            rbc->bufs[rbc->wr_buf_no].data = (u8 *)malloc(rbc->each_buf_size);
+            if (rbc->bufs[rbc->wr_buf_no].data == NULL) {
                 ALOGE("Failed to alloc write buffer");
-                return RB_FAILURE;
+                return RB_RETRY;
             }
         }
 
@@ -193,13 +257,18 @@
                     push_in_rd_ptr += cur_copy_len -
                                     (rbc->cur_rd_buf_idx - rbc->cur_wr_buf_idx);
                     rbc->cur_rd_buf_idx = rbc->cur_wr_buf_idx + cur_copy_len;
-                    if (rbc->cur_rd_buf_idx == rbc->each_buf_size) {
+                    if (rbc->cur_rd_buf_idx >=
+                        rbc->bufs[rbc->rd_buf_no].last_wr_index) {
                         rbc->cur_rd_buf_idx = 0;
                         rbc->rd_buf_no++;
                         if (rbc->rd_buf_no == rbc->max_num_bufs) {
                             rbc->rd_buf_no = 0;
                             ALOGD("Pushing read to the start of ring buffer");
                         }
+                        /* the previous buffer might have little more empty room
+                         * after overwriting the remaining bytes
+                         */
+                        rbc->bufs[rbc->wr_buf_no].full = 0;
                     }
                 }
             }
@@ -209,7 +278,7 @@
         /* don't use lock while doing memcpy, so that we don't block the read
          * context for too long. There is no harm while writing the memory if
          * locking is properly done while upgrading the pointers */
-        memcpy((rbc->bufs[rbc->wr_buf_no] + rbc->cur_wr_buf_idx),
+        memcpy((rbc->bufs[rbc->wr_buf_no].data + rbc->cur_wr_buf_idx),
                (buf + bytes_written),
                cur_copy_len);
 
@@ -218,6 +287,8 @@
         rbc->cur_wr_buf_idx += cur_copy_len;
         if (rbc->cur_wr_buf_idx == rbc->each_buf_size) {
             /* Increment the wr_buf_no as the current buffer is full */
+            rbc->bufs[rbc->wr_buf_no].full = 1;
+            rbc->bufs[rbc->wr_buf_no].last_wr_index = rbc->cur_wr_buf_idx;
             rbc->wr_buf_no++;
             if (rbc->wr_buf_no == rbc->max_num_bufs) {
                 ALOGD("Write rolling over to the start of ring buffer");
@@ -273,7 +344,7 @@
     while (bytes_read < max_length) {
         unsigned int cur_cpy_len;
 
-        if (rbc->bufs[rbc->rd_buf_no] == NULL) {
+        if (rbc->bufs[rbc->rd_buf_no].data == NULL) {
             break;
         }
 
@@ -313,7 +384,7 @@
         }
 
         memcpy((buf + bytes_read),
-               (rbc->bufs[rbc->rd_buf_no] + rbc->cur_rd_buf_idx),
+               (rbc->bufs[rbc->rd_buf_no].data + rbc->cur_rd_buf_idx),
                cur_cpy_len);
 
         /* Update the read index */
@@ -321,8 +392,8 @@
         if (rbc->cur_rd_buf_idx == rbc->each_buf_size) {
             /* Increment rd_buf_no as the current buffer is completely read */
             if (rbc->rd_buf_no != rbc->wr_buf_no) {
-                free(rbc->bufs[rbc->rd_buf_no]);
-                rbc->bufs[rbc->rd_buf_no] = NULL;
+                free(rbc->bufs[rbc->rd_buf_no].data);
+                rbc->bufs[rbc->rd_buf_no].data = NULL;
             }
             rbc->rd_buf_no++;
             if (rbc->rd_buf_no == rbc->max_num_bufs) {
@@ -365,12 +436,25 @@
     u8 *buf;
 
     /* If no buffer is available for reading */
-    if (rbc->bufs[rbc->rd_buf_no] == NULL) {
+    if (rbc->bufs[rbc->rd_buf_no].data == NULL) {
         *length = 0;
         return NULL;
     }
 
     rb_lock(&rbc->rb_rw_lock);
+    if ((rbc->bufs[rbc->rd_buf_no].full == 1) &&
+        (rbc->cur_rd_buf_idx == rbc->bufs[rbc->rd_buf_no].last_wr_index)) {
+        if (rbc->wr_buf_no != rbc->rd_buf_no) {
+            free(rbc->bufs[rbc->rd_buf_no].data);
+            rbc->bufs[rbc->rd_buf_no].data = NULL;
+        }
+        rbc->bufs[rbc->rd_buf_no].full = 0;
+        rbc->rd_buf_no++;
+        if (rbc->rd_buf_no == rbc->max_num_bufs) {
+            rbc->rd_buf_no = 0;
+        }
+        rbc->cur_rd_buf_idx = 0;
+    }
 
     if (rbc->wr_buf_no == rbc->rd_buf_no) {
         /* If read and write are happening on the same buffer currently, use
@@ -386,24 +470,26 @@
             cur_read_len = rbc->cur_wr_buf_idx - rbc->cur_rd_buf_idx;
         } else {
             /* write is rolled over and just behind the read */
-            cur_read_len = rbc->each_buf_size - rbc->cur_rd_buf_idx;
+            cur_read_len = rbc->bufs[rbc->rd_buf_no].last_wr_index - rbc->cur_rd_buf_idx;
         }
     } else {
         if (rbc->cur_rd_buf_idx == 0) {
             /* The complete buffer can be read out */
-            cur_read_len = rbc->each_buf_size;
+            cur_read_len = rbc->bufs[rbc->rd_buf_no].last_wr_index;
         } else {
             /* Read the remaining bytes in this buffer */
-            cur_read_len = rbc->each_buf_size - rbc->cur_rd_buf_idx;
+            cur_read_len = rbc->bufs[rbc->rd_buf_no].last_wr_index - rbc->cur_rd_buf_idx;
         }
     }
 
-    if (cur_read_len == rbc->each_buf_size) {
+    if ((rbc->bufs[rbc->rd_buf_no].full == 1) &&
+         (rbc->cur_rd_buf_idx == 0)) {
         /* Pluck out the complete buffer and send it out */
-        buf = rbc->bufs[rbc->rd_buf_no];
-        rbc->bufs[rbc->rd_buf_no] = NULL;
+        buf = rbc->bufs[rbc->rd_buf_no].data;
+        rbc->bufs[rbc->rd_buf_no].data = NULL;
 
         /* Move to the next buffer */
+        rbc->bufs[rbc->rd_buf_no].full = 0;
         rbc->rd_buf_no++;
         if (rbc->rd_buf_no == rbc->max_num_bufs) {
             ALOGD("Read rolling over to the start of ring buffer");
@@ -414,14 +500,17 @@
          * and copy the data into it.
          */
         buf = (u8 *)malloc(cur_read_len);
-        memcpy(buf, (rbc->bufs[rbc->rd_buf_no] + rbc->cur_rd_buf_idx), cur_read_len);
+        memcpy(buf,
+               (rbc->bufs[rbc->rd_buf_no].data + rbc->cur_rd_buf_idx),
+               cur_read_len);
 
         /* Update the read index */
-        if ((cur_read_len + rbc->cur_rd_buf_idx) == rbc->each_buf_size) {
+        if (rbc->bufs[rbc->rd_buf_no].full == 1) {
             if (rbc->wr_buf_no != rbc->rd_buf_no) {
-                free(rbc->bufs[rbc->rd_buf_no]);
-                rbc->bufs[rbc->rd_buf_no] = NULL;
+                free(rbc->bufs[rbc->rd_buf_no].data);
+                rbc->bufs[rbc->rd_buf_no].data = NULL;
             }
+            rbc->bufs[rbc->rd_buf_no].full = 0;
             rbc->rd_buf_no++;
             if (rbc->rd_buf_no == rbc->max_num_bufs) {
                 rbc->rd_buf_no = 0;
diff --git a/qcwcn/wifi_hal/ring_buffer.h b/qcwcn/wifi_hal/ring_buffer.h
index 4af5578..d47f8d9 100644
--- a/qcwcn/wifi_hal/ring_buffer.h
+++ b/qcwcn/wifi_hal/ring_buffer.h
@@ -33,6 +33,8 @@
 enum rb_status {
     RB_SUCCESS = 0,
     RB_FAILURE = 1,
+    RB_FULL = 2,
+    RB_RETRY = 3,
 };
 
 struct rb_stats {