From 24f1e7c8b70fa6e4f6cc3a5fd92debbe76c5d45f Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 15 Sep 2016 10:12:09 +0530 Subject: [PATCH 01/16] Bluetooth: Add support to enable/disable IPSP This patch supports MGMT commands and code to enable or disable IPSP 6LowPan features. Change-Id: Ibbed275162ac0539205502747923603a2a581c36 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/l2cap.h | 11 +++++++++++ include/net/bluetooth/mgmt_tizen.h | 6 ++++++ net/bluetooth/6lowpan.c | 34 ++++++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index cf393e7..a13d22a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1006,4 +1006,15 @@ void l2cap_conn_put(struct l2cap_conn *conn); int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); +#ifdef TIZEN_BT +#ifdef CONFIG_BT_6LOWPAN +/* IPSP : initialize/deinitialize 6lowpan */ +void bt_6lowpan_enable(void); +void bt_6lowpan_disable(void); +#else +static inline void bt_6lowpan_enable(void) { } +static inline void bt_6lowpan_disable(void) { } +#endif +#endif /* TIZEN_BT */ + #endif /* __L2CAP_H */ diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 982c00d..6549be1 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -167,6 +167,12 @@ struct mgmt_rp_get_adv_tx_power { __s8 adv_tx_power; } __packed; +#define MGMT_OP_ENABLE_6LOWPAN (TIZEN_OP_CODE_BASE + 0x12) +struct mgmt_cp_enable_6lowpan { + __u8 enable_6lowpan; +} __packed; +#define MGMT_ENABLE_BT_6LOWPAN_SIZE 1 + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 4eb1b3c..fd15bff 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -1259,6 +1259,40 @@ static int __init bt_6lowpan_init(void) return register_netdevice_notifier(&bt_6lowpan_dev_notifier); } +#ifdef TIZEN_BT +void bt_6lowpan_enable(void) +{ + if (!enable_6lowpan) { + disconnect_all_peers(); + + enable_6lowpan = true; + + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + } + + listen_chan = bt_6lowpan_listen(); + + register_netdevice_notifier(&bt_6lowpan_dev_notifier); + } +} + +void bt_6lowpan_disable(void) +{ + if (enable_6lowpan) { + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + listen_chan = NULL; + } + disconnect_devices(); + unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); + enable_6lowpan = false; + } +} +#endif + static void __exit bt_6lowpan_exit(void) { debugfs_remove(lowpan_enable_debugfs); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 49ec403..bc4614b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8951,6 +8951,40 @@ void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, sizeof(struct mgmt_ev_vendor_specific_multi_adv_state_changed), NULL); } + +static int enable_bt_6lowpan(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + int err; + struct mgmt_cp_enable_6lowpan *cp = data; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ENABLE_6LOWPAN, + MGMT_STATUS_NOT_POWERED); + goto unlocked; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ENABLE_6LOWPAN, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (cp->enable_6lowpan) + bt_6lowpan_enable(); + else + bt_6lowpan_disable(); + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ENABLE_6LOWPAN, + MGMT_STATUS_SUCCESS, NULL, 0); +unlocked: + hci_dev_unlock(hdev); + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11286,6 +11320,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { le_set_scan_params, MGMT_LE_SET_SCAN_PARAMS_SIZE }, { set_voice_setting, MGMT_SET_VOICE_SETTING_SIZE }, { get_adv_tx_power, MGMT_GET_ADV_TX_POWER_SIZE }, + { enable_bt_6lowpan, MGMT_ENABLE_BT_6LOWPAN_SIZE }, }; #endif -- 2.7.4 From e25dbea713126b21b10d8dad294a31f115156379 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 15 Sep 2016 12:53:03 +0530 Subject: [PATCH 02/16] Bluetooth: IPSP Connect/Disconnect apis This patch adds MGMT code to support IPSP connect and disconnect apis and handle connection state changed event. Change-Id: I6139603a9614217637f109b2d724e1bf9ffb8f93 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/l2cap.h | 5 ++ include/net/bluetooth/mgmt_tizen.h | 18 +++++ net/bluetooth/6lowpan.c | 16 ++++ net/bluetooth/mgmt.c | 150 +++++++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fc9ad74..6dd3d0f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2424,6 +2424,8 @@ void mgmt_le_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len, u8 adv_type); void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, u8 state_change_reason, u16 connection_handle); +void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], + bdaddr_t *bdaddr, u8 addr_type, bool connected); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a13d22a..4bd23ae 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1011,9 +1011,14 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); /* IPSP : initialize/deinitialize 6lowpan */ void bt_6lowpan_enable(void); void bt_6lowpan_disable(void); +/* IPSP: Connect and Disconnect */ +int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type); +int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type); #else static inline void bt_6lowpan_enable(void) { } static inline void bt_6lowpan_disable(void) { } +static inline int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) { return -ENODEV; } +static inline int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) { return -ENODEV; } #endif #endif /* TIZEN_BT */ diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 6549be1..52a36f9 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -173,6 +173,18 @@ struct mgmt_cp_enable_6lowpan { } __packed; #define MGMT_ENABLE_BT_6LOWPAN_SIZE 1 +#define MGMT_OP_CONNECT_6LOWPAN (TIZEN_OP_CODE_BASE + 0x13) +struct mgmt_cp_connect_6lowpan { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_CONNECT_6LOWPAN_SIZE 7 + +#define MGMT_OP_DISCONNECT_6LOWPAN (TIZEN_OP_CODE_BASE + 0x14) +struct mgmt_cp_disconnect_6lowpan { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_DISCONNECT_6LOWPAN_SIZE 7 + /* EVENTS */ /* For device name update changes */ @@ -254,5 +266,11 @@ struct mgmt_ev_vendor_specific_multi_adv_state_changed { } __packed; /* LE advertisement state changed event */ +#define MGMT_EV_6LOWPAN_CONN_STATE_CHANGED (TIZEN_EV_BASE + 0x0c) +struct mgmt_ev_6lowpan_conn_state_changed { + struct mgmt_addr_info addr; + __u8 connected; + __u8 ifname[16]; +} __packed; #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index fd15bff..bcb4407 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -732,6 +732,12 @@ static inline void chan_ready_cb(struct l2cap_chan *chan) add_peer_chan(chan, dev, new_netdev); ifup(dev->netdev); + +#ifdef TIZEN_BT + /* IPSP: Send connection changed state info to bluez */ + mgmt_6lowpan_conn_changed(dev->hdev, dev->netdev->name, &chan->dst, + chan->dst_type, true); +#endif } static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan) @@ -1291,6 +1297,16 @@ void bt_6lowpan_disable(void) enable_6lowpan = false; } } + +int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) +{ + return bt_6lowpan_connect(addr, dst_type); +} + +int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) +{ + return bt_6lowpan_disconnect(conn, dst_type); +} #endif static void __exit bt_6lowpan_exit(void) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc4614b..caaf1f4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8985,6 +8985,154 @@ unlocked: hci_dev_unlock(hdev); return err; } + +static int connect_bt_6lowpan(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_connect_6lowpan *cp = data; + __u8 addr_type = ADDR_LE_DEV_PUBLIC; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_REJECTED); + goto unlocked; + } + + if (bdaddr_type_is_le(cp->addr.type)) { + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + } else { + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + goto unlocked; + } + + hci_dev_unlock(hdev); + + /* 6lowpan Connect */ + err = _bt_6lowpan_connect(&cp->addr.bdaddr, cp->addr.type); + + hci_dev_lock(hdev); + + if (err < 0) { + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_REJECTED, NULL, 0); + + goto unlocked; + } + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, 0, + NULL, 0); +unlocked: + hci_dev_unlock(hdev); + return err; +} + +static int disconnect_bt_6lowpan(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_disconnect_6lowpan *cp = data; + struct hci_conn *conn = NULL; + __u8 addr_type = ADDR_LE_DEV_PUBLIC; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_REJECTED); + goto unlocked; + } + + if (bdaddr_type_is_le(cp->addr.type)) { + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + } else { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + goto unlocked; + } + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); + if (!conn) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_NOT_CONNECTED, NULL, 0); + goto unlocked; + } + + if (conn->dst_type != addr_type) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + goto unlocked; + } + + if (conn->state != BT_CONNECTED) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_NOT_CONNECTED, NULL, 0); + goto unlocked; + } + + /* 6lowpan Disconnect */ + err = _bt_6lowpan_disconnect(conn->l2cap_data, cp->addr.type); + if (err < 0) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_REJECTED, NULL, 0); + goto unlocked; + } + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, 0, + NULL, 0); + +unlocked: + hci_dev_unlock(hdev); + return err; +} + +void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], + bdaddr_t *bdaddr, u8 addr_type, bool connected) +{ + char buf[512]; + struct mgmt_ev_6lowpan_conn_state_changed *ev = (void *)buf; + size_t ev_size; + + memset(buf, 0, sizeof(buf)); + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = addr_type; + ev->connected = connected; + memcpy(ev->ifname, (__u8 *)if_name, 16); + + ev_size = sizeof(*ev); + + mgmt_event(MGMT_EV_6LOWPAN_CONN_STATE_CHANGED, hdev, ev, ev_size, NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11321,6 +11469,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { set_voice_setting, MGMT_SET_VOICE_SETTING_SIZE }, { get_adv_tx_power, MGMT_GET_ADV_TX_POWER_SIZE }, { enable_bt_6lowpan, MGMT_ENABLE_BT_6LOWPAN_SIZE }, + { connect_bt_6lowpan, MGMT_CONNECT_6LOWPAN_SIZE }, + { disconnect_bt_6lowpan, MGMT_DISCONNECT_6LOWPAN_SIZE }, }; #endif -- 2.7.4 From e04ec6e48e3d349ee6757871af309ea2591c9bd9 Mon Sep 17 00:00:00 2001 From: "h.sandeep" Date: Fri, 16 Sep 2016 14:45:24 +0530 Subject: [PATCH 03/16] Bluetooth: Fix IPSP connection callback event issue. This patch fixes the IPSP connection callback event issue between kernel and bluez layer. Change-Id: I7fe5698add70faf5c2ebb72a1799c9790b48edf3 Signed-off-by: h.sandeep Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/l2cap_core.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6029897..7ce906e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1362,8 +1362,23 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) * case of receiving data before the L2CAP info req/rsp * procedure is complete. */ +#ifndef TIZEN_BT if (chan->state == BT_CONNECTED) return; +#else + if (chan->state == BT_CONNECTED) { + if (chan->psm == L2CAP_PSM_IPSP) { + struct l2cap_conn *conn = chan->conn; + + if (conn->hcon->out) + return; + else if (conn->hcon->type != LE_LINK) + return; + } else { + return; + } + } +#endif /* This clears all conf flags, including CONF_NOT_COMPLETE */ chan->conf_state = 0; @@ -7689,8 +7704,23 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, * procedure is done simply assume that the channel is supported * and mark it as ready. */ +#ifndef TIZEN_BT if (chan->chan_type == L2CAP_CHAN_FIXED) l2cap_chan_ready(chan); +#else + if (chan->chan_type == L2CAP_CHAN_FIXED) { + if (chan->psm == L2CAP_PSM_IPSP) { + struct l2cap_conn *conn = chan->conn; + + if (conn->hcon->out) + l2cap_chan_ready(chan); + else if (conn->hcon->type != LE_LINK) + l2cap_chan_ready(chan); + } else { + l2cap_chan_ready(chan); + } + } +#endif if (chan->state != BT_CONNECTED) goto drop; -- 2.7.4 From 30a3ebd2c711783493e16c5763a90aac609ca7fd Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Fri, 16 Sep 2016 10:38:30 +0530 Subject: [PATCH 04/16] Bluetooth: Read LE Max data length command This patch adds the MGMT command and code to support reading the maximum data length supported command for LE. Change-Id: I308cb2de2e7fe5b3e5dd2dd8813668f27d6a2c57 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/mgmt_tizen.h | 9 +++++ net/bluetooth/hci_event.c | 9 +++++ net/bluetooth/mgmt.c | 79 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6dd3d0f..2d17fc7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2426,6 +2426,8 @@ void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, u8 state_change_reason, u16 connection_handle); void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], bdaddr_t *bdaddr, u8 addr_type, bool connected); +void mgmt_le_read_maximum_data_length_complete(struct hci_dev *hdev, + u8 status); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 52a36f9..444d793 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -185,6 +185,15 @@ struct mgmt_cp_disconnect_6lowpan { } __packed; #define MGMT_DISCONNECT_6LOWPAN_SIZE 7 +#define MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x15) +struct mgmt_rp_le_read_maximum_data_length { + __le16 max_tx_octets; + __le16 max_tx_time; + __le16 max_rx_octets; + __le16 max_rx_time; +} __packed; +#define MGMT_LE_READ_MAXIMUM_DATA_LENGTH_SIZE 0 + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f7eaf5d..354a7d2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2152,14 +2152,23 @@ static u8 hci_cc_le_read_max_data_len(struct hci_dev *hdev, void *data, bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); +#ifndef TIZEN_BT if (rp->status) return rp->status; +#else + hci_dev_lock(hdev); +#endif hdev->le_max_tx_len = le16_to_cpu(rp->tx_len); hdev->le_max_tx_time = le16_to_cpu(rp->tx_time); hdev->le_max_rx_len = le16_to_cpu(rp->rx_len); hdev->le_max_rx_time = le16_to_cpu(rp->rx_time); +#ifdef TIZEN_BT + mgmt_le_read_maximum_data_length_complete(hdev, rp->status); + hci_dev_unlock(hdev); +#endif + return rp->status; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index caaf1f4..bb067e8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9133,6 +9133,83 @@ void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], mgmt_event(MGMT_EV_6LOWPAN_CONN_STATE_CHANGED, hdev, ev, ev_size, NULL); } + +void mgmt_le_read_maximum_data_length_complete(struct hci_dev *hdev, u8 status) +{ + struct mgmt_pending_cmd *cmd; + struct mgmt_rp_le_read_maximum_data_length rp; + + BT_DBG("%s status %u", hdev->name, status); + + cmd = pending_find(MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, hdev); + if (!cmd) + return; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, + mgmt_status(status)); + + memset(&rp, 0, sizeof(rp)); + + rp.max_tx_octets = cpu_to_le16(hdev->le_max_tx_len); + rp.max_tx_time = cpu_to_le16(hdev->le_max_tx_time); + rp.max_rx_octets = cpu_to_le16(hdev->le_max_rx_len); + rp.max_rx_time = cpu_to_le16(hdev->le_max_rx_time); + + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, 0, + &rp, sizeof(rp)); + + mgmt_pending_remove(cmd); +} + +static int read_maximum_le_data_length(struct sock *sk, + struct hci_dev *hdev, void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + int err; + + BT_DBG("read_maximum_le_data_length %s", hdev->name); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, + MGMT_STATUS_NOT_SUPPORTED); + goto unlock; + } + + if (pending_find(MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, + MGMT_STATUS_BUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, + hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + err = hci_send_cmd(hdev, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11471,6 +11548,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { enable_bt_6lowpan, MGMT_ENABLE_BT_6LOWPAN_SIZE }, { connect_bt_6lowpan, MGMT_CONNECT_6LOWPAN_SIZE }, { disconnect_bt_6lowpan, MGMT_DISCONNECT_6LOWPAN_SIZE }, + { read_maximum_le_data_length, + MGMT_LE_READ_MAXIMUM_DATA_LENGTH_SIZE }, }; #endif -- 2.7.4 From 8ae598ad4d7db6bc92523e0152d0e7f7b690c8f1 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Fri, 16 Sep 2016 12:09:57 +0530 Subject: [PATCH 05/16] Bluetooth: Write host suggested default le data length This patch adds MGMT command and code for supporting write default le data length command to the controller. Change-Id: Idd59eba48a6726293ef91804d090ecfd7d46f220 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/mgmt_tizen.h | 7 ++++ net/bluetooth/hci_event.c | 13 ++++++ net/bluetooth/mgmt.c | 86 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2d17fc7..4cd4b7d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2428,6 +2428,8 @@ void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], bdaddr_t *bdaddr, u8 addr_type, bool connected); void mgmt_le_read_maximum_data_length_complete(struct hci_dev *hdev, u8 status); +void mgmt_le_write_host_suggested_data_length_complete(struct hci_dev *hdev, + u8 status); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 444d793..0f36ecd 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -194,6 +194,13 @@ struct mgmt_rp_le_read_maximum_data_length { } __packed; #define MGMT_LE_READ_MAXIMUM_DATA_LENGTH_SIZE 0 +#define MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x16) +struct mgmt_cp_le_write_host_suggested_data_length { + __le16 def_tx_octets; + __le16 def_tx_time; +} __packed; +#define MGMT_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_SIZE 4 + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 354a7d2..b3ce9f2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2027,16 +2027,29 @@ static u8 hci_cc_le_write_def_data_len(struct hci_dev *hdev, void *data, bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); if (rp->status) +#ifndef TIZEN_BT return rp->status; +#else + goto unblock; +#endif sent = hci_sent_cmd_data(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN); if (!sent) +#ifndef TIZEN_BT return rp->status; +#else + goto unblock; +#endif hdev->le_def_tx_len = le16_to_cpu(sent->tx_len); hdev->le_def_tx_time = le16_to_cpu(sent->tx_time); return rp->status; +#ifdef TIZEN_BT +unblock: + mgmt_le_write_host_suggested_data_length_complete(hdev, rp->status); + return rp->status; +#endif } static u8 hci_cc_le_add_to_resolv_list(struct hci_dev *hdev, void *data, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bb067e8..f82a5af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9210,6 +9210,90 @@ unlock: hci_dev_unlock(hdev); return err; } + +void mgmt_le_write_host_suggested_data_length_complete(struct hci_dev *hdev, + u8 status) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, hdev); + if (!cmd) { + BT_ERR("cmd not found in the pending list"); + goto unlock; + } + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + 0, NULL, 0); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int write_host_suggested_le_data_length(struct sock *sk, + struct hci_dev *hdev, void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct mgmt_cp_le_write_host_suggested_data_length *cp = data; + struct hci_cp_le_write_def_data_len hci_data; + int err = 0; + + BT_DBG("Write host suggested data length request for %s", hdev->name); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + MGMT_STATUS_NOT_SUPPORTED); + goto unlock; + } + + if (pending_find(MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + MGMT_STATUS_BUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + hci_data.tx_len = cp->def_tx_octets; + hci_data.tx_time = cp->def_tx_time; + + err = hci_send_cmd(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN, + sizeof(hci_data), &hci_data); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); + + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11550,6 +11634,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { disconnect_bt_6lowpan, MGMT_DISCONNECT_6LOWPAN_SIZE }, { read_maximum_le_data_length, MGMT_LE_READ_MAXIMUM_DATA_LENGTH_SIZE }, + { write_host_suggested_le_data_length, + MGMT_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_SIZE }, }; #endif -- 2.7.4 From 96938b8cc096d00316f5085ecb8396cd72235200 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Fri, 16 Sep 2016 12:54:31 +0530 Subject: [PATCH 06/16] Bluetooth: Read host suggested default le data length This patch adds MGMT command and code for supporting reading default le data length value set at the controller. Change-Id: I6194023bf41ef1fe5606f41fdb0776f6ec84cb4f Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/mgmt_tizen.h | 7 ++++ net/bluetooth/hci_event.c | 10 +++++ net/bluetooth/mgmt.c | 81 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4cd4b7d..957dff5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2430,6 +2430,8 @@ void mgmt_le_read_maximum_data_length_complete(struct hci_dev *hdev, u8 status); void mgmt_le_write_host_suggested_data_length_complete(struct hci_dev *hdev, u8 status); +void mgmt_le_read_host_suggested_data_length_complete(struct hci_dev *hdev, + u8 status); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 0f36ecd..2d11d5b 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -201,6 +201,13 @@ struct mgmt_cp_le_write_host_suggested_data_length { } __packed; #define MGMT_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_SIZE 4 +#define MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x17) +struct mgmt_rp_le_read_host_suggested_data_length { + __le16 def_tx_octets; + __le16 def_tx_time; +} __packed; +#define MGMT_LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE 0 + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b3ce9f2..0f98ffe 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2009,12 +2009,22 @@ static u8 hci_cc_le_read_def_data_len(struct hci_dev *hdev, void *data, bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); +#ifdef TIZEN_BT + hci_dev_lock(hdev); +#else if (rp->status) return rp->status; +#endif hdev->le_def_tx_len = le16_to_cpu(rp->tx_len); hdev->le_def_tx_time = le16_to_cpu(rp->tx_time); +#ifdef TIZEN_BT + mgmt_le_read_host_suggested_data_length_complete(hdev, rp->status); + + hci_dev_unlock(hdev); +#endif + return rp->status; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f82a5af..f67e73f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9294,6 +9294,85 @@ unlock: return err; } + +void mgmt_le_read_host_suggested_data_length_complete(struct hci_dev *hdev, + u8 status) +{ + struct mgmt_pending_cmd *cmd; + struct mgmt_rp_le_read_host_suggested_data_length rp; + + BT_DBG("%s status %u", hdev->name, status); + + cmd = pending_find(MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, hdev); + if (!cmd) { + BT_ERR("cmd not found in the pending list"); + return; + } + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, + mgmt_status(status)); + + memset(&rp, 0, sizeof(rp)); + + rp.def_tx_octets = cpu_to_le16(hdev->le_def_tx_len); + rp.def_tx_time = cpu_to_le16(hdev->le_def_tx_time); + + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, 0, + &rp, sizeof(rp)); + + mgmt_pending_remove(cmd); +} + +static int read_host_suggested_data_length(struct sock *sk, + struct hci_dev *hdev, void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + int err; + + BT_DBG("read_host_suggested_data_length %s", hdev->name); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, + MGMT_STATUS_NOT_SUPPORTED); + goto unlock; + } + + if (pending_find(MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, + MGMT_STATUS_BUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, + hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + err = hci_send_cmd(hdev, HCI_OP_LE_READ_DEF_DATA_LEN, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); + + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11636,6 +11715,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { MGMT_LE_READ_MAXIMUM_DATA_LENGTH_SIZE }, { write_host_suggested_le_data_length, MGMT_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_SIZE }, + { read_host_suggested_data_length, + MGMT_LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE }, }; #endif -- 2.7.4 From 47db594e15fa64dd7ea6fb00fb7c055975733370 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Fri, 16 Sep 2016 15:37:22 +0530 Subject: [PATCH 07/16] Bluetooth: Set le data length command and event Sets the data length for the le data packet with in the advised limits. MGMT command and event are added to handle the setting of data length. Change-Id: Idf18a909ab8a949358d28d78d76faa8719215d4b Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: DoHyun Pyun Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/hci_core.h | 14 ++++++ include/net/bluetooth/mgmt_tizen.h | 23 +++++++++ net/bluetooth/hci_conn.c | 29 ++++++++++++ net/bluetooth/hci_event.c | 32 +++++++++++++ net/bluetooth/mgmt.c | 95 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 957dff5..24de664 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -772,6 +772,12 @@ struct hci_conn { __u8 remote_id; unsigned int sent; +#ifdef TIZEN_BT + __u16 tx_len; + __u16 tx_time; + __u16 rx_len; + __u16 rx_time; +#endif struct sk_buff_head data_q; struct list_head chan_list; @@ -835,6 +841,10 @@ struct hci_conn_params { u16 conn_latency; u16 supervision_timeout; +#ifdef TIZEN_BT + u16 max_tx_octets; + u16 max_tx_time; +#endif enum { HCI_AUTO_CONN_DISABLED, HCI_AUTO_CONN_REPORT, @@ -2432,6 +2442,10 @@ void mgmt_le_write_host_suggested_data_length_complete(struct hci_dev *hdev, u8 status); void mgmt_le_read_host_suggested_data_length_complete(struct hci_dev *hdev, u8 status); +void mgmt_le_data_length_change_complete(struct hci_dev *hdev, + bdaddr_t *bdaddr, u16 tx_octets, u16 tx_time, + u16 rx_octets, u16 rx_time); +int hci_le_set_data_length(struct hci_conn *conn, u16 tx_octets, u16 tx_time); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 2d11d5b..cfb9d50 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -208,6 +208,20 @@ struct mgmt_rp_le_read_host_suggested_data_length { } __packed; #define MGMT_LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE 0 +#define MGMT_OP_LE_SET_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x18) +struct mgmt_cp_le_set_data_length { + bdaddr_t bdaddr; + __le16 max_tx_octets; + __le16 max_tx_time; +} __packed; +#define MGMT_LE_SET_DATA_LENGTH_SIZE 10 + +struct mgmt_rp_le_set_data_length { + __u8 status; + __le16 handle; +} __packed; +#define MGMT_LE_SET_DATA_LENGTH_RSP_SIZE 3 + /* EVENTS */ /* For device name update changes */ @@ -296,4 +310,13 @@ struct mgmt_ev_6lowpan_conn_state_changed { __u8 ifname[16]; } __packed; +#define MGMT_EV_LE_DATA_LENGTH_CHANGED (TIZEN_EV_BASE + 0x0d) +struct mgmt_ev_le_data_length_changed { + struct mgmt_addr_info addr; + __le16 max_tx_octets; + __le16 max_tx_time; + __le16 max_rx_octets; + __le16 max_rx_time; +} __packed; + #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a92c0cc..b834fd2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2572,6 +2572,35 @@ int hci_conn_change_supervision_timeout(struct hci_conn *conn, __u16 timeout) return 0; } + +int hci_le_set_data_length(struct hci_conn *conn, u16 tx_octets, u16 tx_time) +{ + struct hci_dev *hdev = conn->hdev; + struct hci_conn_params *params; + struct hci_cp_le_set_data_len cp; + + hci_dev_lock(hdev); + + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) { + params->max_tx_octets = tx_octets; + params->max_tx_time = tx_time; + } + + hci_dev_unlock(hdev); + + memset(&cp, 0, sizeof(cp)); + cp.handle = cpu_to_le16(conn->handle); + cp.tx_len = cpu_to_le16(tx_octets); + cp.tx_time = cpu_to_le16(tx_time); + + hci_send_cmd(hdev, HCI_OP_LE_SET_DATA_LEN, sizeof(cp), &cp); + + if (params) + return 0x01; + + return 0x00; +} #endif /* Enter active mode */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0f98ffe..452d322 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2383,6 +2383,32 @@ static void hci_vendor_specific_evt(struct hci_dev *hdev, void *data, break; } } + +static void hci_le_data_length_changed_complete_evt(struct hci_dev *hdev, + void *data, + struct sk_buff *skb) +{ + struct hci_ev_le_data_len_change *ev = (void *)skb->data; + struct hci_conn *conn; + + BT_DBG("%s status", hdev->name); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + conn->tx_len = le16_to_cpu(ev->tx_len); + conn->tx_time = le16_to_cpu(ev->tx_time); + conn->rx_len = le16_to_cpu(ev->rx_len); + conn->rx_time = le16_to_cpu(ev->rx_time); + + mgmt_le_data_length_change_complete(hdev, &conn->dst, + conn->tx_len, conn->tx_time, + conn->rx_len, conn->rx_time); + } + + hci_dev_unlock(hdev); +} #endif static u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data, @@ -7540,6 +7566,12 @@ static const struct hci_le_ev { HCI_LE_EV(HCI_EV_LE_REMOTE_CONN_PARAM_REQ, hci_le_remote_conn_param_req_evt, sizeof(struct hci_ev_le_remote_conn_param_req)), +#ifdef TIZEN_BT + /* [0x07 = HCI_EV_LE_DATA_LEN_CHANGE] */ + HCI_LE_EV(HCI_EV_LE_DATA_LEN_CHANGE, + hci_le_data_length_changed_complete_evt, + sizeof(struct hci_ev_le_data_len_change)), +#endif /* [0x0a = HCI_EV_LE_ENHANCED_CONN_COMPLETE] */ HCI_LE_EV(HCI_EV_LE_ENHANCED_CONN_COMPLETE, hci_le_enh_conn_complete_evt, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f67e73f..3c9cf67 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9373,6 +9373,99 @@ unlock: return err; } + +static int set_le_data_length_params(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_le_set_data_length *cp = data; + struct mgmt_rp_le_set_data_length *rp; + struct mgmt_pending_cmd *cmd; + struct hci_conn *conn; + int err = 0; + u16 max_tx_octets, max_tx_time; + size_t rp_len; + + BT_INFO("Set Data length for the device %s", hdev->name); + + hci_dev_lock(hdev); + + rp_len = sizeof(*rp); + rp = kmalloc(rp_len, GFP_KERNEL); + if (!rp) { + err = -ENOMEM; + goto unlock; + } + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_NOT_SUPPORTED); + goto unlock; + } + + if (pending_find(MGMT_OP_LE_SET_DATA_LENGTH, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_BUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_LE_SET_DATA_LENGTH, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + max_tx_octets = __le16_to_cpu(cp->max_tx_octets); + max_tx_time = __le16_to_cpu(cp->max_tx_time); + + BT_DBG("max_tx_octets 0x%4.4x max_tx_time 0x%4.4x latency", + max_tx_octets, max_tx_time); + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (!conn) { + mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_NOT_CONNECTED); + goto unlock; + } + + hci_dev_unlock(hdev); + + err = hci_le_set_data_length(conn, max_tx_octets, max_tx_time); + if (err < 0) + mgmt_pending_remove(cmd); + + rp->handle = conn->handle; + rp->status = 0; + + hci_dev_lock(hdev); + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, 0, + rp, rp_len); +unlock: + kfree(rp); + hci_dev_unlock(hdev); + + return err; +} + +void mgmt_le_data_length_change_complete(struct hci_dev *hdev, + bdaddr_t *bdaddr, u16 tx_octets, u16 tx_time, + u16 rx_octets, u16 rx_time) +{ + struct mgmt_ev_le_data_length_changed ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.max_tx_octets = tx_octets; + ev.max_tx_time = tx_time; + ev.max_rx_octets = rx_octets; + ev.max_rx_time = rx_time; + + mgmt_event(MGMT_EV_LE_DATA_LENGTH_CHANGED, hdev, &ev, sizeof(ev), NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11717,6 +11810,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { MGMT_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_SIZE }, { read_host_suggested_data_length, MGMT_LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE }, + { set_le_data_length_params, + MGMT_LE_SET_DATA_LENGTH_SIZE }, }; #endif -- 2.7.4 From 7d28e81f1508119f56dba97e7f77c026ec8c2eec Mon Sep 17 00:00:00 2001 From: Anuj Jain Date: Fri, 6 Jan 2023 15:29:24 +0530 Subject: [PATCH 08/16] Bluetooth: Add LE connection parameter update Add support for BT_LE_CONN_PARAM in l2cap socket. Change-Id: I9a65b55790a9b2a7e43405890209aaac53002b81 Signed-off-by: Anuj Jain Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/bluetooth.h | 10 ++++++++ include/net/bluetooth/l2cap.h | 3 +++ net/bluetooth/hci_conn.c | 12 ++++++++-- net/bluetooth/l2cap_core.c | 49 +++++++++++++++++++++++++++++++++++++++ net/bluetooth/l2cap_sock.c | 35 ++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index bbc7571..a0342cd 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -41,6 +41,16 @@ /*To enable Tizen specific fixes */ #define TIZEN_BT +#ifdef TIZEN_BT +#define BT_LE_CONN_PARAM 14 +struct le_conn_param { + __u16 min; + __u16 max; + __u16 latency; + __u16 to_multiplier; +}; +#endif + /* Bluetooth versions */ #define BLUETOOTH_VER_1_1 1 #define BLUETOOTH_VER_1_2 2 diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4bd23ae..a035865 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1007,6 +1007,9 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); #ifdef TIZEN_BT +int l2cap_update_connection_param(struct l2cap_conn *conn, u16 min, u16 max, + u16 latency, u16 to_multiplier); + #ifdef CONFIG_BT_6LOWPAN /* IPSP : initialize/deinitialize 6lowpan */ void bt_6lowpan_enable(void); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b834fd2..9a93d8e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -577,8 +577,16 @@ u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, cp.conn_interval_max = cpu_to_le16(max); cp.conn_latency = cpu_to_le16(latency); cp.supervision_timeout = cpu_to_le16(to_multiplier); - cp.min_ce_len = cpu_to_le16(0x0000); - cp.max_ce_len = cpu_to_le16(0x0000); + +#ifdef TIZEN_BT + cp.min_ce_len = cpu_to_le16(0x0009); + cp.max_ce_len = cpu_to_le16(0x0009); + + BT_INFO("[%s(%d)] Sent to Remote - Min Connection Interval: %u (in slots), Max Connection Interval: %u (in slots)", __FUNCTION__, __LINE__, min, max); +#else + cp.min_ce_len = cpu_to_le16(0x0000); + cp.max_ce_len = cpu_to_le16(0x0000); +#endif hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7ce906e..13d40c7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1733,6 +1733,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (hcon->out) smp_conn_security(hcon, hcon->pending_sec_level); +#ifndef TIZEN_BT /* For LE peripheral connections, make sure the connection interval * is in the range of the minimum and maximum interval that has * been configured for this connection. If not, then trigger @@ -1751,6 +1752,35 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req); } +#else +/* +* Too small supervision timeout causes sudden link loss, +* when remote device has multiple links and it cannot manage those +* properly. +* +* To protect such a case, it needs to widen supervision timeout +*/ + if (hcon->role == HCI_ROLE_SLAVE && + hcon->le_supv_timeout < hdev->le_supv_timeout) { + if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC && + hcon->features[0][0] & HCI_LE_CONN_PARAM_REQ_PROC) { + BT_DBG("use hci_le_conn_update"); + hci_le_conn_update(hcon, + hcon->le_conn_min_interval, + hcon->le_conn_max_interval, + hcon->le_conn_latency, + hdev->le_supv_timeout); + } else { + BT_DBG("use l2cap conn_update"); + l2cap_update_connection_param(conn, + hcon->le_conn_min_interval, + hcon->le_conn_max_interval, + hcon->le_conn_latency, + hdev->le_supv_timeout); + } + } + +#endif } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -5601,6 +5631,25 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, return 0; } +#ifdef TIZEN_BT +int l2cap_update_connection_param(struct l2cap_conn *conn, u16 min, u16 max, + u16 latency, u16 to_multiplier) +{ + struct l2cap_conn_param_update_req req; + + req.min = cpu_to_le16(min); + req.max = cpu_to_le16(max); + req.latency = cpu_to_le16(latency); + req.to_multiplier = cpu_to_le16(to_multiplier); + + BT_INFO("[%s(%d)] Sent to Remote - Min Connection Interval: %u (in slots), Max Connection Interval: %u (in slots)", __FUNCTION__, __LINE__, min, max); + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONN_PARAM_UPDATE_REQ, + sizeof(req), &req); + + return 0; +} +#endif + static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3bdfc3f..f965126 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1116,6 +1116,41 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; +#ifdef TIZEN_BT + case BT_LE_CONN_PARAM: { + struct hci_dev *hdev; + struct le_conn_param param; + int err; + + len = min_t(unsigned int, sizeof(param), optlen); + if (copy_from_sockptr(¶m, optval, len)) { + err = -EFAULT; + break; + } + + err = hci_check_conn_params(param.min, param.max, + param.latency, param.to_multiplier); + if (err < 0) + break; + + conn = chan->conn; + hdev = conn->hcon->hdev; + if (conn->hcon->out || + (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC && + conn->hcon->features[0][0] & HCI_LE_CONN_PARAM_REQ_PROC)) { + BT_DBG("use hci_le_conn_update"); + err = hci_le_conn_update(conn->hcon, param.min, + param.max, param.latency, + param.to_multiplier); + break; + } + BT_DBG("use l2cap conn_update"); + err = l2cap_update_connection_param(conn, param.min, + param.max, param.latency, param.to_multiplier); + break; + } +#endif + default: err = -ENOPROTOOPT; break; -- 2.7.4 From 6a992cb14e956ea85b572734adf7681bdf917b3a Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Tue, 30 Jun 2020 14:32:02 +0900 Subject: [PATCH 09/16] drm/vc4: add extcon hdmi connection uevent Add extcon hdmi connection and disconnection uevent when extcon module is enabled. The vc4_hdmi detection is done by polling way, so extcon uevent for connection is a bit slow after changing real hdmi cable state. Signed-off-by: Seung-Woo Kim Signed-off-by: Hoegeun Kwon [mszyprow: this is a squashed set of the following patches from platform/kernel/linux-rpi 'tizen' (c4f85fdcd893) branch: drm/vc4: add extcon hdmi connection uevent drm/vc4: hdmi: Fix hotplug extcon uevent to works ported and adapted to Linux v6.6 kernel base] Signed-off-by: Marek Szyprowski Change-Id: I2a825241cd72befd1f75bd094405f719d4b20638 --- drivers/gpu/drm/vc4/vc4_hdmi.c | 34 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_hdmi.h | 9 +++++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b56d736..0722636 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -496,6 +497,15 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector, vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status); pm_runtime_put(&vc4_hdmi->pdev->dev); +#ifdef CONFIG_EXTCON + if (status != vc4_hdmi->status) { + extcon_set_state_sync(vc4_hdmi->edev, EXTCON_DISP_HDMI, + (status == connector_status_connected ? + true : false)); + vc4_hdmi->status = status; + } +#endif + return status; } @@ -3676,6 +3686,13 @@ static void vc4_hdmi_put_ddc_device(void *ptr) put_device(&vc4_hdmi->ddc->dev); } +#ifdef CONFIG_EXTCON +static const unsigned int vc4_hdmi_extcon_cable[] = { + EXTCON_DISP_HDMI, + EXTCON_NONE, +}; +#endif + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) { const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev); @@ -3738,6 +3755,23 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; +#ifdef CONFIG_EXTCON + vc4_hdmi->status = connector_status_disconnected; + + /* Initialize extcon device */ + vc4_hdmi->edev = devm_extcon_dev_allocate(dev, vc4_hdmi_extcon_cable); + if (IS_ERR(vc4_hdmi->edev)) { + dev_err(dev, "failed to allocate memory for extcon\n"); + return PTR_ERR(vc4_hdmi->edev); + } + + ret = devm_extcon_dev_register(dev, vc4_hdmi->edev); + if (ret) { + dev_err(dev, "failed to register extcon device\n"); + return ret; + } +#endif + /* Only use the GPIO HPD pin if present in the DT, otherwise * we'll use the HDMI core's register. */ diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 79811fb..4a96d2f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -12,6 +12,10 @@ struct vc4_hdmi; struct vc4_hdmi_register; struct vc4_hdmi_connector_state; +#ifdef CONFIG_EXTCON +struct extcon_dev; +#endif + enum vc4_hdmi_phy_channel { PHY_LANE_0 = 0, PHY_LANE_1, @@ -228,6 +232,11 @@ struct vc4_hdmi { * for use outside of KMS hooks. Protected by @mutex. */ enum vc4_hdmi_output_format output_format; + +#ifdef CONFIG_EXTCON + enum drm_connector_status status; + struct extcon_dev *edev; +#endif }; #define connector_to_vc4_hdmi(_connector) \ -- 2.7.4 From 2ec8a3b3a8d5b018f353fcda43e25705b3bbc522 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Mon, 19 Dec 2022 15:57:39 +0900 Subject: [PATCH 10/16] drm/vc4: Add gem_info node via debugfs for vc5 The memps requires gem_info with gem_names to analyze graphics shared memory, so this patch adds gem_info node via common helpers for debugfs. Let's save pid/tgid in private file data only once when gem object is created or prime_fd is imported and use them on gem_info. This is to solve the wrong pid problem of gem_info created as different processes share fd of drm device node. The prime fd created in vc4, but handled in v3d, modified to hanle this in vc4. Signed-off-by: Hoegeun Kwon [mszyprow: ported and adapted to v6.6 kernel release] Signed-off-by: Marek Szyprowski Change-Id: I1430eadbfbdfc197f8e39f952e7f82999e249672 --- drivers/gpu/drm/vc4/vc4_debugfs.c | 73 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_drv.c | 77 ++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vc4/vc4_drv.h | 9 +++++ 3 files changed, 158 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index 8144ded..b553901 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c @@ -27,6 +27,10 @@ vc4_debugfs_init(struct drm_minor *minor) if (vc4->hvs) drm_WARN_ON(drm, vc4_hvs_debugfs_init(minor)); + if (vc4->gen > VC4_GEN_4) { + drm_WARN_ON(drm, vc5_bo_debugfs_init(minor)); + } + if (vc4->v3d) { drm_WARN_ON(drm, vc4_bo_debugfs_init(minor)); drm_WARN_ON(drm, vc4_v3d_debugfs_init(minor)); @@ -51,6 +55,75 @@ static int vc4_debugfs_regset32(struct seq_file *m, void *unused) return 0; } +struct vc5_gem_info_data { + struct drm_file *filp; + struct seq_file *m; +}; + +static int vc5_gem_one_info(int id, void *ptr, void *data) +{ + + struct drm_gem_object *obj = (struct drm_gem_object *)ptr; + struct vc5_gem_info_data *gem_info_data = data; + struct vc4_file *vc4file = gem_info_data->filp->driver_priv; + struct drm_vc5_file_private *file_priv = &vc4file->priv; + + if (!obj) { + DRM_ERROR("failed to get drm_gem_object\n"); + return -EFAULT; + } + + drm_gem_object_get(obj); + + seq_printf(gem_info_data->m, + "%5d\t%5d\t%4d\t%4d\t\t%4d\t0x%08zx\t0x%x\t%4d\t%4d\t\t" + "%4d\t\t0x%p\t%6d\n", + file_priv->pid, + file_priv->tgid, + id, + kref_read(&obj->refcount) - 1, + obj->handle_count, + obj->size, + 0, + 0, + obj->dma_buf ? 1 : 0, + obj->import_attach ? 1 : 0, + obj, + obj->name); + + drm_gem_object_put(obj); + + return 0; +} + +int vc5_debugfs_gem_info(struct seq_file *m, void *data) +{ + struct drm_debugfs_entry *entry = m->private; + struct drm_device *drm_dev = entry->dev; + struct vc5_gem_info_data gem_info_data; + struct drm_file *filp; + + gem_info_data.m = m; + + seq_puts(gem_info_data.m, + "pid\ttgid\thandle\trefcount\thcount\tsize\t\tflags\t" + "pfnmap\texport_to_fd\timport_from_fd\tobj_addr\t\t" + "name\n"); + + mutex_lock(&drm_dev->struct_mutex); + list_for_each_entry(filp, &drm_dev->filelist, lhead) { + gem_info_data.filp = filp; + + spin_lock(&filp->table_lock); + idr_for_each(&filp->object_idr, vc5_gem_one_info, + &gem_info_data); + spin_unlock(&filp->table_lock); + } + mutex_unlock(&drm_dev->struct_mutex); + + return 0; +} + void vc4_debugfs_add_regset32(struct drm_device *drm, const char *name, struct debugfs_regset32 *regset) diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 220e862..6e23a68 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -76,6 +76,41 @@ int vc4_dumb_fixup_args(struct drm_mode_create_dumb *args) return 0; } +static void vc5_gem_register_pid(struct drm_file *file_priv) +{ + struct vc4_file *vc4file = file_priv->driver_priv; + struct drm_vc5_file_private *driver_priv = &vc4file->priv; + + if (!driver_priv->pid && !driver_priv->tgid) { + driver_priv->pid = task_pid_nr(current); + driver_priv->tgid = task_tgid_nr(current); + } else { + if (driver_priv->pid != task_pid_nr(current)) + DRM_DEBUG_KMS("wrong pid: %ld, %ld\n", + (unsigned long)driver_priv->pid, + (unsigned long)task_pid_nr(current)); + if (driver_priv->tgid != task_tgid_nr(current)) + DRM_DEBUG_KMS("wrong tgid: %ld, %ld\n", + (unsigned long)driver_priv->tgid, + (unsigned long)task_tgid_nr(current)); + } +} + +int vc5_drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, + uint32_t *handle) +{ + int ret; + + ret = drm_gem_prime_fd_to_handle(dev, file_priv, prime_fd, handle); + if (ret < 0) + return ret; + + vc5_gem_register_pid(file_priv); + + return ret; +} + static int vc5_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) @@ -86,7 +121,11 @@ static int vc5_dumb_create(struct drm_file *file_priv, if (ret) return ret; - return drm_gem_dma_dumb_create_internal(file_priv, dev, args); + ret = drm_gem_dma_dumb_create_internal(file_priv, dev, args); + if (!ret) + vc5_gem_register_pid(file_priv); + + return ret; } static int vc4_get_param_ioctl(struct drm_device *dev, void *data, @@ -189,6 +228,27 @@ vc4_prime_import_sg_table(struct drm_device *dev, return drm_gem_dma_prime_import_sg_table(dev, attach, sgt); } +static int vc5_open(struct drm_device *dev, struct drm_file *file) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file; + + vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL); + if (!vc4file) + return -ENOMEM; + vc4file->dev = vc4; + + file->driver_priv = vc4file; + return 0; +} + +static void vc5_close(struct drm_device *dev, struct drm_file *file) +{ + struct vc4_file *vc4file = file->driver_priv; + + kfree(vc4file); +} + DEFINE_DRM_GEM_FOPS(vc4_drm_fops); static const struct drm_ioctl_desc vc4_drm_ioctls[] = { @@ -245,6 +305,8 @@ const struct drm_driver vc5_drm_driver = { DRIVER_ATOMIC | DRIVER_GEM), + .open = vc5_open, + .postclose = vc5_close, #if defined(CONFIG_DEBUG_FS) .debugfs_init = vc4_debugfs_init, #endif @@ -252,6 +314,7 @@ const struct drm_driver vc5_drm_driver = { .dumb_create = vc5_dumb_create, .gem_prime_import_sg_table = vc4_prime_import_sg_table, + .prime_fd_to_handle = vc5_drm_gem_prime_fd_to_handle, .fops = &vc4_drm_fops, .name = DRIVER_NAME, @@ -312,6 +375,18 @@ static bool firmware_kms(void) "raspberrypi,rpi-firmware-kms-2711")); } +int vc5_bo_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *drm = minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + + if (vc4->gen == VC4_GEN_4) + return -ENODEV; + + drm_debugfs_add_file(drm, "gem_info", vc5_debugfs_gem_info, NULL); + return 0; +} + static int vc4_drm_bind(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 70703d2..fa51b2b 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -843,6 +843,11 @@ struct vc4_exec_info { bool bin_bo_used; }; +struct drm_vc5_file_private { + pid_t pid; + pid_t tgid; +}; + /* Per-open file private data. Any driver-specific resource that has to be * released when the DRM file is closed should be placed here. */ @@ -855,6 +860,7 @@ struct vc4_file { } perfmon; bool bin_bo_used; + struct drm_vc5_file_private priv; }; static inline struct vc4_exec_info * @@ -985,6 +991,7 @@ void vc4_bo_dec_usecnt(struct vc4_bo *bo); void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo); void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo); int vc4_bo_debugfs_init(struct drm_minor *minor); +int vc5_bo_debugfs_init(struct drm_minor *minor); /* vc4_crtc.c */ extern struct platform_driver vc4_crtc_driver; @@ -1157,6 +1164,8 @@ bool vc4_check_tex_size(struct vc4_exec_info *exec, struct vc4_validated_shader_info * vc4_validate_shader(struct drm_gem_dma_object *shader_obj); +int vc5_debugfs_gem_info(struct seq_file *m, void *data); + /* vc4_perfmon.c */ void vc4_perfmon_get(struct vc4_perfmon *perfmon); void vc4_perfmon_put(struct vc4_perfmon *perfmon); -- 2.7.4 From bd2cb30a6bb5097376f0df698ca870c32de0f637 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Mon, 19 Sep 2022 19:35:14 +0900 Subject: [PATCH 11/16] drm/v3d: Add gpu_gem_info node via debugfs Add gpu_gem_info node via debugfs of dri debug sysfs for each process with pid/tgid and its gem objects. Same gem object can be opened from multiple processes, so from the gpu_gem_info node, it can print same gem in multiple lines. Ported from the commit dea4ace78ec7 ("drm/vc4: Add gem_info node via debugfs") to v3d. NOTE: From Raspberry Pi 4 board, v3d gpu is card0 and also render node in dri card128, so accessing can be from both nodes. For render fixed node, it is /sys/kernel/debug/dri/128/gpu_gem_info. Also, Raspberry Pi 4 board gives entire gem count and total size with /sys/kernel/debug/dri/128/bo_stats. Signed-off-by: Seung-Woo Kim [mszyprow: ported and adapted to v6.6 kernel release] Signed-off-by: Marek Szyprowski Change-Id: I0b9cc241d551904a95cafb7531c50ba6e1dd9082 --- drivers/gpu/drm/v3d/v3d_bo.c | 43 ++++++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_debugfs.c | 69 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_drv.c | 1 + drivers/gpu/drm/v3d/v3d_drv.h | 9 +++++ 4 files changed, 122 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c index 8b3229a..8c28e80 100644 --- a/drivers/gpu/drm/v3d/v3d_bo.c +++ b/drivers/gpu/drm/v3d/v3d_bo.c @@ -167,6 +167,46 @@ v3d_prime_import_sg_table(struct drm_device *dev, return obj; } +static void v3d_gem_register_pid(struct drm_file *file) +{ + struct v3d_file_priv *v3d_priv = file->driver_priv; + struct drm_v3d_file_private *pid_priv; + + if (!v3d_priv) + return; + + pid_priv = &v3d_priv->priv; + + if (!pid_priv->pid && !pid_priv->tgid) { + pid_priv->pid = task_pid_nr(current); + pid_priv->tgid = task_tgid_nr(current); + } else { + if (pid_priv->pid != task_pid_nr(current)) + DRM_DEBUG_KMS("wrong pid: %ld, %ld\n", + (unsigned long)pid_priv->pid, + (unsigned long)task_pid_nr(current)); + if (pid_priv->tgid != task_tgid_nr(current)) + DRM_DEBUG_KMS("wrong tgid: %ld, %ld\n", + (unsigned long)pid_priv->tgid, + (unsigned long)task_tgid_nr(current)); + } +} + +int v3d_drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, + uint32_t *handle) +{ + int ret; + + ret = drm_gem_prime_fd_to_handle(dev, file_priv, prime_fd, handle); + if (ret < 0) + return ret; + + v3d_gem_register_pid(file_priv); + + return ret; +} + int v3d_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -186,6 +226,9 @@ int v3d_create_bo_ioctl(struct drm_device *dev, void *data, args->offset = bo->node.start << PAGE_SHIFT; ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + if (!ret) + v3d_gem_register_pid(file_priv); + drm_gem_object_put(&bo->base.base); return ret; diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c index 9a94065..0d4552e 100644 --- a/drivers/gpu/drm/v3d/v3d_debugfs.c +++ b/drivers/gpu/drm/v3d/v3d_debugfs.c @@ -338,12 +338,81 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) return 0; } +struct v3d_gem_info_data { + struct drm_file *filp; + struct seq_file *m; +}; + +static int v3d_gem_one_info(int id, void *ptr, void *data) +{ + struct drm_gem_object *obj = (struct drm_gem_object *)ptr; + struct v3d_gem_info_data *gem_info_data = data; + struct v3d_file_priv *v3d_priv = gem_info_data->filp->driver_priv; + struct drm_v3d_file_private *pid_priv = &v3d_priv->priv; + + if (!obj) { + DRM_ERROR("failed to get drm_gem_object\n"); + return -EFAULT; + } + + drm_gem_object_get(obj); + + seq_printf(gem_info_data->m, + "%5d\t%5d\t%4d\t%4d\t\t%4d\t0x%08zx\t0x%x\t%4d\t%4d\t\t" + "%4d\t\t0x%p\t%6d\n", + pid_priv->pid, + pid_priv->tgid, + id, + kref_read(&obj->refcount) - 1, + obj->handle_count, + obj->size, + 0, + 0, + obj->dma_buf ? 1 : 0, + obj->import_attach ? 1 : 0, + obj, + obj->name); + + drm_gem_object_put(obj); + + return 0; +} + +int v3d_debugfs_gem_info(struct seq_file *m, void *data) +{ + struct drm_debugfs_entry *entry = m->private; + struct drm_device *drm_dev = entry->dev; + struct v3d_gem_info_data gem_info_data; + struct drm_file *filp; + + gem_info_data.m = m; + + seq_puts(gem_info_data.m, + "pid\ttgid\thandle\trefcount\thcount\tsize\t\tflags\t" + "pfnmap\texport_to_fd\timport_from_fd\tobj_addr\t\t" + "name\n"); + + mutex_lock(&drm_dev->struct_mutex); + list_for_each_entry(filp, &drm_dev->filelist, lhead) { + gem_info_data.filp = filp; + + spin_lock(&filp->table_lock); + idr_for_each(&filp->object_idr, v3d_gem_one_info, + &gem_info_data); + spin_unlock(&filp->table_lock); + } + mutex_unlock(&drm_dev->struct_mutex); + + return 0; +} + static const struct drm_debugfs_info v3d_debugfs_list[] = { {"v3d_ident", v3d_v3d_debugfs_ident, 0}, {"v3d_regs", v3d_v3d_debugfs_regs, 0}, {"measure_clock", v3d_measure_clock, 0}, {"bo_stats", v3d_debugfs_bo_stats, 0}, {"gpu_usage", v3d_debugfs_gpu_usage, 0}, + {"gpu_gem_info", v3d_debugfs_gem_info, 0}, {"gpu_pid_usage", v3d_debugfs_gpu_pid_usage, 0}, }; diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 1258a47..77e634e 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -174,6 +174,7 @@ static const struct drm_driver v3d_drm_driver = { #endif .gem_create_object = v3d_create_object, + .prime_fd_to_handle = v3d_drm_gem_prime_fd_to_handle, .gem_prime_import_sg_table = v3d_prime_import_sg_table, .ioctls = v3d_drm_ioctls, diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index e2f1986..f312c27 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -216,6 +216,11 @@ v3d_has_csd(struct v3d_dev *v3d) #define v3d_to_pdev(v3d) to_platform_device((v3d)->drm.dev) +struct drm_v3d_file_private { + pid_t pid; + pid_t tgid; +}; + /* The per-fd struct, which tracks the MMU mappings. */ struct v3d_file_priv { struct v3d_dev *v3d; @@ -226,6 +231,7 @@ struct v3d_file_priv { } perfmon; struct drm_sched_entity sched_entity[V3D_MAX_QUEUES]; + struct drm_v3d_file_private priv; }; struct v3d_bo { @@ -425,6 +431,9 @@ int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *v3d_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); +int v3d_drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, + uint32_t *handle); /* v3d_debugfs.c */ void v3d_debugfs_init(struct drm_minor *minor); -- 2.7.4 From df63e899d9d8298b05656a9c3511756f58837afd Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 18 Feb 2020 13:36:40 +0900 Subject: [PATCH 12/16] usb: dwc2: gadget: Set extcon state for usb cable as always true To inform to userspace as enable usb features always, set extcon state for usb cable as connected permanently. To enable this, add "g-extcon-always-on" property on dt. Signed-off-by: Dongwoo Lee [mszyprow: ported and adapted to v6.6 kernel release] Signed-off-by: Marek Szyprowski Change-Id: Ib0e9982b426fda7deed510e482d6731a2f23d0b1 --- drivers/usb/dwc2/core.h | 3 +++ drivers/usb/dwc2/gadget.c | 20 ++++++++++++++++++++ drivers/usb/dwc2/params.c | 5 +++++ 3 files changed, 28 insertions(+) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index c92a1da..faf40c1 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -497,6 +497,9 @@ struct dwc2_core_params { u32 g_rx_fifo_size; u32 g_np_tx_fifo_size; u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; +#if IS_ENABLED(CONFIG_EXTCON) + bool g_extcon_always_on; +#endif bool change_speed_quirk; }; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index b517a72..68292c2 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -5060,6 +5061,25 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) dwc2_hsotg_dump(hsotg); +#if IS_ENABLED(CONFIG_EXTCON) + if (hsotg->params.g_extcon_always_on) { + struct extcon_dev *edev; + static const unsigned int supported_cable[] = { + EXTCON_USB, + EXTCON_NONE, + }; + + edev = devm_extcon_dev_allocate(dev, supported_cable); + if (IS_ERR(edev)) + return PTR_ERR(edev); + + ret = devm_extcon_dev_register(dev, edev); + if (ret) + return ret; + + extcon_set_state_sync(edev, EXTCON_USB, true); + } +#endif return 0; } diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 93f52e3..d0508a0 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -546,6 +546,11 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) &p->g_np_tx_fifo_size); num = device_property_count_u32(hsotg->dev, "g-tx-fifo-size"); +#if IS_ENABLED(CONFIG_EXTCON) + if (of_find_property(hsotg->dev->of_node, + "g-extcon-always-on", NULL)) + p->g_extcon_always_on = 1; +#endif if (num > 0) { num = min(num, 15); memset(p->g_tx_fifo_size, 0, -- 2.7.4 From ba0b4a5cd974d3a7a016bb6d3a1a533ed00470ca Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Thu, 27 Oct 2022 19:53:47 +0900 Subject: [PATCH 13/16] overlays: Add dwc2-tizen-overlay Add g-extcon-always-on value, Set extcon state for dwc2 cable as always true. Signed-off-by: Dongwoo Lee Signed-off-by: Hoegeun Kwon Signed-off-by: Marek Szyprowski Change-Id: Ibd209a402978343eeb6af3d4597a80d48f53f019 --- arch/arm/boot/dts/overlays/Makefile | 1 + arch/arm/boot/dts/overlays/dwc2-tizen-overlay.dts | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/dwc2-tizen-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index cab9b8a..d6d4b7f 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -60,6 +60,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ draws.dtbo \ dwc-otg.dtbo \ dwc2.dtbo \ + dwc2-tizen.dtbo \ edt-ft5406.dtbo \ enc28j60.dtbo \ enc28j60-spi2.dtbo \ diff --git a/arch/arm/boot/dts/overlays/dwc2-tizen-overlay.dts b/arch/arm/boot/dts/overlays/dwc2-tizen-overlay.dts new file mode 100644 index 0000000..d2a929f --- /dev/null +++ b/arch/arm/boot/dts/overlays/dwc2-tizen-overlay.dts @@ -0,0 +1,14 @@ +/dts-v1/; +/plugin/; + +#include "dwc2-overlay.dts" + +/{ + compatible = "brcm,bcm2835"; + + fragment@0 { + dwc2_usb: __overlay__ { + g-extcon-always-on; + }; + }; +}; -- 2.7.4 From 212b15900a7ed5a61dffe23dc2b42d1a46603253 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 26 Feb 2024 11:52:54 +0900 Subject: [PATCH 14/16] packaging: Add NO_JEVENTS=1 option to build perf Add NO_JEVENTS=1 option to build perf for aarch64. During building aarch64, it's failed with below message. [ 61s] Makefile.config:846: No python interpreter was found: disables Python support - please install python-devel/python-dev [ 61s] Makefile.config:881: *** ERROR: No python interpreter needed for jevents generation. Install python or build with NO_JEVENTS=1.. Stop. [ 61s] make[1]: *** [Makefile.perf:242: sub-make] Error 2 [ 61s] make: *** [Makefile:70: all] Error 2 [ 61s] error: Bad exit status from /var/tmp/rpm-tmp.dIxz2n (%build) Change-Id: I77ebb333561733cef1f45cb1432dedacb3b5191c Signed-off-by: Jaehoon Chung --- packaging/linux-rpi4.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/linux-rpi4.spec b/packaging/linux-rpi4.spec index 05ed5c8..360c33b 100644 --- a/packaging/linux-rpi4.spec +++ b/packaging/linux-rpi4.spec @@ -147,7 +147,7 @@ for target in %{variant} %{variant}-rt; do # Build perf # WERROR=0 make O=build/${target} -s -C tools/lib/traceevent %{?_smp_mflags} - WERROR=0 make O=build/${target} -s -C tools/perf EXTRA_CFLAGS="-fPIE -rdynamic" %{?_smp_mflags} NO_LIBTRACEEVENT=1 + WERROR=0 make O=build/${target} -s -C tools/perf EXTRA_CFLAGS="-fPIE -rdynamic" %{?_smp_mflags} NO_LIBTRACEEVENT=1 NO_JEVENTS=1 ;; %{variant}-rt) cat _localversion-rt > localversion-rt @@ -201,7 +201,7 @@ for target in %{variant} %{variant}-rt; do %endif # Install perf - WERROR=0 make O=build/${target} -s -C tools/perf EXTRA_CFLAGS="-fPIE -rdynamic" DESTDIR=%{buildroot}/usr install NO_LIBTRACEEVENT=1 + WERROR=0 make O=build/${target} -s -C tools/perf EXTRA_CFLAGS="-fPIE -rdynamic" DESTDIR=%{buildroot}/usr install NO_LIBTRACEEVENT=1 NO_JEVENTS=1 rm -rf %{buildroot}/usr/etc rm -rf %{buildroot}/usr/lib/debug rm -rf %{buildroot}/usr/lib/perf -- 2.7.4 From 64e41c96c4fc0a91f602bd77db0f22eefd9119e8 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 20 Jan 2023 13:41:37 +0900 Subject: [PATCH 15/16] Partially Revert "brcmfmac: p2p: Deal with set but unused variables" This partially reverts commit 2de64ca7c9fadd32b261530592db4a6adbfcb53f. The commit 61325dc073e2 ("Revert "brcmfmac: move configuration of probe request IEs"") requires vif set with p2p interface, but commit 2de64ca7c9fa removes setting. Partially revert the commit to support p2p usage with p2p interface. Change-Id: Iaa3a6c57bb9e14c80ef9f4714eea0cfc447d6adc Reported-by: Jiung Yu Signed-off-by: Seung-Woo Kim Signed-off-by: Jaehoon Chung --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 7376f9f..99ee0e6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -912,6 +912,8 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy, if (err) return err; + vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + /* override .run_escan() callback. */ cfg->escan_info.run = brcmf_p2p_run_escan; } -- 2.7.4 From 1fd25f5f88e058ef2a184e8bae3b82b749b6c67a Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Mon, 21 Dec 2020 12:40:27 +0100 Subject: [PATCH 16/16] kdbus: Revert "fs: unexport poll_schedule_timeout" MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This reverts commit 8f546ae1fc5ce8396827d4868c7eee1f1cc6947a. Change-Id: Ic603b089a2e7a3d65c86fbb41309c105c9a1e2fa Signed-off-by: Łukasz Stelmach Signed-off-by: Seung-Woo Kim --- fs/select.c | 3 ++- include/linux/poll.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/select.c b/fs/select.c index 0ee55af..c66cc7a 100644 --- a/fs/select.c +++ b/fs/select.c @@ -234,7 +234,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, add_wait_queue(wait_address, &entry->wait); } -static int poll_schedule_timeout(struct poll_wqueues *pwq, int state, +int poll_schedule_timeout(struct poll_wqueues *pwq, int state, ktime_t *expires, unsigned long slack) { int rc = -EINTR; @@ -259,6 +259,7 @@ static int poll_schedule_timeout(struct poll_wqueues *pwq, int state, return rc; } +EXPORT_SYMBOL(poll_schedule_timeout); /** * poll_select_set_timeout - helper function to setup the timeout value diff --git a/include/linux/poll.h b/include/linux/poll.h index a9e0e1c..3b8e699 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -110,6 +110,8 @@ struct poll_wqueues { extern void poll_initwait(struct poll_wqueues *pwq); extern void poll_freewait(struct poll_wqueues *pwq); +extern int poll_schedule_timeout(struct poll_wqueues *pwq, int state, + ktime_t *expires, unsigned long slack); extern u64 select_estimate_accuracy(struct timespec64 *tv); #define MAX_INT64_SECONDS (((s64)(~((u64)0)>>1)/HZ)-1) -- 2.7.4