diff mbox series

[4/4] Bluetooth: Update LE TX & RX PHYs when connection established

Message ID 20210722053843.6691-5-ayush.garg@samsung.com (mailing list archive)
State New, archived
Headers show
Series Bluetooth: Support for LE Set Preferred PHY | expand

Commit Message

Ayush Garg July 22, 2021, 5:38 a.m. UTC
The TX and RX PHYs will always be 1M if the established LE
connection is a legacy connection. These values may
differ in case of LE Extended connection.
This change will read and update the connection PHYs and
autonomously send LE PHY Update event if the connection
is LE Extended.

< HCI Command: LE Read PHY (0x08|0x0030) plen 2
		Handle: 0
> HCI Event: Command Complete (0x0e) plen 8
	  LE Read PHY (0x08|0x0030) ncmd 1
		Status: Success (0x00)
		Handle: 0
		TX PHY: LE 1M (0x01)
		RX PHY: LE 1M (0x01)
@ MGMT Event: LE PHY Update Complete (0x002f) plen 12
		LE Address: 45:18:F8:CF:23:7E (Resolvable)
		Status: Success (0x00)
		Updated PHYs: 0x0600
		  LE 1M TX
		  LE 1M RX

Reviewed-by: Anupam Roy <anupam.r@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
---
 include/net/bluetooth/hci.h | 12 +++++++++
 net/bluetooth/hci_event.c   | 51 +++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)
diff mbox series

Patch

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 06e10ccf2a1c..6073e8431ed5 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1670,6 +1670,18 @@  struct hci_rp_le_read_max_data_len {
 	__le16	rx_time;
 } __packed;
 
+#define HCI_OP_LE_READ_PHY	0x2030
+struct hci_cp_le_read_phy {
+	__le16 handle;
+} __packed;
+
+struct hci_rp_le_read_phy {
+	__u8	status;
+	__le16	handle;
+	__u8	tx_phy;
+	__u8	rx_phy;
+} __packed;
+
 #define HCI_OP_LE_SET_DEFAULT_PHY	0x2031
 struct hci_cp_le_set_default_phy {
 	__u8    all_phys;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index effe525e5272..37ab2f2a1d06 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1196,6 +1196,31 @@  static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
 	hci_dev_unlock(hdev);
 }
 
+static void hci_cc_le_read_phy(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_le_read_phy *rp = (void *)skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+	if (!conn)
+		goto unlock;
+
+	conn->le_tx_phy = rp->tx_phy;
+	conn->le_rx_phy = rp->rx_phy;
+
+	mgmt_le_phy_update(hdev, conn, 0);
+
+unlock:
+	hci_dev_unlock(hdev);
+}
+
 static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
                                               struct sk_buff *skb)
 {
@@ -3642,6 +3667,10 @@  static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
 		hci_cc_le_read_transmit_power(hdev, skb);
 		break;
 
+	case HCI_OP_LE_READ_PHY:
+		hci_cc_le_read_phy(hdev, skb);
+		break;
+
 	default:
 		BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
 		break;
@@ -5229,6 +5258,17 @@  static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
 		goto unlock;
 	}
 
+	/* If this LE connection is not an extended connection, then LE
+	 * PHYs will always be 1M at the time of connection establishment.
+	 * So, set 1M as initial LE PHY values.
+	 * But if this is LE Extended connection, then the PHY values
+	 * can be 1M, 2M or CODED. So, In this case, read and update
+	 * the values after the conn->state becomes connected and
+	 * then, send the LE_PHY_UPDATE_COMPLETE event.
+	 */
+	conn->le_tx_phy = HCI_LE_SET_PHY_1M;
+	conn->le_rx_phy = HCI_LE_SET_PHY_1M;
+
 	if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
 		mgmt_device_connected(hdev, conn, NULL, 0);
 
@@ -5267,6 +5307,17 @@  static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
 		hci_connect_cfm(conn, status);
 	}
 
+	/* If this is LE Extended connection and HCI_LE_READ_PHY
+	 * command is supported, then update the LE PHYs.
+	 */
+	if (use_ext_conn(hdev) && hdev->commands[35] & 0x10) {
+		struct hci_cp_le_read_phy cp;
+
+		cp.handle = __cpu_to_le16(conn->handle);
+
+		hci_send_cmd(hdev, HCI_OP_LE_READ_PHY, sizeof(cp), &cp);
+	}
+
 	params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
 					   conn->dst_type);
 	if (params) {