Bluetooth: Use transmit window from config response for ack timing

This change addresses an L2CAP ERTM throughput problem when a remote
device does not fully utilize the available transmit window.

The L2CAP ERTM transmit window size determines the maximum number of
unacked frames that may be outstanding at any time. It is configured
separately for each direction of an ERTM connection. Each side sends a
configuration request with a tx_win field indicating how many unacked
frames it is capable of receiving before sending an ack. The
configuration response's tx_win field shows how many frames the
transmitter will actually send before waiting for an ack.

It's important to trace both the actual transmit window (to check for
validity of incoming frames) and the number of frames that the
transmitter will send before waiting (to send acks at the appropriate
time). Now there are separate tx_win and ack_win values. ack_win is
updated based on configuration responses, and is used to determine
when acks are sent.

CRs-fixed: 370909
Change-Id: I6d9ef55a2ff2f5f3d0117ad376a09e4cc26fe742
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
This commit is contained in:
Mat Martineau
2012-06-22 11:36:18 -07:00
committed by Stephen Boyd
parent 0cab4a7a1a
commit c1f3fb57a3
3 changed files with 20 additions and 8 deletions

View File

@@ -534,6 +534,7 @@ struct l2cap_pinfo {
__u16 tx_win;
__u16 tx_win_max;
__u16 ack_win;
__u8 max_tx;
__u8 amp_pref;
__u16 remote_tx_win;

View File

@@ -1993,10 +1993,10 @@ static void l2cap_ertm_send_ack(struct sock *sk)
frames_to_ack = 0;
}
/* Ack now if the tx window is 3/4ths full.
/* Ack now if the window is 3/4ths full.
* Calculate without mul or div
*/
threshold = pi->tx_win;
threshold = pi->ack_win;
threshold += threshold << 1;
threshold >>= 2;
@@ -3105,6 +3105,7 @@ static void l2cap_setup_txwin(struct l2cap_pinfo *pi)
pi->tx_win_max = L2CAP_TX_WIN_MAX_ENHANCED;
pi->extended_control = 0;
}
pi->ack_win = pi->tx_win;
}
static void l2cap_aggregate_fs(struct hci_ext_fs *cur,
@@ -3844,10 +3845,7 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
break;
case L2CAP_CONF_EXT_WINDOW:
pi->tx_win = val;
if (pi->tx_win > L2CAP_TX_WIN_MAX_ENHANCED)
pi->tx_win = L2CAP_TX_WIN_MAX_ENHANCED;
pi->ack_win = min_t(u16, val, pi->ack_win);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EXT_WINDOW,
2, pi->tx_win);
@@ -3869,6 +3867,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
pi->mps = le16_to_cpu(rfc.max_pdu_size);
if (!pi->extended_control) {
pi->ack_win = min_t(u16, pi->ack_win,
rfc.txwin_size);
}
break;
case L2CAP_MODE_STREAMING:
pi->mps = le16_to_cpu(rfc.max_pdu_size);
@@ -3901,6 +3903,7 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
int type, olen;
unsigned long val;
struct l2cap_conf_rfc rfc;
u16 txwin_ext = pi->ack_win;
BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len);
@@ -3909,6 +3912,7 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
rfc.txwin_size = min_t(u16, pi->ack_win, L2CAP_DEFAULT_TX_WINDOW);
if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING))
return;
@@ -3920,16 +3924,22 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
case L2CAP_CONF_RFC:
if (olen == sizeof(rfc))
memcpy(&rfc, (void *)val, olen);
goto done;
break;
case L2CAP_CONF_EXT_WINDOW:
txwin_ext = val;
break;
}
}
done:
switch (rfc.mode) {
case L2CAP_MODE_ERTM:
pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
pi->mps = le16_to_cpu(rfc.max_pdu_size);
if (pi->extended_control)
pi->ack_win = min_t(u16, pi->ack_win, txwin_ext);
else
pi->ack_win = min_t(u16, pi->ack_win, rfc.txwin_size);
break;
case L2CAP_MODE_STREAMING:
pi->mps = le16_to_cpu(rfc.max_pdu_size);

View File

@@ -1270,6 +1270,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->scid = 0;
pi->dcid = 0;
pi->tx_win_max = L2CAP_TX_WIN_MAX_ENHANCED;
pi->ack_win = pi->tx_win;
pi->extended_control = 0;
pi->local_conf.fcs = pi->fcs;