Commit 9f3248c9 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-next-2022-01-07' of...

Merge tag 'for-net-next-2022-01-07' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Luiz Augusto von Dentz says:

====================
bluetooth-next pull request for net-next:

 - Add support for Foxconn QCA 0xe0d0
 - Fix HCI init sequence on MacBook Air 8,1 and 8,2
 - Fix Intel firmware loading on legacy ROM devices

* tag 'for-net-next-2022-01-07' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next:
  Bluetooth: hci_sock: fix endian bug in hci_sock_setsockopt()
  Bluetooth: L2CAP: uninitialized variables in l2cap_sock_setsockopt()
  Bluetooth: btqca: sequential validation
  Bluetooth: btusb: Add support for Foxconn QCA 0xe0d0
  Bluetooth: btintel: Fix broken LED quirk for legacy ROM devices
  Bluetooth: hci_event: Rework hci_inquiry_result_with_rssi_evt
  Bluetooth: btbcm: disable read tx power for MacBook Air 8,1 and 8,2
  Bluetooth: hci_qca: Fix NULL vs IS_ERR_OR_NULL check in qca_serdev_probe
  Bluetooth: hci_bcm: Check for error irq
====================

Link: https://lore.kernel.org/r/20220107210942.3750887-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents d5c8725c b9f9dbad
......@@ -363,6 +363,18 @@ static const struct dmi_system_id disable_broken_read_transmit_power[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,4"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,1"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,2"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
......
......@@ -2355,8 +2355,15 @@ static int btintel_setup_combined(struct hci_dev *hdev)
* As a workaround, send HCI Reset command first which will reset the
* number of completed commands and allow normal command processing
* from now on.
*
* Regarding the INTEL_BROKEN_SHUTDOWN_LED flag, these devices maybe
* in the SW_RFKILL ON state as a workaround of fixing LED issue during
* the shutdown() procedure, and once the device is in SW_RFKILL ON
* state, the only way to exit out of it is sending the HCI_Reset
* command.
*/
if (btintel_test_flag(hdev, INTEL_BROKEN_INITIAL_NCMD)) {
if (btintel_test_flag(hdev, INTEL_BROKEN_INITIAL_NCMD) ||
btintel_test_flag(hdev, INTEL_BROKEN_SHUTDOWN_LED)) {
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
......@@ -2428,12 +2435,6 @@ static int btintel_setup_combined(struct hci_dev *hdev)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks);
/* These devices have an issue with LED which doesn't
* go off immediately during shutdown. Set the flag
* here to send the LED OFF command during shutdown.
*/
btintel_set_flag(hdev, INTEL_BROKEN_LED);
err = btintel_legacy_rom_setup(hdev, &ver);
break;
case 0x0b: /* SfP */
......@@ -2586,9 +2587,10 @@ static int btintel_shutdown_combined(struct hci_dev *hdev)
/* Some platforms have an issue with BT LED when the interface is
* down or BT radio is turned off, which takes 5 seconds to BT LED
* goes off. This command turns off the BT LED immediately.
* goes off. As a workaround, sends HCI_Intel_SW_RFKILL to put the
* device in the RFKILL ON state which turns off the BT LED immediately.
*/
if (btintel_test_flag(hdev, INTEL_BROKEN_LED)) {
if (btintel_test_flag(hdev, INTEL_BROKEN_SHUTDOWN_LED)) {
skb = __hci_cmd_sync(hdev, 0xfc3f, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
......
......@@ -150,7 +150,7 @@ enum {
INTEL_FIRMWARE_FAILED,
INTEL_BOOTING,
INTEL_BROKEN_INITIAL_NCMD,
INTEL_BROKEN_LED,
INTEL_BROKEN_SHUTDOWN_LED,
INTEL_ROM_LEGACY,
__INTEL_NUM_FLAGS,
......
......@@ -142,6 +142,50 @@ static int qca_read_fw_build_info(struct hci_dev *hdev)
return err;
}
static int qca_send_patch_config_cmd(struct hci_dev *hdev)
{
const u8 cmd[] = { EDL_PATCH_CONFIG_CMD, 0x01, 0, 0, 0 };
struct sk_buff *skb;
struct edl_event_hdr *edl;
int err;
bt_dev_dbg(hdev, "QCA Patch config");
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, sizeof(cmd),
cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Sending QCA Patch config failed (%d)", err);
return err;
}
if (skb->len != 2) {
bt_dev_err(hdev, "QCA Patch config cmd size mismatch len %d", skb->len);
err = -EILSEQ;
goto out;
}
edl = (struct edl_event_hdr *)(skb->data);
if (!edl) {
bt_dev_err(hdev, "QCA Patch config with no header");
err = -EILSEQ;
goto out;
}
if (edl->cresp != EDL_PATCH_CONFIG_RES_EVT || edl->rtype != EDL_PATCH_CONFIG_CMD) {
bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
edl->rtype);
err = -EIO;
goto out;
}
err = 0;
out:
kfree_skb(skb);
return err;
}
static int qca_send_reset(struct hci_dev *hdev)
{
struct sk_buff *skb;
......@@ -552,6 +596,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
*/
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
if (soc_type == QCA_WCN6750)
qca_send_patch_config_cmd(hdev);
/* Download rampatch file */
config.type = TLV_TYPE_PATCH;
if (qca_is_wcn399x(soc_type)) {
......
......@@ -13,6 +13,7 @@
#define EDL_PATCH_TLV_REQ_CMD (0x1E)
#define EDL_GET_BUILD_INFO_CMD (0x20)
#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01)
#define EDL_PATCH_CONFIG_CMD (0x28)
#define MAX_SIZE_PER_TLV_SEGMENT (243)
#define QCA_PRE_SHUTDOWN_CMD (0xFC08)
#define QCA_DISABLE_LOGGING (0xFC17)
......@@ -24,6 +25,7 @@
#define EDL_CMD_EXE_STATUS_EVT (0x00)
#define EDL_SET_BAUDRATE_RSP_EVT (0x92)
#define EDL_NVM_ACCESS_CODE_EVT (0x0B)
#define EDL_PATCH_CONFIG_RES_EVT (0x00)
#define QCA_DISABLE_LOGGING_SUB_OP (0x14)
#define EDL_TAG_ID_HCI (17)
......
......@@ -60,6 +60,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_WIDEBAND_SPEECH 0x400000
#define BTUSB_VALID_LE_STATES 0x800000
#define BTUSB_QCA_WCN6855 0x1000000
#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED 0x2000000
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD 0x4000000
static const struct usb_device_id btusb_table[] = {
......@@ -311,6 +312,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
......@@ -381,10 +385,13 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
BTUSB_INTEL_BROKEN_INITIAL_NCMD },
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED },
BTUSB_INTEL_BROKEN_INITIAL_NCMD |
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED |
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED |
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
{ USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_COMBINED },
/* Other Intel Bluetooth devices */
......@@ -3732,6 +3739,9 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INTEL_BROKEN_INITIAL_NCMD)
btintel_set_flag(hdev, INTEL_BROKEN_INITIAL_NCMD);
if (id->driver_info & BTUSB_INTEL_BROKEN_SHUTDOWN_LED)
btintel_set_flag(hdev, INTEL_BROKEN_SHUTDOWN_LED);
}
if (id->driver_info & BTUSB_MARVELL)
......
......@@ -1188,7 +1188,12 @@ static int bcm_probe(struct platform_device *pdev)
return -ENOMEM;
dev->dev = &pdev->dev;
dev->irq = platform_get_irq(pdev, 0);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
dev->irq = ret;
/* Initialize routing field to an unused value */
dev->pcm_int_params[0] = 0xff;
......
......@@ -2059,14 +2059,14 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (!qcadev->bt_en && data->soc_type == QCA_WCN6750) {
if (IS_ERR_OR_NULL(qcadev->bt_en) && data->soc_type == QCA_WCN6750) {
dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
power_ctrl_enabled = false;
}
qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
GPIOD_IN);
if (!qcadev->sw_ctrl && data->soc_type == QCA_WCN6750)
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && data->soc_type == QCA_WCN6750)
dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
......@@ -2088,7 +2088,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (!qcadev->bt_en) {
if (IS_ERR_OR_NULL(qcadev->bt_en)) {
dev_warn(&serdev->dev, "failed to acquire enable gpio\n");
power_ctrl_enabled = false;
}
......
......@@ -2233,11 +2233,7 @@ struct inquiry_info_rssi_pscan {
} __packed;
struct hci_ev_inquiry_result_rssi {
__u8 num;
struct inquiry_info_rssi info[];
} __packed;
struct hci_ev_inquiry_result_rssi_pscan {
__u8 num;
struct inquiry_info_rssi_pscan info[];
__u8 data[];
} __packed;
#define HCI_EV_REMOTE_EXT_FEATURES 0x23
......
......@@ -4507,16 +4507,13 @@ static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, void *data,
static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata,
struct sk_buff *skb)
{
union {
struct hci_ev_inquiry_result_rssi *res1;
struct hci_ev_inquiry_result_rssi_pscan *res2;
} *ev = edata;
struct hci_ev_inquiry_result_rssi *ev = edata;
struct inquiry_data data;
int i;
bt_dev_dbg(hdev, "num_rsp %d", ev->res1->num);
bt_dev_dbg(hdev, "num_rsp %d", ev->num);
if (!ev->res1->num)
if (!ev->num)
return;
if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
......@@ -4524,10 +4521,11 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata,
hci_dev_lock(hdev);
if (skb->len == flex_array_size(ev, res2->info, ev->res2->num)) {
if (skb->len == array_size(ev->num,
sizeof(struct inquiry_info_rssi_pscan))) {
struct inquiry_info_rssi_pscan *info;
for (i = 0; i < ev->res2->num; i++) {
for (i = 0; i < ev->num; i++) {
u32 flags;
info = hci_ev_skb_pull(hdev, skb,
......@@ -4554,10 +4552,11 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata,
info->dev_class, info->rssi,
flags, NULL, 0, NULL, 0);
}
} else if (skb->len == flex_array_size(ev, res1->info, ev->res1->num)) {
} else if (skb->len == array_size(ev->num,
sizeof(struct inquiry_info_rssi))) {
struct inquiry_info_rssi *info;
for (i = 0; i < ev->res1->num; i++) {
for (i = 0; i < ev->num; i++) {
u32 flags;
info = hci_ev_skb_pull(hdev, skb,
......
......@@ -1911,7 +1911,8 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
{
struct sock *sk = sock->sk;
int err = 0, opt = 0;
int err = 0;
u16 opt;
BT_DBG("sk %p, opt %d", sk, optname);
......@@ -1937,7 +1938,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
goto done;
}
if (copy_from_sockptr(&opt, optval, sizeof(u16))) {
if (copy_from_sockptr(&opt, optval, sizeof(opt))) {
err = -EFAULT;
break;
}
......
......@@ -904,6 +904,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
struct l2cap_conn *conn;
int len, err = 0;
u32 opt;
u16 mtu;
u8 mode;
BT_DBG("sk %p", sk);
......@@ -1086,16 +1088,16 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (copy_from_sockptr(&opt, optval, sizeof(u16))) {
if (copy_from_sockptr(&mtu, optval, sizeof(u16))) {
err = -EFAULT;
break;
}
if (chan->mode == L2CAP_MODE_EXT_FLOWCTL &&
sk->sk_state == BT_CONNECTED)
err = l2cap_chan_reconfigure(chan, opt);
err = l2cap_chan_reconfigure(chan, mtu);
else
chan->imtu = opt;
chan->imtu = mtu;
break;
......@@ -1117,14 +1119,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (copy_from_sockptr(&opt, optval, sizeof(u8))) {
if (copy_from_sockptr(&mode, optval, sizeof(u8))) {
err = -EFAULT;
break;
}
BT_DBG("opt %u", opt);
BT_DBG("mode %u", mode);
err = l2cap_set_mode(chan, opt);
err = l2cap_set_mode(chan, mode);
if (err)
break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment