Bluetooth: Rotate outgoing ACL packets via a pending queue

To ensure that we never have more outgoing ACL buffers available than
the controller is willing to accept we should hold on to them between
calling drv->send() and getting the corresponding Number of Completed
Packets event. This patch adds a temporary FIFO in bt_dev for this.

Change-Id: I918119a03081d507de2bb4a731b2709ea99a648d
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
diff --git a/net/bluetooth/conn.c b/net/bluetooth/conn.c
index e55e008..632d017 100644
--- a/net/bluetooth/conn.c
+++ b/net/bluetooth/conn.c
@@ -208,7 +208,7 @@
 		}
 
 		dev->drv->send(buf);
-		bt_buf_put(buf);
+		nano_fiber_fifo_put(&dev->acl_pend, buf);
 	}
 
 	BT_DBG("handle %u disconnected - cleaning up\n", conn->handle);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b69328b..73346ca 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -357,14 +357,22 @@
 
 	for (i = 0; i < num_handles; i++) {
 		uint16_t handle, count;
+		struct bt_buf *buf;
 
 		handle = sys_le16_to_cpu(evt->h[i].handle);
 		count = sys_le16_to_cpu(evt->h[i].count);
 
 		BT_DBG("handle %u count %u\n", handle, count);
 
-		while (count--)
+		while (count--) {
 			nano_fiber_sem_give(&dev.le_pkts_sem);
+			buf = nano_fiber_fifo_get(&dev.acl_pend);
+			if (!buf) {
+				BT_ERR("Mismatch with pending ACL buffers\n");
+				continue;
+			}
+			bt_buf_put(buf);
+		}
 	}
 }
 
@@ -647,6 +655,9 @@
 	if (err)
 		return err;
 
+	/* Initialize pending ACL packets FIFO */
+	nano_fifo_init(&dev.acl_pend);
+
 	/* Re-initialize buffers now that we know the ACL counts */
 	if (dev.le_pkts > ACL_OUT_MAX)
 		acl_out = ACL_OUT_MAX;
diff --git a/net/bluetooth/hci_core.h b/net/bluetooth/hci_core.h
index 1e0ca11..83dba36 100644
--- a/net/bluetooth/hci_core.h
+++ b/net/bluetooth/hci_core.h
@@ -71,6 +71,9 @@
 	/* Queue for outgoing HCI commands */
 	struct nano_fifo	cmd_queue;
 
+	/* Pending outgoing ACL packets */
+	struct nano_fifo	acl_pend;
+
 	/* Registered HCI driver */
 	struct bt_driver	*drv;
 };