summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/btmrvl.txt29
-rw-r--r--drivers/bluetooth/ath3k.c2
-rw-r--r--drivers/bluetooth/btmrvl_main.c51
-rw-r--r--drivers/bluetooth/btusb.c1
-rw-r--r--include/net/bluetooth/hci_core.h1
-rw-r--r--net/bluetooth/hci_core.c39
-rw-r--r--net/bluetooth/hci_event.c51
-rw-r--r--net/bluetooth/l2cap_core.c14
-rw-r--r--net/ieee802154/6lowpan_rtnl.c2
-rw-r--r--net/ieee802154/netlink.c2
-rw-r--r--net/ieee802154/nl-mac.c2
-rw-r--r--net/ieee802154/nl-phy.c2
-rw-r--r--net/mac802154/iface.c8
13 files changed, 143 insertions, 61 deletions
diff --git a/Documentation/devicetree/bindings/btmrvl.txt b/Documentation/devicetree/bindings/btmrvl.txt
new file mode 100644
index 0000000..58f964b
--- /dev/null
+++ b/Documentation/devicetree/bindings/btmrvl.txt
@@ -0,0 +1,29 @@
+btmrvl
+------
+
+Required properties:
+
+ - compatible : must be "btmrvl,cfgdata"
+
+Optional properties:
+
+ - btmrvl,cal-data : Calibration data downloaded to the device during
+ initialization. This is an array of 28 values(u8).
+
+ - btmrvl,gpio-gap : gpio and gap (in msecs) combination to be
+ configured.
+
+Example:
+
+GPIO pin 13 is configured as a wakeup source and GAP is set to 100 msecs
+in below example.
+
+btmrvl {
+ compatible = "btmrvl,cfgdata";
+
+ btmrvl,cal-data = /bits/ 8 <
+ 0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
+ 0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0xf0 0x00>;
+ btmrvl,gpio-gap = <0x0d64>;
+};
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 25c874d..fce7588 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -106,6 +106,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3375) },
{ USB_DEVICE(0x13d3, 0x3393) },
{ USB_DEVICE(0x13d3, 0x3402) },
+ { USB_DEVICE(0x13d3, 0x3408) },
{ USB_DEVICE(0x13d3, 0x3432) },
/* Atheros AR5BBU12 with sflash firmware */
@@ -158,6 +159,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 1d7db20..bb0d2c2 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -41,6 +41,11 @@ void btmrvl_interrupt(struct btmrvl_private *priv)
priv->adapter->int_count++;
+ if (priv->adapter->hs_state == HS_ACTIVATED) {
+ BT_DBG("BT: HS DEACTIVATED in ISR!\n");
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ }
+
wake_up_interruptible(&priv->main_thread.wait_q);
}
EXPORT_SYMBOL_GPL(btmrvl_interrupt);
@@ -323,6 +328,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv)
} else {
ret = priv->hw_wakeup_firmware(priv);
priv->adapter->hs_state = HS_DEACTIVATED;
+ BT_DBG("BT: HS DEACTIVATED due to host activity!\n");
}
}
@@ -492,29 +498,31 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv,
return 0;
}
-static int btmrvl_cal_data_dt(struct btmrvl_private *priv)
+static int btmrvl_check_device_tree(struct btmrvl_private *priv)
{
struct device_node *dt_node;
u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE];
- const char name[] = "btmrvl_caldata";
- const char property[] = "btmrvl,caldata";
int ret;
-
- dt_node = of_find_node_by_name(NULL, name);
- if (!dt_node)
- return -ENODEV;
-
- ret = of_property_read_u8_array(dt_node, property,
- cal_data + BT_CAL_HDR_LEN,
- BT_CAL_DATA_SIZE);
- if (ret)
- return ret;
-
- BT_DBG("Use cal data from device tree");
- ret = btmrvl_download_cal_data(priv, cal_data, BT_CAL_DATA_SIZE);
- if (ret) {
- BT_ERR("Fail to download calibrate data");
- return ret;
+ u32 val;
+
+ for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") {
+ ret = of_property_read_u32(dt_node, "btmrvl,gpio-gap", &val);
+ if (!ret)
+ priv->btmrvl_dev.gpio_gap = val;
+
+ ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data",
+ cal_data + BT_CAL_HDR_LEN,
+ BT_CAL_DATA_SIZE);
+ if (ret)
+ return ret;
+
+ BT_DBG("Use cal data from device tree");
+ ret = btmrvl_download_cal_data(priv, cal_data,
+ BT_CAL_DATA_SIZE);
+ if (ret) {
+ BT_ERR("Fail to download calibrate data");
+ return ret;
+ }
}
return 0;
@@ -526,14 +534,15 @@ static int btmrvl_setup(struct hci_dev *hdev)
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
- btmrvl_cal_data_dt(priv);
+ priv->btmrvl_dev.gpio_gap = 0xffff;
+
+ btmrvl_check_device_tree(priv);
btmrvl_pscan_window_reporting(priv, 0x01);
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
- priv->btmrvl_dev.gpio_gap = 0xffff;
btmrvl_send_hscfg_cmd(priv);
return 0;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7c13d7a..9efdace 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -185,6 +185,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a805b3d..396c098 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -130,6 +130,7 @@ struct smp_irk {
struct link_key {
struct list_head list;
+ struct rcu_head rcu;
bdaddr_t bdaddr;
u8 type;
u8 val[HCI_LINK_KEY_SIZE];
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d786958..5c319a4 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -274,15 +274,13 @@ static const struct file_operations inquiry_cache_fops = {
static int link_keys_show(struct seq_file *f, void *ptr)
{
struct hci_dev *hdev = f->private;
- struct list_head *p, *n;
+ struct link_key *key;
- hci_dev_lock(hdev);
- list_for_each_safe(p, n, &hdev->link_keys) {
- struct link_key *key = list_entry(p, struct link_key, list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(key, &hdev->link_keys, list)
seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type,
HCI_LINK_KEY_SIZE, key->val, key->pin_len);
- }
- hci_dev_unlock(hdev);
+ rcu_read_unlock();
return 0;
}
@@ -1128,6 +1126,7 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
err = hci_req_run(&req, hci_req_sync_complete);
if (err < 0) {
remove_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_RUNNING);
return ERR_PTR(err);
}
@@ -1196,6 +1195,7 @@ static int __hci_req_sync(struct hci_dev *hdev,
hdev->req_status = 0;
remove_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_RUNNING);
/* ENODATA means the HCI request command queue is empty.
* This can happen when a request with conditionals doesn't
@@ -3099,15 +3099,11 @@ void hci_uuids_clear(struct hci_dev *hdev)
void hci_link_keys_clear(struct hci_dev *hdev)
{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->link_keys) {
- struct link_key *key;
-
- key = list_entry(p, struct link_key, list);
+ struct link_key *key;
- list_del(p);
- kfree(key);
+ list_for_each_entry_rcu(key, &hdev->link_keys, list) {
+ list_del_rcu(&key->list);
+ kfree_rcu(key, rcu);
}
}
@@ -3135,9 +3131,14 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct link_key *k;
- list_for_each_entry(k, &hdev->link_keys, list)
- if (bacmp(bdaddr, &k->bdaddr) == 0)
+ rcu_read_lock();
+ list_for_each_entry_rcu(k, &hdev->link_keys, list) {
+ if (bacmp(bdaddr, &k->bdaddr) == 0) {
+ rcu_read_unlock();
return k;
+ }
+ }
+ rcu_read_unlock();
return NULL;
}
@@ -3288,7 +3289,7 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
key = kzalloc(sizeof(*key), GFP_KERNEL);
if (!key)
return NULL;
- list_add(&key->list, &hdev->link_keys);
+ list_add_rcu(&key->list, &hdev->link_keys);
}
BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
@@ -3381,8 +3382,8 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
BT_DBG("%s removing %pMR", hdev->name, bdaddr);
- list_del(&key->list);
- kfree(key);
+ list_del_rcu(&key->list);
+ kfree_rcu(key, rcu);
return 0;
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 844f7d1..bd0a801 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3191,6 +3191,38 @@ unlock:
hci_dev_unlock(hdev);
}
+static void conn_set_key(struct hci_conn *conn, u8 key_type, u8 pin_len)
+{
+ if (key_type == HCI_LK_CHANGED_COMBINATION)
+ return;
+
+ conn->pin_length = pin_len;
+ conn->key_type = key_type;
+
+ switch (key_type) {
+ case HCI_LK_LOCAL_UNIT:
+ case HCI_LK_REMOTE_UNIT:
+ case HCI_LK_DEBUG_COMBINATION:
+ return;
+ case HCI_LK_COMBINATION:
+ if (pin_len == 16)
+ conn->pending_sec_level = BT_SECURITY_HIGH;
+ else
+ conn->pending_sec_level = BT_SECURITY_MEDIUM;
+ break;
+ case HCI_LK_UNAUTH_COMBINATION_P192:
+ case HCI_LK_UNAUTH_COMBINATION_P256:
+ conn->pending_sec_level = BT_SECURITY_MEDIUM;
+ break;
+ case HCI_LK_AUTH_COMBINATION_P192:
+ conn->pending_sec_level = BT_SECURITY_HIGH;
+ break;
+ case HCI_LK_AUTH_COMBINATION_P256:
+ conn->pending_sec_level = BT_SECURITY_FIPS;
+ break;
+ }
+}
+
static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_link_key_req *ev = (void *) skb->data;
@@ -3232,8 +3264,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
goto not_found;
}
- conn->key_type = key->type;
- conn->pin_length = key->pin_len;
+ conn_set_key(conn, key->type, key->pin_len);
}
bacpy(&cp.bdaddr, &ev->bdaddr);
@@ -3266,12 +3297,8 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (conn) {
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- pin_len = conn->pin_length;
-
- if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
- conn->key_type = ev->key_type;
-
hci_conn_drop(conn);
+ conn_set_key(conn, ev->key_type, conn->pin_length);
}
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
@@ -3282,6 +3309,12 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (!key)
goto unlock;
+ /* Update connection information since adding the key will have
+ * fixed up the type in the case of changed combination keys.
+ */
+ if (ev->key_type == HCI_LK_CHANGED_COMBINATION)
+ conn_set_key(conn, key->type, key->pin_len);
+
mgmt_new_link_key(hdev, key, persistent);
/* Keep debug keys around only if the HCI_KEEP_DEBUG_KEYS flag
@@ -3291,8 +3324,8 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
*/
if (key->type == HCI_LK_DEBUG_COMBINATION &&
!test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) {
- list_del(&key->list);
- kfree(key);
+ list_del_rcu(&key->list);
+ kfree_rcu(key, rcu);
} else if (conn) {
if (persistent)
clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 8e12731..c2d1489 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -840,7 +840,10 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
if (!skb)
return;
- if (lmp_no_flush_capable(conn->hcon->hdev))
+ /* Use NO_FLUSH if supported or we have an LE link (which does
+ * not support auto-flushing packets) */
+ if (lmp_no_flush_capable(conn->hcon->hdev) ||
+ conn->hcon->type == LE_LINK)
flags = ACL_START_NO_FLUSH;
else
flags = ACL_START;
@@ -874,8 +877,13 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
return;
}
- if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
- lmp_no_flush_capable(hcon->hdev))
+ /* Use NO_FLUSH for LE links (where this is the only option) or
+ * if the BR/EDR link supports it and flushing has not been
+ * explicitly requested (through FLAG_FLUSHABLE).
+ */
+ if (hcon->type == LE_LINK ||
+ (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
+ lmp_no_flush_capable(hcon->hdev)))
flags = ACL_START_NO_FLUSH;
else
flags = ACL_START;
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index 290e14f..16f5e91 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -597,7 +597,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
entry->ldev = dev;
- /* Set the lowpan harware address to the wpan hardware address. */
+ /* Set the lowpan hardware address to the wpan hardware address. */
memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN);
mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 63ee7d6..6ad0da3 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -1,5 +1,5 @@
/*
- * Netlink inteface for IEEE 802.15.4 stack
+ * Netlink interface for IEEE 802.15.4 stack
*
* Copyright 2007, 2008 Siemens AG
*
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index fe77f0c..1f085ed 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -1,5 +1,5 @@
/*
- * Netlink inteface for IEEE 802.15.4 stack
+ * Netlink interface for IEEE 802.15.4 stack
*
* Copyright 2007, 2008 Siemens AG
*
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index 80a946d..6246354 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -1,5 +1,5 @@
/*
- * Netlink inteface for IEEE 802.15.4 stack
+ * Netlink interface for IEEE 802.15.4 stack
*
* Copyright 2007, 2008 Siemens AG
*
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
index 38dfc72..9ae8930 100644
--- a/net/mac802154/iface.c
+++ b/net/mac802154/iface.c
@@ -510,11 +510,9 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
if (ret)
goto err;
- if (ndev) {
- ret = register_netdevice(ndev);
- if (ret < 0)
- goto err;
- }
+ ret = register_netdevice(ndev);
+ if (ret < 0)
+ goto err;
mutex_lock(&local->iflist_mtx);
list_add_tail_rcu(&sdata->list, &local->interfaces);