diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index d4e2cb9a4eb4..bede8b005594 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,9 @@ #define ECDSA_OFFSET 644 #define ECDSA_HEADER_LEN 320 +#define BTINTEL_PPAG_NAME "PPAG" +#define BTINTEL_PPAG_PREFIX "\\_SB_.PCI0.XHCI.RHUB" + #define CMD_WRITE_BOOT_PARAMS 0xfc0e struct cmd_write_boot_params { __le32 boot_addr; @@ -1278,6 +1282,63 @@ static int btintel_read_debug_features(struct hci_dev *hdev, return 0; } +static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data, + void **ret) +{ + acpi_status status; + size_t len; + struct btintel_ppag *ppag = data; + union acpi_object *p, *elements; + struct acpi_buffer string = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + struct hci_dev *hdev = ppag->hdev; + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); + if (ACPI_FAILURE(status)) { + bt_dev_warn(hdev, "ACPI Failure: %s", acpi_format_exception(status)); + return status; + } + + if (strncmp(BTINTEL_PPAG_PREFIX, string.pointer, + strlen(BTINTEL_PPAG_PREFIX))) { + kfree(string.pointer); + return AE_OK; + } + + len = strlen(string.pointer); + if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) { + kfree(string.pointer); + return AE_OK; + } + kfree(string.pointer); + + status = acpi_evaluate_object(handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + bt_dev_warn(hdev, "ACPI Failure: %s", acpi_format_exception(status)); + return status; + } + + p = buffer.pointer; + ppag = (struct btintel_ppag *)data; + + if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) { + kfree(buffer.pointer); + bt_dev_warn(hdev, "Invalid object type: %d or package count: %d", + p->type, p->package.count); + return AE_ERROR; + } + + elements = p->package.elements; + + /* PPAG table is located at element[1] */ + p = &elements[1]; + + ppag->domain = (u32)p->package.elements[0].integer.value; + ppag->mode = (u32)p->package.elements[1].integer.value; + kfree(buffer.pointer); + return AE_CTRL_TERMINATE; +} + static int btintel_set_debug_features(struct hci_dev *hdev, const struct intel_debug_features *features) { @@ -2251,6 +2312,58 @@ error: return err; } +static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver) +{ + acpi_status status; + struct btintel_ppag ppag; + struct sk_buff *skb; + struct btintel_loc_aware_reg ppag_cmd; + + /* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */ + switch (ver->cnvr_top & 0xFFF) { + case 0x504: /* Hrp2 */ + case 0x202: /* Jfp2 */ + case 0x201: /* Jfp1 */ + return; + } + + memset(&ppag, 0, sizeof(ppag)); + + ppag.hdev = hdev; + status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, NULL, + btintel_ppag_callback, &ppag, NULL); + + if (ACPI_FAILURE(status)) { + /* Do not log warning message if ACPI entry is not found */ + if (status == AE_NOT_FOUND) + return; + bt_dev_warn(hdev, "PPAG: ACPI Failure: %s", acpi_format_exception(status)); + return; + } + + if (ppag.domain != 0x12) { + bt_dev_warn(hdev, "PPAG-BT Domain disabled"); + return; + } + + /* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */ + if (!(ppag.mode & BIT(0))) { + bt_dev_dbg(hdev, "PPAG disabled"); + return; + } + + ppag_cmd.mcc = cpu_to_le32(0); + ppag_cmd.sel = cpu_to_le32(0); /* 0 - Enable , 1 - Disable, 2 - Testing mode */ + ppag_cmd.delta = cpu_to_le32(0); + skb = __hci_cmd_sync(hdev, 0xfe19, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb)); + return; + } + kfree_skb(skb); +} + static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver) { @@ -2297,6 +2410,9 @@ static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); + /* Set PPAG feature */ + btintel_set_ppag(hdev, ver); + /* Read the Intel version information after loading the FW */ err = btintel_read_version_tlv(hdev, &new_ver); if (err) diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index e0060e58573c..8e7da877efae 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -137,6 +137,19 @@ struct intel_offload_use_cases { __u8 preset[8]; } __packed; +/* structure to store the PPAG data read from ACPI table */ +struct btintel_ppag { + u32 domain; + u32 mode; + struct hci_dev *hdev; +}; + +struct btintel_loc_aware_reg { + __le32 mcc; + __le32 sel; + __le32 delta; +} __packed; + #define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8)) #define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16)) #define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2ad4efdd9e40..18bc94718711 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -64,6 +64,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_BROKEN_SHUTDOWN_LED BIT(24) #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) +#define BTUSB_ACTIONS_SEMI BIT(27) static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -492,6 +493,10 @@ static const struct usb_device_id blacklist_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01), .driver_info = BTUSB_IGNORE }, + /* Realtek 8821CE Bluetooth devices */ + { USB_DEVICE(0x13d3, 0x3529), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, + /* Realtek 8822CE Bluetooth devices */ { USB_DEVICE(0x0bda, 0xb00c), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, @@ -566,6 +571,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe0e0), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, @@ -677,6 +685,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + /* Actions Semiconductor ATS2851 based devices */ + { USB_DEVICE(0x10d7, 0xb012), .driver_info = BTUSB_ACTIONS_SEMI }, + /* Silicon Wave based devices */ { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE }, @@ -4098,6 +4109,11 @@ static int btusb_probe(struct usb_interface *intf, set_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags); } + if (id->driver_info & BTUSB_ACTIONS_SEMI) { + /* Support is advertised, but not implemented */ + set_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks); + } + if (!reset) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index bbe9cf1cae27..3df8c3606e93 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -128,13 +128,13 @@ struct qca_memdump_event_hdr { __u8 evt; __u8 plen; __u16 opcode; - __u16 seq_no; + __le16 seq_no; __u8 reserved; } __packed; struct qca_dump_size { - u32 dump_size; + __le32 dump_size; } __packed; struct qca_data { @@ -1588,10 +1588,11 @@ static bool qca_wakeup(struct hci_dev *hdev) struct hci_uart *hu = hci_get_drvdata(hdev); bool wakeup; - /* UART driver handles the interrupt from BT SoC.So we need to use - * device handle of UART driver to get the status of device may wakeup. + /* BT SoC attached through the serial bus is handled by the serdev driver. + * So we need to use the device handle of the serdev driver to get the + * status of device may wakeup. */ - wakeup = device_may_wakeup(hu->serdev->ctrl->dev.parent); + wakeup = device_may_wakeup(&hu->serdev->ctrl->dev); bt_dev_dbg(hu->hdev, "wakeup status : %d", wakeup); return wakeup; diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 8d773b042c85..400f8a7d0c3f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2156,7 +2156,7 @@ struct hci_cp_le_big_create_sync { __u8 mse; __le16 timeout; __u8 num_bis; - __u8 bis[0]; + __u8 bis[]; } __packed; #define HCI_OP_LE_BIG_TERM_SYNC 0x206c @@ -2174,7 +2174,7 @@ struct hci_cp_le_setup_iso_path { __le16 codec_vid; __u8 delay[3]; __u8 codec_cfg_len; - __u8 codec_cfg[0]; + __u8 codec_cfg[]; } __packed; struct hci_rp_le_setup_iso_path { diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 743f6f59dff8..e18a927669c0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -109,6 +109,8 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_STATIC_ADDRESS 0x00008000 #define MGMT_SETTING_PHY_CONFIGURATION 0x00010000 #define MGMT_SETTING_WIDEBAND_SPEECH 0x00020000 +#define MGMT_SETTING_CIS_CENTRAL 0x00040000 +#define MGMT_SETTING_CIS_PERIPHERAL 0x00080000 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index acf563fbdfd9..17b946f9ba31 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1061,8 +1061,15 @@ int hci_conn_del(struct hci_conn *conn) if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; - if (sco) + if (sco) { sco->link = NULL; + /* Due to race, SCO connection might be not established + * yet at this point. Delete it now, otherwise it is + * possible for it to be stuck and can't be deleted. + */ + if (sco->handle == HCI_CONN_HANDLE_UNSET) + hci_conn_del(sco); + } /* Unacked frames */ hdev->acl_cnt += conn->sent; @@ -1243,6 +1250,8 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) if (conn != hci_lookup_le_connect(hdev)) goto done; + /* Flush to make sure we send create conn cancel command if needed */ + flush_delayed_work(&conn->le_conn_timeout); hci_conn_failed(conn, bt_status(err)); done: @@ -1981,16 +1990,14 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, qos->latency = conn->le_conn_latency; } -static struct hci_conn *hci_bind_bis(struct hci_conn *conn, - struct bt_iso_qos *qos) +static void hci_bind_bis(struct hci_conn *conn, + struct bt_iso_qos *qos) { /* Update LINK PHYs according to QoS preference */ conn->le_tx_phy = qos->out.phy; conn->le_tx_phy = qos->out.phy; conn->iso_qos = *qos; conn->state = BT_BOUND; - - return conn; } static int create_big_sync(struct hci_dev *hdev, void *data) @@ -2119,11 +2126,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, if (IS_ERR(conn)) return conn; - conn = hci_bind_bis(conn, qos); - if (!conn) { - hci_conn_drop(conn); - return ERR_PTR(-ENOMEM); - } + hci_bind_bis(conn, qos); /* Add Basic Announcement into Peridic Adv Data if BASE is set */ if (base_len && base) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a3e0dc6a6e73..adfc3ea06d08 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2683,14 +2683,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) if (IS_ERR(skb)) return PTR_ERR(skb); - /* Channel lock is released before requesting new skb and then - * reacquired thus we need to recheck channel state. - */ - if (chan->state != BT_CONNECTED) { - kfree_skb(skb); - return -ENOTCONN; - } - l2cap_do_send(chan, skb); return len; } @@ -2735,14 +2727,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) if (IS_ERR(skb)) return PTR_ERR(skb); - /* Channel lock is released before requesting new skb and then - * reacquired thus we need to recheck channel state. - */ - if (chan->state != BT_CONNECTED) { - kfree_skb(skb); - return -ENOTCONN; - } - l2cap_do_send(chan, skb); err = len; break; @@ -2763,14 +2747,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) */ err = l2cap_segment_sdu(chan, &seg_queue, msg, len); - /* The channel could have been closed while segmenting, - * check that it is still connected. - */ - if (chan->state != BT_CONNECTED) { - __skb_queue_purge(&seg_queue); - err = -ENOTCONN; - } - if (err) break; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index ca8f07f3542b..eebe256104bc 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1624,6 +1624,14 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, if (!skb) return ERR_PTR(err); + /* Channel lock is released before requesting new skb and then + * reacquired thus we need to recheck channel state. + */ + if (chan->state != BT_CONNECTED) { + kfree_skb(skb); + return ERR_PTR(-ENOTCONN); + } + skb->priority = sk->sk_priority; bt_cb(skb)->l2cap.chan = chan; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d2ea8e19aa1b..7add66f30e4d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -859,6 +859,12 @@ static u32 get_supported_settings(struct hci_dev *hdev) hdev->set_bdaddr) settings |= MGMT_SETTING_CONFIGURATION; + if (cis_central_capable(hdev)) + settings |= MGMT_SETTING_CIS_CENTRAL; + + if (cis_peripheral_capable(hdev)) + settings |= MGMT_SETTING_CIS_PERIPHERAL; + settings |= MGMT_SETTING_PHY_CONFIGURATION; return settings; @@ -932,6 +938,12 @@ static u32 get_current_settings(struct hci_dev *hdev) if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED)) settings |= MGMT_SETTING_WIDEBAND_SPEECH; + if (cis_central_capable(hdev)) + settings |= MGMT_SETTING_CIS_CENTRAL; + + if (cis_peripheral_capable(hdev)) + settings |= MGMT_SETTING_CIS_PERIPHERAL; + return settings; }