Bluetooth: Introduce dedicated TX fragment pool
There's a risk of a deadlock if we use the same pool for ACL fragments as we use for general ACL TX buffers: all TX buffers are queued up, and we try to segment one of them, a segment buffer will never become available. To work around this risk, introduce a dedicated fragment pool. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
4c123a5162
commit
abc20e7eae
2 changed files with 35 additions and 0 deletions
|
@ -168,6 +168,18 @@ config BT_L2CAP_TX_BUF_COUNT
|
||||||
help
|
help
|
||||||
Number of buffers available for outgoing L2CAP packets.
|
Number of buffers available for outgoing L2CAP packets.
|
||||||
|
|
||||||
|
config BT_L2CAP_TX_FRAG_COUNT
|
||||||
|
int "Number of L2CAP TX fragment buffers"
|
||||||
|
default 2
|
||||||
|
range 0 255
|
||||||
|
help
|
||||||
|
Number of buffers available for fragments of TX buffers. Warning:
|
||||||
|
setting this to 0 means that the application must ensure that
|
||||||
|
queued TX buffers never need to be fragmented, i.e. that the
|
||||||
|
controller's buffer size is large enough. If this is not ensured,
|
||||||
|
and there are no dedicated fragment buffers, a deadlock may occur.
|
||||||
|
In most cases the default value of 2 is a safe bet.
|
||||||
|
|
||||||
config BT_L2CAP_TX_MTU
|
config BT_L2CAP_TX_MTU
|
||||||
int "Maximum supported L2CAP MTU for L2CAP TX buffers"
|
int "Maximum supported L2CAP MTU for L2CAP TX buffers"
|
||||||
default 23
|
default 23
|
||||||
|
|
|
@ -37,6 +37,25 @@ NET_BUF_POOL_DEFINE(acl_tx_pool, CONFIG_BT_L2CAP_TX_BUF_COUNT,
|
||||||
BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
|
BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
|
||||||
BT_BUF_USER_DATA_MIN, NULL);
|
BT_BUF_USER_DATA_MIN, NULL);
|
||||||
|
|
||||||
|
#if CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0
|
||||||
|
|
||||||
|
#if defined(BT_CTLR_TX_BUFFER_SIZE)
|
||||||
|
#define FRAG_SIZE BT_L2CAP_BUF_SIZE(BT_CTLR_TX_BUFFER_SIZE - 4)
|
||||||
|
#else
|
||||||
|
#define FRAG_SIZE BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Dedicated pool for fragment buffers in case queued up TX buffers don't
|
||||||
|
* fit the controllers buffer size. We can't use the acl_tx_pool for the
|
||||||
|
* fragmentation, since it's possible that pool is empty and all buffers
|
||||||
|
* are queued up in the TX queue. In such a situation, trying to allocate
|
||||||
|
* another buffer from the acl_tx_pool would result in a deadlock.
|
||||||
|
*/
|
||||||
|
NET_BUF_POOL_FIXED_DEFINE(frag_pool, CONFIG_BT_L2CAP_TX_FRAG_COUNT, FRAG_SIZE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0 */
|
||||||
|
|
||||||
/* How long until we cancel HCI_LE_Create_Connection */
|
/* How long until we cancel HCI_LE_Create_Connection */
|
||||||
#define CONN_TIMEOUT K_SECONDS(3)
|
#define CONN_TIMEOUT K_SECONDS(3)
|
||||||
|
|
||||||
|
@ -1198,7 +1217,11 @@ static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
|
||||||
struct net_buf *frag;
|
struct net_buf *frag;
|
||||||
u16_t frag_len;
|
u16_t frag_len;
|
||||||
|
|
||||||
|
#if CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0
|
||||||
|
frag = bt_conn_create_pdu(&frag_pool, 0);
|
||||||
|
#else
|
||||||
frag = bt_conn_create_pdu(NULL, 0);
|
frag = bt_conn_create_pdu(NULL, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (conn->state != BT_CONN_CONNECTED) {
|
if (conn->state != BT_CONN_CONNECTED) {
|
||||||
net_buf_unref(frag);
|
net_buf_unref(frag);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue