mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-09-10 19:20:01 +00:00
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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 H_NIMBLE_TRANSPORT_IPC_
|
||||
#define H_NIMBLE_TRANSPORT_IPC_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* NOTE: These APIs shall only be used by IPC transports */
|
||||
|
||||
#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))
|
||||
|
||||
/* 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_IPC_ */
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user