This is an automated email from the ASF dual-hosted git repository.
andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
The following commit(s) were added to refs/heads/master by this push:
new e178ff0d nimble/transport: Add generic IPC transport with flow control
e178ff0d is described below
commit e178ff0d9f9c970e1b8df3358f393f9d564f2b9c
Author: Andrzej Kaczmarek <[email protected]>
AuthorDate: Thu Aug 11 10:47:11 2022 +0200
nimble/transport: Add generic IPC transport with flow control
This adds generic IPC transport that should be used as a base for any
transport with LL on separate core. It's similar to HCI H4, but has a
bit different header to simplify processing and supports internal flow
control to make sure LL does not send data that other core does not have
free buffers for.
IPC transport requires memory shared between cores to keep track of
number of available buffers on application core. Application core will
initialize counters to total number of available buffers. Then on each
alloc LL will atomically test and decrease relevan counter and will
allocate buffer only if that counter was non-zero. The counter will be
increased by application core if relevant buffer was freed.
---
nimble/controller/src/ble_ll_conn.c | 20 +-
.../hci_ipc/include/nimble/transport/hci_ipc.h | 98 +++++++++
.../{nrf5340/syscfg.yml => common/hci_ipc/pkg.yml} | 10 +-
nimble/transport/common/hci_ipc/src/hci_ipc.c | 219 +++++++++++++++++++++
nimble/transport/include/nimble/transport.h | 3 +
.../transport_ipc.h} | 31 ++-
nimble/transport/include/nimble/transport_impl.h | 6 -
nimble/transport/nrf5340/pkg.yml | 2 +-
nimble/transport/nrf5340/src/nrf5340_ble_hci.c | 116 ++++++-----
nimble/transport/src/transport.c | 80 +++++++-
10 files changed, 496 insertions(+), 89 deletions(-)
diff --git a/nimble/controller/src/ble_ll_conn.c
b/nimble/controller/src/ble_ll_conn.c
index 12b67069..d7a202da 100644
--- a/nimble/controller/src/ble_ll_conn.c
+++ b/nimble/controller/src/ble_ll_conn.c
@@ -43,6 +43,9 @@
#include "controller/ble_ll_utils.h"
#include "ble_ll_conn_priv.h"
#include "ble_ll_ctrl_priv.h"
+#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc
+#include <nimble/transport/hci_ipc.h>
+#endif
#if (BLETEST_THROUGHPUT_TEST == 1)
extern void bletest_completed_pkt(uint16_t handle);
@@ -3548,9 +3551,9 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct
ble_mbuf_hdr *hdr)
/* Free buffer */
conn_rx_data_pdu_end:
-#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL)
+#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc
if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT_INT) {
- ble_transport_int_flow_ctl_put();
+ hci_ipc_put(HCI_IPC_TYPE_ACL);
}
#endif
@@ -3614,12 +3617,12 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct
ble_mbuf_hdr *rxhdr)
alloc_rxpdu = false;
}
-#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL)
- /* Do not alloc PDU if there are no free buffers in transport. We'll nak
- * this PDU in LL.
+#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc
+ /* If IPC transport is used, make sure there is buffer available on app
side
+ * for this PDU. We'll just nak in LL if there are no free buffers.
*/
if (alloc_rxpdu && BLE_LL_LLID_IS_DATA(hdr_byte) && (rx_pyld_len > 0)) {
- if (ble_transport_int_flow_ctl_get()) {
+ if (hci_ipc_get(HCI_IPC_TYPE_ACL)) {
rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT_INT;
} else {
alloc_rxpdu = false;
@@ -3639,8 +3642,9 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct
ble_mbuf_hdr *rxhdr)
if (ble_ll_conn_cth_flow_alloc_credit(connsm)) {
rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT;
} else {
-#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL)
- ble_transport_int_flow_ctl_put();
+#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc
+ /* Need to return app buffer to pool since we won't use it */
+ hci_ipc_put(HCI_IPC_TYPE_ACL);
#endif
alloc_rxpdu = false;
}
diff --git a/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h
b/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h
new file mode 100644
index 00000000..2f84f68f
--- /dev/null
+++ b/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _HCI_IPC_H_
+#define _HCI_IPC_H_
+
+#include <stdint.h>
+
+#define HCI_IPC_TYPE_CMD 0x01
+#define HCI_IPC_TYPE_ACL 0x02
+#define HCI_IPC_TYPE_EVT 0x04
+#define HCI_IPC_TYPE_EVT_DISCARDABLE 0x05
+#define HCI_IPC_TYPE_EVT_IN_CMD 0x06
+
+struct __attribute__((packed)) hci_ipc_hdr {
+ uint8_t type;
+ uint16_t length;
+};
+
+struct hci_ipc_sm {
+ struct hci_ipc_hdr hdr;
+ uint8_t hdr_len;
+ uint16_t rem_len;
+ uint16_t buf_len;
+
+ union {
+ uint8_t *buf;
+ struct os_mbuf *om;
+ };
+};
+
+struct hci_ipc_shm {
+ uint16_t n2a_num_acl;
+ uint16_t n2a_num_evt;
+ uint16_t n2a_num_evt_disc;
+};
+
+void hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm);
+int hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len);
+
+extern void hci_ipc_atomic_put(volatile uint16_t *num);
+extern uint16_t hci_ipc_atomic_get(volatile uint16_t *num);
+
+/* Just to optimize static inlines below, do not use directly! */
+extern volatile struct hci_ipc_shm *g_ipc_shm;
+
+static inline int
+hci_ipc_get(uint8_t type)
+{
+ volatile struct hci_ipc_shm *shm = g_ipc_shm;
+
+ switch (type) {
+ case HCI_IPC_TYPE_ACL:
+ return hci_ipc_atomic_get(&shm->n2a_num_acl);
+ case HCI_IPC_TYPE_EVT:
+ return hci_ipc_atomic_get(&shm->n2a_num_evt);
+ case HCI_IPC_TYPE_EVT_DISCARDABLE:
+ return hci_ipc_atomic_get(&shm->n2a_num_evt_disc);
+ }
+
+ return 0;
+}
+
+static inline void
+hci_ipc_put(uint8_t type)
+{
+ volatile struct hci_ipc_shm *shm = g_ipc_shm;
+
+ switch (type) {
+ case HCI_IPC_TYPE_ACL:
+ hci_ipc_atomic_put(&shm->n2a_num_acl);
+ break;
+ case HCI_IPC_TYPE_EVT:
+ hci_ipc_atomic_put(&shm->n2a_num_evt);
+ break;
+ case HCI_IPC_TYPE_EVT_DISCARDABLE:
+ hci_ipc_atomic_put(&shm->n2a_num_evt_disc);
+ break;
+ }
+}
+
+#endif /* _HCI_IPC_H_ */
diff --git a/nimble/transport/nrf5340/syscfg.yml
b/nimble/transport/common/hci_ipc/pkg.yml
similarity index 79%
rename from nimble/transport/nrf5340/syscfg.yml
rename to nimble/transport/common/hci_ipc/pkg.yml
index e8334f2a..b66a3320 100644
--- a/nimble/transport/nrf5340/syscfg.yml
+++ b/nimble/transport/common/hci_ipc/pkg.yml
@@ -1,3 +1,4 @@
+#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -16,5 +17,10 @@
# under the License.
#
-syscfg.defs:
- BLE_TRANSPORT_INT_FLOW_CTL: 1
+pkg.name: nimble/transport/common/hci_ipc
+pkg.description: Custom HCI IPC protocol
+pkg.author: "Apache Mynewt <[email protected]>"
+pkg.homepage: "https://mynewt.apache.org/"
+
+pkg.deps:
+ - nimble
diff --git a/nimble/transport/common/hci_ipc/src/hci_ipc.c
b/nimble/transport/common/hci_ipc/src/hci_ipc.c
new file mode 100644
index 00000000..fafbacc3
--- /dev/null
+++ b/nimble/transport/common/hci_ipc/src/hci_ipc.c
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <syscfg/syscfg.h>
+#include <os/os.h>
+#include <os/os_mbuf.h>
+#include <nimble/transport.h>
+#include <nimble/transport/hci_ipc.h>
+
+volatile struct hci_ipc_shm *g_ipc_shm;
+
+static void
+hci_ipc_alloc(struct hci_ipc_sm *sm)
+{
+ assert(sm->hdr.type);
+ assert(sm->buf == NULL);
+
+ switch (sm->hdr.type) {
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ case HCI_IPC_TYPE_CMD:
+ sm->buf = ble_transport_alloc_cmd();
+ break;
+#endif
+ case HCI_IPC_TYPE_ACL:
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ sm->om = ble_transport_alloc_acl_from_hs();
+#else
+ sm->om = ble_transport_alloc_acl_from_ll();
+#endif
+ break;
+#if !MYNEWT_VAL(BLE_CONTROLLER)
+ case HCI_IPC_TYPE_EVT:
+ sm->buf = ble_transport_alloc_evt(0);
+ break;
+ case HCI_IPC_TYPE_EVT_DISCARDABLE:
+ sm->buf = ble_transport_alloc_evt(1);
+ break;
+ case HCI_IPC_TYPE_EVT_IN_CMD:
+ sm->buf = ble_transport_alloc_cmd();
+ break;
+#endif
+ default:
+ assert(0);
+ break;
+ }
+
+ assert(sm->buf);
+
+ sm->rem_len = sm->hdr.length;
+ sm->buf_len = 0;
+}
+
+static bool
+hci_ipc_has_hdr(struct hci_ipc_sm *sm)
+{
+ return sm->hdr_len == sizeof(sm->hdr);
+}
+
+static void
+hci_ipc_frame(struct hci_ipc_sm *sm)
+{
+ assert(sm->hdr.type);
+ assert(sm->buf);
+ assert(sm->rem_len == 0);
+
+ switch (sm->hdr.type) {
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ case HCI_IPC_TYPE_CMD:
+ ble_transport_to_ll_cmd(sm->buf);
+ break;
+#endif
+ case HCI_IPC_TYPE_ACL:
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ ble_transport_to_ll_acl(sm->om);
+#else
+ ble_transport_to_hs_acl(sm->om);
+#endif
+ break;
+#if !MYNEWT_VAL(BLE_CONTROLLER)
+ case HCI_IPC_TYPE_EVT:
+ case HCI_IPC_TYPE_EVT_DISCARDABLE:
+ case HCI_IPC_TYPE_EVT_IN_CMD:
+ ble_transport_to_hs_evt(sm->buf);
+ break;
+#endif
+ default:
+ assert(0);
+ break;
+ }
+
+ sm->hdr.type = 0;
+ sm->hdr.length = 0;
+ sm->hdr_len = 0;
+ sm->buf_len = 0;
+ sm->rem_len = 0;
+ sm->buf = NULL;
+}
+
+static uint16_t
+hci_ipc_copy_to_hdr(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len)
+{
+ uint16_t rem_hdr_len;
+ uint8_t *p;
+
+ if (hci_ipc_has_hdr(sm)) {
+ return 0;
+ }
+
+ rem_hdr_len = sizeof(sm->hdr) - sm->hdr_len;
+ len = min(len, rem_hdr_len);
+
+ p = (void *)&sm->hdr;
+ memcpy(p + sm->hdr_len, buf, len);
+
+ sm->hdr_len += len;
+
+ if (hci_ipc_has_hdr(sm)) {
+ hci_ipc_alloc(sm);
+ }
+
+ return len;
+}
+
+static uint16_t
+hci_ipc_copy_to_buf(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len)
+{
+ int rc;
+
+ assert(sm->hdr.type);
+ assert(sm->buf);
+
+ len = min(len, sm->rem_len);
+
+ switch (sm->hdr.type) {
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ case HCI_IPC_TYPE_CMD:
+#else
+ case HCI_IPC_TYPE_EVT:
+ case HCI_IPC_TYPE_EVT_DISCARDABLE:
+ case HCI_IPC_TYPE_EVT_IN_CMD:
+#endif
+ memcpy(sm->buf + sm->buf_len, buf, len);
+ break;
+ case HCI_IPC_TYPE_ACL:
+ rc = os_mbuf_append(sm->om, buf, len);
+ assert(rc == 0);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ sm->rem_len -= len;
+ sm->buf_len += len;
+
+ if (sm->rem_len == 0) {
+ hci_ipc_frame(sm);
+ }
+
+ return len;
+}
+
+int
+hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len)
+{
+ uint16_t rem_len = len;
+ uint16_t copy_len;
+
+ while (rem_len) {
+ if (hci_ipc_has_hdr(sm)) {
+ copy_len = hci_ipc_copy_to_buf(sm, buf, rem_len);
+ } else {
+ copy_len = hci_ipc_copy_to_hdr(sm, buf, rem_len);
+ }
+
+ rem_len -= copy_len;
+ buf += copy_len;
+ }
+
+ return len;
+}
+
+void
+hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm)
+{
+ assert(g_ipc_shm == NULL);
+
+ g_ipc_shm = shm;
+ memset(sm, 0, sizeof(*sm));
+
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ while (shm->n2a_num_evt_disc == 0) {
+ /* Wait until app side initializes credits */
+ }
+#else
+ shm->n2a_num_acl = MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT);
+ shm->n2a_num_evt = MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT);
+ shm->n2a_num_evt_disc = MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT);
+#endif
+}
diff --git a/nimble/transport/include/nimble/transport.h
b/nimble/transport/include/nimble/transport.h
index fc3d7375..d18ff560 100644
--- a/nimble/transport/include/nimble/transport.h
+++ b/nimble/transport/include/nimble/transport.h
@@ -26,6 +26,9 @@ extern "C" {
#include <nimble/transport_impl.h>
#include <nimble/transport/monitor.h>
+#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc
+#include <nimble/transport/transport_ipc.h>
+#endif
struct os_mbuf;
diff --git a/nimble/transport/include/nimble/transport_impl.h
b/nimble/transport/include/nimble/transport/transport_ipc.h
similarity index 53%
copy from nimble/transport/include/nimble/transport_impl.h
copy to nimble/transport/include/nimble/transport/transport_ipc.h
index 61d8cd68..18175149 100644
--- a/nimble/transport/include/nimble/transport_impl.h
+++ b/nimble/transport/include/nimble/transport/transport_ipc.h
@@ -17,31 +17,30 @@
* under the License.
*/
-#ifndef H_NIMBLE_TRANSPORT_IMPL_
-#define H_NIMBLE_TRANSPORT_IMPL_
+#ifndef H_NIMBLE_TRANSPORT_IPC_
+#define H_NIMBLE_TRANSPORT_IPC_
#ifdef __cplusplus
extern "C" {
#endif
-/* Init functions to be implemented for transport acting as HS/LL side */
-extern void ble_transport_ll_init(void);
-extern void ble_transport_hs_init(void);
+/* NOTE: These APIs shall only be used by IPC transports */
-/* APIs to be implemented by HS/LL side of transports */
-extern int ble_transport_to_ll_cmd_impl(void *buf);
-extern int ble_transport_to_ll_acl_impl(struct os_mbuf *om);
-extern int ble_transport_to_hs_evt_impl(void *buf);
-extern int ble_transport_to_hs_acl_impl(struct os_mbuf *om);
+#define BLE_TRANSPORT_IPC \
+ MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc
+#define BLE_TRANSPORT_IPC_ON_HS \
+ (BLE_TRANSPORT_IPC && !MYNEWT_VAL(BLE_CONTROLLER))
+#define BLE_TRANSPORT_IPC_ON_LL \
+ (BLE_TRANSPORT_IPC && MYNEWT_VAL(BLE_CONTROLLER))
-#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL)
-/* To be implemented if transport supports internal flow control between cores
*/
-extern int ble_transport_int_flow_ctl_get(void);
-extern void ble_transport_int_flow_ctl_put(void);
-#endif
+/* Free cmd/evt buffer sent over IPC */
+void ble_transport_ipc_free(void *buf);
+
+/* Get IPC type for cmd/evt buffer */
+uint8_t ble_transport_ipc_buf_evt_type_get(void *buf);
#ifdef __cplusplus
}
#endif
-#endif /* H_NIMBLE_TRANSPORT_IMPL_ */
+#endif /* H_NIMBLE_TRANSPORT_IPC_ */
diff --git a/nimble/transport/include/nimble/transport_impl.h
b/nimble/transport/include/nimble/transport_impl.h
index 61d8cd68..d99a8d95 100644
--- a/nimble/transport/include/nimble/transport_impl.h
+++ b/nimble/transport/include/nimble/transport_impl.h
@@ -34,12 +34,6 @@ extern int ble_transport_to_ll_acl_impl(struct os_mbuf *om);
extern int ble_transport_to_hs_evt_impl(void *buf);
extern int ble_transport_to_hs_acl_impl(struct os_mbuf *om);
-#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL)
-/* To be implemented if transport supports internal flow control between cores
*/
-extern int ble_transport_int_flow_ctl_get(void);
-extern void ble_transport_int_flow_ctl_put(void);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/nimble/transport/nrf5340/pkg.yml b/nimble/transport/nrf5340/pkg.yml
index 73dfcf9e..be44d0f8 100644
--- a/nimble/transport/nrf5340/pkg.yml
+++ b/nimble/transport/nrf5340/pkg.yml
@@ -28,7 +28,7 @@ pkg.keywords:
pkg.deps:
- nimble
- - nimble/transport/common/hci_h4
+ - nimble/transport/common/hci_ipc
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/hw/drivers/ipc_nrf5340"
diff --git a/nimble/transport/nrf5340/src/nrf5340_ble_hci.c
b/nimble/transport/nrf5340/src/nrf5340_ble_hci.c
index 2e9e746f..e5ea5a51 100644
--- a/nimble/transport/nrf5340/src/nrf5340_ble_hci.c
+++ b/nimble/transport/nrf5340/src/nrf5340_ble_hci.c
@@ -23,7 +23,7 @@
#include <nimble/ble.h>
#include <ipc_nrf5340/ipc_nrf5340.h>
#include <nimble/transport.h>
-#include <nimble/transport/hci_h4.h>
+#include <nimble/transport/hci_ipc.h>
#if MYNEWT_VAL(BLE_CONTROLLER)
#define IPC_TX_CHANNEL 0
@@ -33,16 +33,19 @@
#define IPC_RX_CHANNEL 0
#endif
-static struct hci_h4_sm hci_nrf5340_h4sm;
+static struct hci_ipc_sm g_hci_ipc_sm;
static int
nrf5340_ble_hci_acl_tx(struct os_mbuf *om)
{
- uint8_t ind = HCI_H4_ACL;
+ struct hci_ipc_hdr hdr;
struct os_mbuf *x;
int rc;
- rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &ind, 1, false);
+ hdr.type = HCI_IPC_TYPE_ACL;
+ hdr.length = 4 + get_le16(&om->om_data[2]);
+
+ rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false);
if (rc == 0) {
x = om;
while (x) {
@@ -59,37 +62,6 @@ nrf5340_ble_hci_acl_tx(struct os_mbuf *om)
return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0;
}
-static int
-nrf5340_ble_hci_frame_cb(uint8_t pkt_type, void *data)
-{
- int rc;
-
- switch (pkt_type) {
-#if MYNEWT_VAL(BLE_CONTROLLER)
- case HCI_H4_CMD:
- rc = ble_transport_to_ll_cmd(data);
- break;
-#endif
- case HCI_H4_ACL:
-#if MYNEWT_VAL(BLE_CONTROLLER)
- rc = ble_transport_to_ll_acl(data);
-#else
- rc = ble_transport_to_hs_acl(data);
-#endif
- break;
-#if !MYNEWT_VAL(BLE_CONTROLLER)
- case HCI_H4_EVT:
- rc = ble_transport_to_hs_evt(data);
- break;
-#endif
- default:
- assert(0);
- break;
- }
-
- return rc;
-}
-
static void
nrf5340_ble_hci_trans_rx(int channel, void *user_data)
{
@@ -98,7 +70,7 @@ nrf5340_ble_hci_trans_rx(int channel, void *user_data)
len = ipc_nrf5340_available_buf(channel, (void **)&buf);
while (len > 0) {
- len = hci_h4_sm_rx(&hci_nrf5340_h4sm, buf, len);
+ len = hci_ipc_rx(&g_hci_ipc_sm, buf, len);
ipc_nrf5340_consume(channel, len);
len = ipc_nrf5340_available_buf(channel, (void **)&buf);
}
@@ -116,17 +88,19 @@ nrf5340_ble_hci_init(void)
int
ble_transport_to_hs_evt_impl(void *buf)
{
- uint8_t ind = HCI_H4_EVT;
- uint8_t* hci_ev = buf;
- int len = 2 + hci_ev[1];
+ struct hci_ipc_hdr hdr;
+ uint8_t *hci_ev = buf;
int rc;
- rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &ind, 1, false);
+ hdr.type = ble_transport_ipc_buf_evt_type_get(buf);
+ hdr.length = 2 + hci_ev[1];
+
+ rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false);
if (rc == 0) {
- rc = ipc_nrf5340_write(IPC_TX_CHANNEL, hci_ev, len, true);
+ rc = ipc_nrf5340_write(IPC_TX_CHANNEL, hci_ev, hdr.length, true);
}
- ble_transport_free(buf);
+ ble_transport_ipc_free(buf);
return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0;
}
@@ -140,8 +114,9 @@ ble_transport_to_hs_acl_impl(struct os_mbuf *om)
void
ble_transport_hs_init(void)
{
- hci_h4_sm_init(&hci_nrf5340_h4sm, &hci_h4_allocs_from_hs,
- nrf5340_ble_hci_frame_cb);
+ volatile struct hci_ipc_shm *shm = ipc_nrf5340_hci_shm_get();
+
+ hci_ipc_init(shm, &g_hci_ipc_sm);
nrf5340_ble_hci_init();
}
#endif /* BLE_CONTROLLER */
@@ -150,17 +125,19 @@ ble_transport_hs_init(void)
int
ble_transport_to_ll_cmd_impl(void *buf)
{
- uint8_t ind = HCI_H4_CMD;
+ struct hci_ipc_hdr hdr;
uint8_t *cmd = buf;
- int len = 3 + cmd[2];
int rc;
- rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &ind, 1, false);
+ hdr.type = HCI_IPC_TYPE_CMD;
+ hdr.length = 3 + cmd[2];
+
+ rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false);
if (rc == 0) {
- rc = ipc_nrf5340_write(IPC_TX_CHANNEL, cmd, len, true);
+ rc = ipc_nrf5340_write(IPC_TX_CHANNEL, cmd, hdr.length, true);
}
- ble_transport_free(buf);
+ ble_transport_ipc_free(buf);
return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0;
}
@@ -174,8 +151,45 @@ ble_transport_to_ll_acl_impl(struct os_mbuf *om)
void
ble_transport_ll_init(void)
{
- hci_h4_sm_init(&hci_nrf5340_h4sm, &hci_h4_allocs_from_ll,
- nrf5340_ble_hci_frame_cb);
+ volatile struct hci_ipc_shm *shm = ipc_nrf5340_hci_shm_get();
+
+ hci_ipc_init(shm, &g_hci_ipc_sm);
nrf5340_ble_hci_init();
}
#endif /* !BLE_CONTROLLER */
+
+uint16_t
+hci_ipc_atomic_get(volatile uint16_t *num)
+{
+ int ret;
+
+ __asm__ volatile (".syntax unified \n"
+ "1: ldrexh r1, [%[addr]] \n"
+ " mov %[ret], r1 \n"
+ " cmp r1, #0 \n"
+ " itte ne \n"
+ " subne r2, r1, #1 \n"
+ " strexhne r1, r2, [%[addr]] \n"
+ " clrexeq \n"
+ " cmp r1, #0 \n"
+ " bne 1b \n"
+ : [ret] "=&r" (ret)
+ : [addr] "r" (num)
+ : "r1", "r2", "memory");
+
+ return ret;
+}
+
+void
+hci_ipc_atomic_put(volatile uint16_t *num)
+{
+ __asm__ volatile (".syntax unified \n"
+ "1: ldrexh r1, [%[addr]] \n"
+ " add r1, r1, #1 \n"
+ " strexh r2, r1, [%[addr]] \n"
+ " cmp r2, #0 \n"
+ " bne 1b \n"
+ :
+ : [addr] "r" (num)
+ : "r1", "r2", "memory");
+}
diff --git a/nimble/transport/src/transport.c b/nimble/transport/src/transport.c
index 0a641a80..9de703e7 100644
--- a/nimble/transport/src/transport.c
+++ b/nimble/transport/src/transport.c
@@ -25,6 +25,9 @@
#include <nimble/ble.h>
#include <nimble/hci_common.h>
#include <nimble/transport.h>
+#if BLE_TRANSPORT_IPC
+#include <nimble/transport/hci_ipc.h>
+#endif
#define OMP_FLAG_FROM_HS (0x01)
#define OMP_FLAG_FROM_LL (0x02)
@@ -79,17 +82,48 @@ ble_transport_alloc_cmd(void)
return os_memblock_get(&pool_cmd);
}
+static void *
+try_alloc_evt(struct os_mempool *mp)
+{
+#if BLE_TRANSPORT_IPC_ON_LL
+ uint8_t type;
+#endif
+ void *buf;
+
+#if BLE_TRANSPORT_IPC_ON_LL
+ if (mp == &pool_evt) {
+ type = HCI_IPC_TYPE_EVT;
+ } else {
+ type = HCI_IPC_TYPE_EVT_DISCARDABLE;
+ }
+
+ if (!hci_ipc_get(type)) {
+ return NULL;
+ }
+#endif
+
+ buf = os_memblock_get(mp);
+
+#if BLE_TRANSPORT_IPC_ON_LL
+ if (!buf) {
+ hci_ipc_put(type);
+ }
+#endif
+
+ return buf;
+}
+
void *
ble_transport_alloc_evt(int discardable)
{
void *buf;
if (discardable) {
- buf = os_memblock_get(&pool_evt_lo);
+ buf = try_alloc_evt(&pool_evt_lo);
} else {
- buf = os_memblock_get(&pool_evt);
+ buf = try_alloc_evt(&pool_evt);
if (!buf) {
- buf = os_memblock_get(&pool_evt_lo);
+ buf = try_alloc_evt(&pool_evt_lo);
}
}
@@ -135,6 +169,26 @@ ble_transport_alloc_acl_from_ll(void)
void
ble_transport_free(void *buf)
+{
+ if (os_memblock_from(&pool_cmd, buf)) {
+ os_memblock_put(&pool_cmd, buf);
+ } else if (os_memblock_from(&pool_evt, buf)) {
+ os_memblock_put(&pool_evt, buf);
+#if BLE_TRANSPORT_IPC
+ hci_ipc_put(HCI_IPC_TYPE_EVT);
+#endif
+ } else if (os_memblock_from(&pool_evt_lo, buf)) {
+ os_memblock_put(&pool_evt_lo, buf);
+#if BLE_TRANSPORT_IPC
+ hci_ipc_put(HCI_IPC_TYPE_EVT_DISCARDABLE);
+#endif
+ } else {
+ assert(0);
+ }
+}
+
+void
+ble_transport_ipc_free(void *buf)
{
if (os_memblock_from(&pool_cmd, buf)) {
os_memblock_put(&pool_cmd, buf);
@@ -172,9 +226,9 @@ ble_transport_acl_put(struct os_mempool_ext *mpe, void
*data, void *arg)
err = os_memblock_put_from_cb(&mpe->mpe_mp, data);
}
-#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL)
+#if BLE_TRANSPORT_IPC_ON_HS
if (from_ll && !err) {
- ble_transport_int_flow_ctl_put();
+ hci_ipc_put(HCI_IPC_TYPE_ACL);
}
#endif
@@ -218,3 +272,19 @@
ble_transport_register_put_acl_from_ll_cb(os_mempool_put_fn (*cb))
return 0;
}
+
+#if BLE_TRANSPORT_IPC
+uint8_t
+ble_transport_ipc_buf_evt_type_get(void *buf)
+{
+ if (os_memblock_from(&pool_cmd, buf)) {
+ return HCI_IPC_TYPE_EVT_IN_CMD;
+ } else if (os_memblock_from(&pool_evt, buf)) {
+ return HCI_IPC_TYPE_EVT;
+ } else if (os_memblock_from(&pool_evt_lo, buf)) {
+ return HCI_IPC_TYPE_EVT_DISCARDABLE;
+ } else {
+ assert(0);
+ }
+}
+#endif