Commit f730cc9f authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2017-10-19

Here's the first bluetooth-next pull request targeting the 4.15 kernel
release.

 - Multiple fixes & improvements to the hci_bcm driver
 - DT improvements, e.g. new local-bd-address property
 - Fixes & improvements to ECDH usage. Private key is now generated by
   the crypto subsystem.
 - gcc-4.9 warning fixes

Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 164a5e7a fac72b24
The following properties are common to the Bluetooth controllers:
- local-bd-address: array of 6 bytes, specifies the BD address that was
uniquely assigned to the Bluetooth device, formatted with least significant
byte first (little-endian).
...@@ -37,6 +37,11 @@ The following properties are defined to the bluetooth node: ...@@ -37,6 +37,11 @@ The following properties are defined to the bluetooth node:
Definition: must be: Definition: must be:
"qcom,wcnss-bt" "qcom,wcnss-bt"
- local-bd-address:
Usage: optional
Value type: <u8 array>
Definition: see Documentation/devicetree/bindings/net/bluetooth.txt
== WiFi == WiFi
The following properties are defined to the WiFi node: The following properties are defined to the WiFi node:
...@@ -91,6 +96,9 @@ smd { ...@@ -91,6 +96,9 @@ smd {
bt { bt {
compatible = "qcom,wcnss-bt"; compatible = "qcom,wcnss-bt";
/* BD address 00:11:22:33:44:55 */
local-bd-address = [ 55 44 33 22 11 00 ];
}; };
wlan { wlan {
......
...@@ -65,6 +65,7 @@ config BT_HCIBTSDIO ...@@ -65,6 +65,7 @@ config BT_HCIBTSDIO
config BT_HCIUART config BT_HCIUART
tristate "HCI UART driver" tristate "HCI UART driver"
depends on SERIAL_DEV_BUS || !SERIAL_DEV_BUS
depends on TTY depends on TTY
help help
Bluetooth HCI UART driver. Bluetooth HCI UART driver.
...@@ -79,7 +80,6 @@ config BT_HCIUART ...@@ -79,7 +80,6 @@ config BT_HCIUART
config BT_HCIUART_SERDEV config BT_HCIUART_SERDEV
bool bool
depends on SERIAL_DEV_BUS && BT_HCIUART depends on SERIAL_DEV_BUS && BT_HCIUART
depends on SERIAL_DEV_BUS=y || SERIAL_DEV_BUS=BT_HCIUART
default y default y
config BT_HCIUART_H4 config BT_HCIUART_H4
...@@ -169,6 +169,7 @@ config BT_HCIUART_BCM ...@@ -169,6 +169,7 @@ config BT_HCIUART_BCM
bool "Broadcom protocol support" bool "Broadcom protocol support"
depends on BT_HCIUART depends on BT_HCIUART
depends on BT_HCIUART_SERDEV depends on BT_HCIUART_SERDEV
depends on (!ACPI || SERIAL_DEV_CTRL_TTYPORT)
select BT_HCIUART_H4 select BT_HCIUART_H4
select BT_BCM select BT_BCM
help help
......
...@@ -121,7 +121,7 @@ static void bcm203x_complete(struct urb *urb) ...@@ -121,7 +121,7 @@ static void bcm203x_complete(struct urb *urb)
} }
data->state = BCM203X_LOAD_FIRMWARE; data->state = BCM203X_LOAD_FIRMWARE;
/* fall through */
case BCM203X_LOAD_FIRMWARE: case BCM203X_LOAD_FIRMWARE:
if (data->fw_sent == data->fw_size) { if (data->fw_sent == data->fw_size) {
usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
......
...@@ -156,9 +156,9 @@ static void bluecard_detach(struct pcmcia_device *p_dev); ...@@ -156,9 +156,9 @@ static void bluecard_detach(struct pcmcia_device *p_dev);
/* ======================== LED handling routines ======================== */ /* ======================== LED handling routines ======================== */
static void bluecard_activity_led_timeout(u_long arg) static void bluecard_activity_led_timeout(struct timer_list *t)
{ {
struct bluecard_info *info = (struct bluecard_info *)arg; struct bluecard_info *info = from_timer(info, t, timer);
unsigned int iobase = info->p_dev->resource[0]->start; unsigned int iobase = info->p_dev->resource[0]->start;
if (test_bit(CARD_ACTIVITY, &(info->hw_state))) { if (test_bit(CARD_ACTIVITY, &(info->hw_state))) {
...@@ -691,8 +691,7 @@ static int bluecard_open(struct bluecard_info *info) ...@@ -691,8 +691,7 @@ static int bluecard_open(struct bluecard_info *info)
spin_lock_init(&(info->lock)); spin_lock_init(&(info->lock));
setup_timer(&(info->timer), &bluecard_activity_led_timeout, timer_setup(&info->timer, bluecard_activity_led_timeout, 0);
(u_long)info);
skb_queue_head_init(&(info->txq)); skb_queue_head_init(&(info->txq));
......
...@@ -327,6 +327,8 @@ static const struct { ...@@ -327,6 +327,8 @@ static const struct {
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */ { 0x610c, "BCM4354" }, /* 003.001.012 */
{ 0x2209, "BCM43430A1" }, /* 001.002.009 */ { 0x2209, "BCM43430A1" }, /* 001.002.009 */
{ 0x6119, "BCM4345C0" }, /* 003.001.025 */
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
{ } { }
}; };
...@@ -361,6 +363,7 @@ int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len) ...@@ -361,6 +363,7 @@ int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
switch ((rev & 0xf000) >> 12) { switch ((rev & 0xf000) >> 12) {
case 0: case 0:
case 1: case 1:
case 2:
case 3: case 3:
for (i = 0; bcm_uart_subver_table[i].name; i++) { for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) { if (subver == bcm_uart_subver_table[i].subver) {
......
...@@ -64,7 +64,7 @@ static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv) ...@@ -64,7 +64,7 @@ static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
struct btmrvl_sdio_card *card = priv; struct btmrvl_sdio_card *card = priv;
struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg; struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
pr_info("%s: wake by bt", __func__); pr_info("%s: wake by bt\n", __func__);
cfg->wake_by_bt = true; cfg->wake_by_bt = true;
disable_irq_nosync(irq); disable_irq_nosync(irq);
...@@ -87,7 +87,7 @@ static int btmrvl_sdio_probe_of(struct device *dev, ...@@ -87,7 +87,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
if (!dev->of_node || if (!dev->of_node ||
!of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) { !of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
pr_err("sdio platform data not available"); pr_err("sdio platform data not available\n");
return -1; return -1;
} }
...@@ -99,7 +99,7 @@ static int btmrvl_sdio_probe_of(struct device *dev, ...@@ -99,7 +99,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
if (cfg && card->plt_of_node) { if (cfg && card->plt_of_node) {
cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0); cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0);
if (!cfg->irq_bt) { if (!cfg->irq_bt) {
dev_err(dev, "fail to parse irq_bt from device tree"); dev_err(dev, "fail to parse irq_bt from device tree\n");
cfg->irq_bt = -1; cfg->irq_bt = -1;
} else { } else {
ret = devm_request_irq(dev, cfg->irq_bt, ret = devm_request_irq(dev, cfg->irq_bt,
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rpmsg.h> #include <linux/rpmsg.h>
#include <linux/of.h>
#include <linux/soc/qcom/wcnss_ctrl.h> #include <linux/soc/qcom/wcnss_ctrl.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -26,6 +28,7 @@ ...@@ -26,6 +28,7 @@
struct btqcomsmd { struct btqcomsmd {
struct hci_dev *hdev; struct hci_dev *hdev;
bdaddr_t bdaddr;
struct rpmsg_endpoint *acl_channel; struct rpmsg_endpoint *acl_channel;
struct rpmsg_endpoint *cmd_channel; struct rpmsg_endpoint *cmd_channel;
}; };
...@@ -100,6 +103,38 @@ static int btqcomsmd_close(struct hci_dev *hdev) ...@@ -100,6 +103,38 @@ static int btqcomsmd_close(struct hci_dev *hdev)
return 0; return 0;
} }
static int btqcomsmd_setup(struct hci_dev *hdev)
{
struct btqcomsmd *btq = hci_get_drvdata(hdev);
struct sk_buff *skb;
int err;
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
/* Devices do not have persistent storage for BD address. If no
* BD address has been retrieved during probe, mark the device
* as having an invalid BD address.
*/
if (!bacmp(&btq->bdaddr, BDADDR_ANY)) {
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
return 0;
}
/* When setting a configured BD address fails, mark the device
* as having an invalid BD address.
*/
err = qca_set_bdaddr_rome(hdev, &btq->bdaddr);
if (err) {
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
return 0;
}
return 0;
}
static int btqcomsmd_probe(struct platform_device *pdev) static int btqcomsmd_probe(struct platform_device *pdev)
{ {
struct btqcomsmd *btq; struct btqcomsmd *btq;
...@@ -123,6 +158,15 @@ static int btqcomsmd_probe(struct platform_device *pdev) ...@@ -123,6 +158,15 @@ static int btqcomsmd_probe(struct platform_device *pdev)
if (IS_ERR(btq->cmd_channel)) if (IS_ERR(btq->cmd_channel))
return PTR_ERR(btq->cmd_channel); return PTR_ERR(btq->cmd_channel);
/* The local-bd-address property is usually injected by the
* bootloader which has access to the allocated BD address.
*/
if (!of_property_read_u8_array(pdev->dev.of_node, "local-bd-address",
(u8 *)&btq->bdaddr, sizeof(bdaddr_t))) {
dev_info(&pdev->dev, "BD address %pMR retrieved from device-tree",
&btq->bdaddr);
}
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) if (!hdev)
return -ENOMEM; return -ENOMEM;
...@@ -135,6 +179,7 @@ static int btqcomsmd_probe(struct platform_device *pdev) ...@@ -135,6 +179,7 @@ static int btqcomsmd_probe(struct platform_device *pdev)
hdev->open = btqcomsmd_open; hdev->open = btqcomsmd_open;
hdev->close = btqcomsmd_close; hdev->close = btqcomsmd_close;
hdev->send = btqcomsmd_send; hdev->send = btqcomsmd_send;
hdev->setup = btqcomsmd_setup;
hdev->set_bdaddr = qca_set_bdaddr_rome; hdev->set_bdaddr = qca_set_bdaddr_rome;
ret = hci_register_dev(hdev); ret = hci_register_dev(hdev);
......
...@@ -66,7 +66,6 @@ static struct usb_driver btusb_driver; ...@@ -66,7 +66,6 @@ static struct usb_driver btusb_driver;
#define BTUSB_BCM2045 0x40000 #define BTUSB_BCM2045 0x40000
#define BTUSB_IFNUM_2 0x80000 #define BTUSB_IFNUM_2 0x80000
#define BTUSB_CW6622 0x100000 #define BTUSB_CW6622 0x100000
#define BTUSB_BCM_NO_PRODID 0x200000
static const struct usb_device_id btusb_table[] = { static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */ /* Generic Bluetooth USB device */
...@@ -171,10 +170,6 @@ static const struct usb_device_id btusb_table[] = { ...@@ -171,10 +170,6 @@ static const struct usb_device_id btusb_table[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x0930, 0xff, 0x01, 0x01), { USB_VENDOR_AND_INTERFACE_INFO(0x0930, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM }, .driver_info = BTUSB_BCM_PATCHRAM },
/* Broadcom devices with missing product id */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0000, 0x0000, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM | BTUSB_BCM_NO_PRODID },
/* Intel Bluetooth USB Bootloader (RAM module) */ /* Intel Bluetooth USB Bootloader (RAM module) */
{ USB_DEVICE(0x8087, 0x0a5a), { USB_DEVICE(0x8087, 0x0a5a),
.driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },
...@@ -2909,19 +2904,6 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -2909,19 +2904,6 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info == BTUSB_IGNORE) if (id->driver_info == BTUSB_IGNORE)
return -ENODEV; return -ENODEV;
if (id->driver_info & BTUSB_BCM_NO_PRODID) {
struct usb_device *udev = interface_to_usbdev(intf);
/* For the broken Broadcom devices that show 0000:0000
* as USB vendor and product information, check that the
* manufacturer string identifies them as Broadcom based
* devices.
*/
if (!udev->manufacturer ||
strcmp(udev->manufacturer, "Broadcom Corp"))
return -ENODEV;
}
if (id->driver_info & BTUSB_ATH3012) { if (id->driver_info & BTUSB_ATH3012) {
struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = interface_to_usbdev(intf);
......
...@@ -52,11 +52,13 @@ ...@@ -52,11 +52,13 @@
#define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */ #define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */
/* platform device driver resources */ /* device driver resources */
struct bcm_device { struct bcm_device {
/* Must be the first member, hci_serdev.c expects this. */
struct hci_uart serdev_hu;
struct list_head list; struct list_head list;
struct platform_device *pdev; struct device *dev;
const char *name; const char *name;
struct gpio_desc *device_wakeup; struct gpio_desc *device_wakeup;
...@@ -68,7 +70,7 @@ struct bcm_device { ...@@ -68,7 +70,7 @@ struct bcm_device {
u32 init_speed; u32 init_speed;
u32 oper_speed; u32 oper_speed;
int irq; int irq;
u8 irq_polarity; bool irq_active_low;
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct hci_uart *hu; struct hci_uart *hu;
...@@ -76,11 +78,6 @@ struct bcm_device { ...@@ -76,11 +78,6 @@ struct bcm_device {
#endif #endif
}; };
/* serdev driver resources */
struct bcm_serdev {
struct hci_uart hu;
};
/* generic bcm uart resources */ /* generic bcm uart resources */
struct bcm_data { struct bcm_data {
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
...@@ -155,6 +152,12 @@ static bool bcm_device_exists(struct bcm_device *device) ...@@ -155,6 +152,12 @@ static bool bcm_device_exists(struct bcm_device *device)
{ {
struct list_head *p; struct list_head *p;
#ifdef CONFIG_PM
/* Devices using serdev always exist */
if (device && device->hu && device->hu->serdev)
return true;
#endif
list_for_each(p, &bcm_device_list) { list_for_each(p, &bcm_device_list) {
struct bcm_device *dev = list_entry(p, struct bcm_device, list); struct bcm_device *dev = list_entry(p, struct bcm_device, list);
...@@ -188,9 +191,9 @@ static irqreturn_t bcm_host_wake(int irq, void *data) ...@@ -188,9 +191,9 @@ static irqreturn_t bcm_host_wake(int irq, void *data)
bt_dev_dbg(bdev, "Host wake IRQ"); bt_dev_dbg(bdev, "Host wake IRQ");
pm_runtime_get(&bdev->pdev->dev); pm_runtime_get(bdev->dev);
pm_runtime_mark_last_busy(&bdev->pdev->dev); pm_runtime_mark_last_busy(bdev->dev);
pm_runtime_put_autosuspend(&bdev->pdev->dev); pm_runtime_put_autosuspend(bdev->dev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -200,7 +203,6 @@ static int bcm_request_irq(struct bcm_data *bcm) ...@@ -200,7 +203,6 @@ static int bcm_request_irq(struct bcm_data *bcm)
struct bcm_device *bdev = bcm->dev; struct bcm_device *bdev = bcm->dev;
int err; int err;
/* If this is not a platform device, do not enable PM functionalities */
mutex_lock(&bcm_device_lock); mutex_lock(&bcm_device_lock);
if (!bcm_device_exists(bdev)) { if (!bcm_device_exists(bdev)) {
err = -ENODEV; err = -ENODEV;
...@@ -212,18 +214,20 @@ static int bcm_request_irq(struct bcm_data *bcm) ...@@ -212,18 +214,20 @@ static int bcm_request_irq(struct bcm_data *bcm)
goto unlock; goto unlock;
} }
err = devm_request_irq(&bdev->pdev->dev, bdev->irq, bcm_host_wake, err = devm_request_irq(bdev->dev, bdev->irq, bcm_host_wake,
IRQF_TRIGGER_RISING, "host_wake", bdev); bdev->irq_active_low ? IRQF_TRIGGER_FALLING :
IRQF_TRIGGER_RISING,
"host_wake", bdev);
if (err) if (err)
goto unlock; goto unlock;
device_init_wakeup(&bdev->pdev->dev, true); device_init_wakeup(bdev->dev, true);
pm_runtime_set_autosuspend_delay(&bdev->pdev->dev, pm_runtime_set_autosuspend_delay(bdev->dev,
BCM_AUTOSUSPEND_DELAY); BCM_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&bdev->pdev->dev); pm_runtime_use_autosuspend(bdev->dev);
pm_runtime_set_active(&bdev->pdev->dev); pm_runtime_set_active(bdev->dev);
pm_runtime_enable(&bdev->pdev->dev); pm_runtime_enable(bdev->dev);
unlock: unlock:
mutex_unlock(&bcm_device_lock); mutex_unlock(&bcm_device_lock);
...@@ -253,7 +257,7 @@ static int bcm_setup_sleep(struct hci_uart *hu) ...@@ -253,7 +257,7 @@ static int bcm_setup_sleep(struct hci_uart *hu)
struct sk_buff *skb; struct sk_buff *skb;
struct bcm_set_sleep_mode sleep_params = default_sleep_params; struct bcm_set_sleep_mode sleep_params = default_sleep_params;
sleep_params.host_wake_active = !bcm->dev->irq_polarity; sleep_params.host_wake_active = !bcm->dev->irq_active_low;
skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_params), skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_params),
&sleep_params, HCI_INIT_TIMEOUT); &sleep_params, HCI_INIT_TIMEOUT);
...@@ -311,18 +315,17 @@ static int bcm_open(struct hci_uart *hu) ...@@ -311,18 +315,17 @@ static int bcm_open(struct hci_uart *hu)
hu->priv = bcm; hu->priv = bcm;
/* If this is a serdev defined device, then only use mutex_lock(&bcm_device_lock);
* serdev open primitive and skip the rest.
*/
if (hu->serdev) { if (hu->serdev) {
serdev_device_open(hu->serdev); serdev_device_open(hu->serdev);
bcm->dev = serdev_device_get_drvdata(hu->serdev);
goto out; goto out;
} }
if (!hu->tty->dev) if (!hu->tty->dev)
goto out; goto out;
mutex_lock(&bcm_device_lock);
list_for_each(p, &bcm_device_list) { list_for_each(p, &bcm_device_list) {
struct bcm_device *dev = list_entry(p, struct bcm_device, list); struct bcm_device *dev = list_entry(p, struct bcm_device, list);
...@@ -330,50 +333,56 @@ static int bcm_open(struct hci_uart *hu) ...@@ -330,50 +333,56 @@ static int bcm_open(struct hci_uart *hu)
* platform device (saved during device probe) and * platform device (saved during device probe) and
* parent of tty device used by hci_uart * parent of tty device used by hci_uart
*/ */
if (hu->tty->dev->parent == dev->pdev->dev.parent) { if (hu->tty->dev->parent == dev->dev->parent) {
bcm->dev = dev; bcm->dev = dev;
hu->init_speed = dev->init_speed;
hu->oper_speed = dev->oper_speed;
#ifdef CONFIG_PM #ifdef CONFIG_PM
dev->hu = hu; dev->hu = hu;
#endif #endif
bcm_gpio_set_power(bcm->dev, true);
break; break;
} }
} }
mutex_unlock(&bcm_device_lock);
out: out:
if (bcm->dev) {
hu->init_speed = bcm->dev->init_speed;
hu->oper_speed = bcm->dev->oper_speed;
bcm_gpio_set_power(bcm->dev, true);
}
mutex_unlock(&bcm_device_lock);
return 0; return 0;
} }
static int bcm_close(struct hci_uart *hu) static int bcm_close(struct hci_uart *hu)
{ {
struct bcm_data *bcm = hu->priv; struct bcm_data *bcm = hu->priv;
struct bcm_device *bdev = bcm->dev; struct bcm_device *bdev = NULL;
bt_dev_dbg(hu->hdev, "hu %p", hu); bt_dev_dbg(hu->hdev, "hu %p", hu);
/* If this is a serdev defined device, only use serdev
* close primitive and then continue as usual.
*/
if (hu->serdev)
serdev_device_close(hu->serdev);
/* Protect bcm->dev against removal of the device or driver */ /* Protect bcm->dev against removal of the device or driver */
mutex_lock(&bcm_device_lock); mutex_lock(&bcm_device_lock);
if (bcm_device_exists(bdev)) {
if (hu->serdev) {
serdev_device_close(hu->serdev);
bdev = serdev_device_get_drvdata(hu->serdev);
} else if (bcm_device_exists(bcm->dev)) {
bdev = bcm->dev;
#ifdef CONFIG_PM
bdev->hu = NULL;
#endif
}
if (bdev) {
bcm_gpio_set_power(bdev, false); bcm_gpio_set_power(bdev, false);
#ifdef CONFIG_PM #ifdef CONFIG_PM
pm_runtime_disable(&bdev->pdev->dev); pm_runtime_disable(bdev->dev);
pm_runtime_set_suspended(&bdev->pdev->dev); pm_runtime_set_suspended(bdev->dev);
if (device_can_wakeup(&bdev->pdev->dev)) { if (device_can_wakeup(bdev->dev)) {
devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev); devm_free_irq(bdev->dev, bdev->irq, bdev);
device_init_wakeup(&bdev->pdev->dev, false); device_init_wakeup(bdev->dev, false);
} }
bdev->hu = NULL;
#endif #endif
} }
mutex_unlock(&bcm_device_lock); mutex_unlock(&bcm_device_lock);
...@@ -504,9 +513,9 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count) ...@@ -504,9 +513,9 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
/* Delay auto-suspend when receiving completed packet */ /* Delay auto-suspend when receiving completed packet */
mutex_lock(&bcm_device_lock); mutex_lock(&bcm_device_lock);
if (bcm->dev && bcm_device_exists(bcm->dev)) { if (bcm->dev && bcm_device_exists(bcm->dev)) {
pm_runtime_get(&bcm->dev->pdev->dev); pm_runtime_get(bcm->dev->dev);
pm_runtime_mark_last_busy(&bcm->dev->pdev->dev); pm_runtime_mark_last_busy(bcm->dev->dev);
pm_runtime_put_autosuspend(&bcm->dev->pdev->dev); pm_runtime_put_autosuspend(bcm->dev->dev);
} }
mutex_unlock(&bcm_device_lock); mutex_unlock(&bcm_device_lock);
} }
...@@ -537,15 +546,15 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu) ...@@ -537,15 +546,15 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
if (bcm_device_exists(bcm->dev)) { if (bcm_device_exists(bcm->dev)) {
bdev = bcm->dev; bdev = bcm->dev;
pm_runtime_get_sync(&bdev->pdev->dev); pm_runtime_get_sync(bdev->dev);
/* Shall be resumed here */ /* Shall be resumed here */
} }
skb = skb_dequeue(&bcm->txq); skb = skb_dequeue(&bcm->txq);
if (bdev) { if (bdev) {
pm_runtime_mark_last_busy(&bdev->pdev->dev); pm_runtime_mark_last_busy(bdev->dev);
pm_runtime_put_autosuspend(&bdev->pdev->dev); pm_runtime_put_autosuspend(bdev->dev);
} }
mutex_unlock(&bcm_device_lock); mutex_unlock(&bcm_device_lock);
...@@ -556,7 +565,7 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu) ...@@ -556,7 +565,7 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int bcm_suspend_device(struct device *dev) static int bcm_suspend_device(struct device *dev)
{ {
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); struct bcm_device *bdev = dev_get_drvdata(dev);
bt_dev_dbg(bdev, ""); bt_dev_dbg(bdev, "");
...@@ -579,7 +588,7 @@ static int bcm_suspend_device(struct device *dev) ...@@ -579,7 +588,7 @@ static int bcm_suspend_device(struct device *dev)
static int bcm_resume_device(struct device *dev) static int bcm_resume_device(struct device *dev)
{ {
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); struct bcm_device *bdev = dev_get_drvdata(dev);
bt_dev_dbg(bdev, ""); bt_dev_dbg(bdev, "");
...@@ -601,16 +610,18 @@ static int bcm_resume_device(struct device *dev) ...@@ -601,16 +610,18 @@ static int bcm_resume_device(struct device *dev)
#endif #endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
/* Platform suspend callback */ /* suspend callback */
static int bcm_suspend(struct device *dev) static int bcm_suspend(struct device *dev)
{ {
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); struct bcm_device *bdev = dev_get_drvdata(dev);
int error; int error;
bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended); bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
/* bcm_suspend can be called at any time as long as platform device is /*
* bound, so it should use bcm_device_lock to protect access to hci_uart * When used with a device instantiated as platform_device, bcm_suspend
* can be called at any time as long as the platform device is bound,
* so it should use bcm_device_lock to protect access to hci_uart
* and device_wake-up GPIO. * and device_wake-up GPIO.
*/ */
mutex_lock(&bcm_device_lock); mutex_lock(&bcm_device_lock);
...@@ -621,7 +632,7 @@ static int bcm_suspend(struct device *dev) ...@@ -621,7 +632,7 @@ static int bcm_suspend(struct device *dev)
if (pm_runtime_active(dev)) if (pm_runtime_active(dev))
bcm_suspend_device(dev); bcm_suspend_device(dev);
if (device_may_wakeup(&bdev->pdev->dev)) { if (device_may_wakeup(dev)) {
error = enable_irq_wake(bdev->irq); error = enable_irq_wake(bdev->irq);
if (!error) if (!error)
bt_dev_dbg(bdev, "BCM irq: enabled"); bt_dev_dbg(bdev, "BCM irq: enabled");
...@@ -633,15 +644,17 @@ static int bcm_suspend(struct device *dev) ...@@ -633,15 +644,17 @@ static int bcm_suspend(struct device *dev)
return 0; return 0;
} }
/* Platform resume callback */ /* resume callback */
static int bcm_resume(struct device *dev) static int bcm_resume(struct device *dev)
{ {
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev)); struct bcm_device *bdev = dev_get_drvdata(dev);
bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended); bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);
/* bcm_resume can be called at any time as long as platform device is /*
* bound, so it should use bcm_device_lock to protect access to hci_uart * When used with a device instantiated as platform_device, bcm_resume
* can be called at any time as long as platform device is bound,
* so it should use bcm_device_lock to protect access to hci_uart
* and device_wake-up GPIO. * and device_wake-up GPIO.
*/ */
mutex_lock(&bcm_device_lock); mutex_lock(&bcm_device_lock);
...@@ -649,7 +662,7 @@ static int bcm_resume(struct device *dev) ...@@ -649,7 +662,7 @@ static int bcm_resume(struct device *dev)
if (!bdev->hu) if (!bdev->hu)
goto unlock; goto unlock;
if (device_may_wakeup(&bdev->pdev->dev)) { if (device_may_wakeup(dev)) {
disable_irq_wake(bdev->irq); disable_irq_wake(bdev->irq);
bt_dev_dbg(bdev, "BCM irq: disabled"); bt_dev_dbg(bdev, "BCM irq: disabled");
} }
...@@ -690,10 +703,8 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = { ...@@ -690,10 +703,8 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = {
}; };
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static u8 acpi_active_low = ACPI_ACTIVE_LOW;
/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */ /* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = {
{ {
.ident = "Asus T100TA", .ident = "Asus T100TA",
.matches = { .matches = {
...@@ -701,7 +712,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { ...@@ -701,7 +712,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
"ASUSTeK COMPUTER INC."), "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
}, },
.driver_data = &acpi_active_low,
}, },
{ {
.ident = "Asus T100CHI", .ident = "Asus T100CHI",
...@@ -710,7 +720,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { ...@@ -710,7 +720,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
"ASUSTeK COMPUTER INC."), "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"),
}, },
.driver_data = &acpi_active_low,
}, },
{ /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ { /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */
.ident = "Lenovo ThinkPad 8", .ident = "Lenovo ThinkPad 8",
...@@ -718,7 +727,13 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { ...@@ -718,7 +727,13 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
}, },
.driver_data = &acpi_active_low, },
{
.ident = "MINIX Z83-4",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"),
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
},
}, },
{ } { }
}; };
...@@ -733,13 +748,13 @@ static int bcm_resource(struct acpi_resource *ares, void *data) ...@@ -733,13 +748,13 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
switch (ares->type) { switch (ares->type) {
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
irq = &ares->data.extended_irq; irq = &ares->data.extended_irq;
dev->irq_polarity = irq->polarity; dev->irq_active_low = irq->polarity == ACPI_ACTIVE_LOW;
break; break;
case ACPI_RESOURCE_TYPE_GPIO: case ACPI_RESOURCE_TYPE_GPIO:
gpio = &ares->data.gpio; gpio = &ares->data.gpio;
if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
dev->irq_polarity = gpio->polarity; dev->irq_active_low = gpio->polarity == ACPI_ACTIVE_LOW;
break; break;
case ACPI_RESOURCE_TYPE_SERIAL_BUS: case ACPI_RESOURCE_TYPE_SERIAL_BUS:
...@@ -754,36 +769,32 @@ static int bcm_resource(struct acpi_resource *ares, void *data) ...@@ -754,36 +769,32 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
break; break;
} }
/* Always tell the ACPI core to skip this resource */ return 0;
return 1;
} }
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
static int bcm_platform_probe(struct bcm_device *dev) static int bcm_get_resources(struct bcm_device *dev)
{ {
struct platform_device *pdev = dev->pdev; dev->name = dev_name(dev->dev);
dev->name = dev_name(&pdev->dev);
dev->clk = devm_clk_get(&pdev->dev, NULL); dev->clk = devm_clk_get(dev->dev, NULL);
dev->device_wakeup = devm_gpiod_get_optional(&pdev->dev, dev->device_wakeup = devm_gpiod_get_optional(dev->dev,
"device-wakeup", "device-wakeup",
GPIOD_OUT_LOW); GPIOD_OUT_LOW);
if (IS_ERR(dev->device_wakeup)) if (IS_ERR(dev->device_wakeup))
return PTR_ERR(dev->device_wakeup); return PTR_ERR(dev->device_wakeup);
dev->shutdown = devm_gpiod_get_optional(&pdev->dev, "shutdown", dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown",
GPIOD_OUT_LOW); GPIOD_OUT_LOW);
if (IS_ERR(dev->shutdown)) if (IS_ERR(dev->shutdown))
return PTR_ERR(dev->shutdown); return PTR_ERR(dev->shutdown);
/* IRQ can be declared in ACPI table as Interrupt or GpioInt */ /* IRQ can be declared in ACPI table as Interrupt or GpioInt */
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq <= 0) { if (dev->irq <= 0) {
struct gpio_desc *gpio; struct gpio_desc *gpio;
gpio = devm_gpiod_get_optional(&pdev->dev, "host-wakeup", gpio = devm_gpiod_get_optional(dev->dev, "host-wakeup",
GPIOD_IN); GPIOD_IN);
if (IS_ERR(gpio)) if (IS_ERR(gpio))
return PTR_ERR(gpio); return PTR_ERR(gpio);
...@@ -791,54 +802,48 @@ static int bcm_platform_probe(struct bcm_device *dev) ...@@ -791,54 +802,48 @@ static int bcm_platform_probe(struct bcm_device *dev)
dev->irq = gpiod_to_irq(gpio); dev->irq = gpiod_to_irq(gpio);
} }
dev_info(&pdev->dev, "BCM irq: %d\n", dev->irq); dev_info(dev->dev, "BCM irq: %d\n", dev->irq);
/* Make sure at-least one of the GPIO is defined and that
* a name is specified for this instance
*/
if ((!dev->device_wakeup && !dev->shutdown) || !dev->name) {
dev_err(&pdev->dev, "invalid platform data\n");
return -EINVAL;
}
return 0; return 0;
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static int bcm_acpi_probe(struct bcm_device *dev) static int bcm_acpi_probe(struct bcm_device *dev)
{ {
struct platform_device *pdev = dev->pdev;
LIST_HEAD(resources); LIST_HEAD(resources);
const struct dmi_system_id *dmi_id; const struct dmi_system_id *dmi_id;
const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios; const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios;
const struct acpi_device_id *id; const struct acpi_device_id *id;
struct resource_entry *entry;
int ret; int ret;
/* Retrieve GPIO data */ /* Retrieve GPIO data */
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); id = acpi_match_device(dev->dev->driver->acpi_match_table, dev->dev);
if (id) if (id)
gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data; gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data;
ret = devm_acpi_dev_add_driver_gpios(&pdev->dev, gpio_mapping); ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping);
if (ret)
return ret;
ret = bcm_platform_probe(dev);
if (ret) if (ret)
return ret; return ret;
/* Retrieve UART ACPI info */ /* Retrieve UART ACPI info */
ret = acpi_dev_get_resources(ACPI_COMPANION(&dev->pdev->dev), ret = acpi_dev_get_resources(ACPI_COMPANION(dev->dev),
&resources, bcm_resource, dev); &resources, bcm_resource, dev);
if (ret < 0) if (ret < 0)
return ret; return ret;
resource_list_for_each_entry(entry, &resources) {
if (resource_type(entry->res) == IORESOURCE_IRQ) {
dev->irq = entry->res->start;
break;
}
}
acpi_dev_free_resource_list(&resources); acpi_dev_free_resource_list(&resources);
dmi_id = dmi_first_match(bcm_wrong_irq_dmi_table); dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table);
if (dmi_id) { if (dmi_id) {
bt_dev_warn(dev, "%s: Overwriting IRQ polarity to active low", dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low",
dmi_id->ident); dmi_id->ident);
dev->irq_polarity = *(u8 *)dmi_id->driver_data; dev->irq_active_low = true;
} }
return 0; return 0;
...@@ -850,6 +855,12 @@ static int bcm_acpi_probe(struct bcm_device *dev) ...@@ -850,6 +855,12 @@ static int bcm_acpi_probe(struct bcm_device *dev)
} }
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
static int bcm_of_probe(struct bcm_device *bdev)
{
device_property_read_u32(bdev->dev, "max-speed", &bdev->oper_speed);
return 0;
}
static int bcm_probe(struct platform_device *pdev) static int bcm_probe(struct platform_device *pdev)
{ {
struct bcm_device *dev; struct bcm_device *dev;
...@@ -859,12 +870,16 @@ static int bcm_probe(struct platform_device *pdev) ...@@ -859,12 +870,16 @@ static int bcm_probe(struct platform_device *pdev)
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
dev->pdev = pdev; dev->dev = &pdev->dev;
dev->irq = platform_get_irq(pdev, 0);
if (has_acpi_companion(&pdev->dev)) if (has_acpi_companion(&pdev->dev)) {
ret = bcm_acpi_probe(dev); ret = bcm_acpi_probe(dev);
else if (ret)
ret = bcm_platform_probe(dev); return ret;
}
ret = bcm_get_resources(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -926,14 +941,16 @@ static const struct acpi_device_id bcm_acpi_match[] = { ...@@ -926,14 +941,16 @@ static const struct acpi_device_id bcm_acpi_match[] = {
{ "BCM2E71", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E71", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
{ "BCM2E7B", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E7B", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
{ "BCM2E7C", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E7C", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
{ "BCM2E7E", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
{ "BCM2E95", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, { "BCM2E95", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
{ "BCM2E96", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, { "BCM2E96", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
{ "BCM2EA4", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match); MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
#endif #endif
/* Platform suspend and resume callbacks */ /* suspend and resume callbacks */
static const struct dev_pm_ops bcm_pm_ops = { static const struct dev_pm_ops bcm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume) SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume)
SET_RUNTIME_PM_OPS(bcm_suspend_device, bcm_resume_device, NULL) SET_RUNTIME_PM_OPS(bcm_suspend_device, bcm_resume_device, NULL)
...@@ -951,29 +968,41 @@ static struct platform_driver bcm_driver = { ...@@ -951,29 +968,41 @@ static struct platform_driver bcm_driver = {
static int bcm_serdev_probe(struct serdev_device *serdev) static int bcm_serdev_probe(struct serdev_device *serdev)
{ {
struct bcm_serdev *bcmdev; struct bcm_device *bcmdev;
u32 speed;
int err; int err;
bcmdev = devm_kzalloc(&serdev->dev, sizeof(*bcmdev), GFP_KERNEL); bcmdev = devm_kzalloc(&serdev->dev, sizeof(*bcmdev), GFP_KERNEL);
if (!bcmdev) if (!bcmdev)
return -ENOMEM; return -ENOMEM;
bcmdev->hu.serdev = serdev; bcmdev->dev = &serdev->dev;
#ifdef CONFIG_PM
bcmdev->hu = &bcmdev->serdev_hu;
#endif
bcmdev->serdev_hu.serdev = serdev;
serdev_device_set_drvdata(serdev, bcmdev); serdev_device_set_drvdata(serdev, bcmdev);
err = device_property_read_u32(&serdev->dev, "max-speed", &speed); if (has_acpi_companion(&serdev->dev))
if (!err) err = bcm_acpi_probe(bcmdev);
bcmdev->hu.oper_speed = speed; else
err = bcm_of_probe(bcmdev);
if (err)
return err;
err = bcm_get_resources(bcmdev);
if (err)
return err;
bcm_gpio_set_power(bcmdev, false);
return hci_uart_register_device(&bcmdev->hu, &bcm_proto); return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto);
} }
static void bcm_serdev_remove(struct serdev_device *serdev) static void bcm_serdev_remove(struct serdev_device *serdev)
{ {
struct bcm_serdev *bcmdev = serdev_device_get_drvdata(serdev); struct bcm_device *bcmdev = serdev_device_get_drvdata(serdev);
hci_uart_unregister_device(&bcmdev->hu); hci_uart_unregister_device(&bcmdev->serdev_hu);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -990,6 +1019,8 @@ static struct serdev_device_driver bcm_serdev_driver = { ...@@ -990,6 +1019,8 @@ static struct serdev_device_driver bcm_serdev_driver = {
.driver = { .driver = {
.name = "hci_uart_bcm", .name = "hci_uart_bcm",
.of_match_table = of_match_ptr(bcm_bluetooth_of_match), .of_match_table = of_match_ptr(bcm_bluetooth_of_match),
.acpi_match_table = ACPI_PTR(bcm_acpi_match),
.pm = &bcm_pm_ops,
}, },
}; };
......
...@@ -65,6 +65,7 @@ struct bcsp_struct { ...@@ -65,6 +65,7 @@ struct bcsp_struct {
u8 rxseq_txack; /* rxseq == txack. */ u8 rxseq_txack; /* rxseq == txack. */
u8 rxack; /* Last packet sent by us that the peer ack'ed */ u8 rxack; /* Last packet sent by us that the peer ack'ed */
struct timer_list tbcsp; struct timer_list tbcsp;
struct hci_uart *hu;
enum { enum {
BCSP_W4_PKT_DELIMITER, BCSP_W4_PKT_DELIMITER,
...@@ -697,10 +698,10 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) ...@@ -697,10 +698,10 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
} }
/* Arrange to retransmit all messages in the relq. */ /* Arrange to retransmit all messages in the relq. */
static void bcsp_timed_event(unsigned long arg) static void bcsp_timed_event(struct timer_list *t)
{ {
struct hci_uart *hu = (struct hci_uart *)arg; struct bcsp_struct *bcsp = from_timer(bcsp, t, tbcsp);
struct bcsp_struct *bcsp = hu->priv; struct hci_uart *hu = bcsp->hu;
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags; unsigned long flags;
...@@ -729,11 +730,12 @@ static int bcsp_open(struct hci_uart *hu) ...@@ -729,11 +730,12 @@ static int bcsp_open(struct hci_uart *hu)
return -ENOMEM; return -ENOMEM;
hu->priv = bcsp; hu->priv = bcsp;
bcsp->hu = hu;
skb_queue_head_init(&bcsp->unack); skb_queue_head_init(&bcsp->unack);
skb_queue_head_init(&bcsp->rel); skb_queue_head_init(&bcsp->rel);
skb_queue_head_init(&bcsp->unrel); skb_queue_head_init(&bcsp->unrel);
setup_timer(&bcsp->tbcsp, bcsp_timed_event, (u_long)hu); timer_setup(&bcsp->tbcsp, bcsp_timed_event, 0);
bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
......
...@@ -78,6 +78,7 @@ struct h5 { ...@@ -78,6 +78,7 @@ struct h5 {
int (*rx_func)(struct hci_uart *hu, u8 c); int (*rx_func)(struct hci_uart *hu, u8 c);
struct timer_list timer; /* Retransmission timer */ struct timer_list timer; /* Retransmission timer */
struct hci_uart *hu; /* Parent HCI UART */
u8 tx_seq; /* Next seq number to send */ u8 tx_seq; /* Next seq number to send */
u8 tx_ack; /* Next ack number to send */ u8 tx_ack; /* Next ack number to send */
...@@ -120,12 +121,12 @@ static u8 h5_cfg_field(struct h5 *h5) ...@@ -120,12 +121,12 @@ static u8 h5_cfg_field(struct h5 *h5)
return h5->tx_win & 0x07; return h5->tx_win & 0x07;
} }
static void h5_timed_event(unsigned long arg) static void h5_timed_event(struct timer_list *t)
{ {
const unsigned char sync_req[] = { 0x01, 0x7e }; const unsigned char sync_req[] = { 0x01, 0x7e };
unsigned char conf_req[3] = { 0x03, 0xfc }; unsigned char conf_req[3] = { 0x03, 0xfc };
struct hci_uart *hu = (struct hci_uart *)arg; struct h5 *h5 = from_timer(h5, t, timer);
struct h5 *h5 = hu->priv; struct hci_uart *hu = h5->hu;
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags; unsigned long flags;
...@@ -197,6 +198,7 @@ static int h5_open(struct hci_uart *hu) ...@@ -197,6 +198,7 @@ static int h5_open(struct hci_uart *hu)
return -ENOMEM; return -ENOMEM;
hu->priv = h5; hu->priv = h5;
h5->hu = hu;
skb_queue_head_init(&h5->unack); skb_queue_head_init(&h5->unack);
skb_queue_head_init(&h5->rel); skb_queue_head_init(&h5->rel);
...@@ -204,7 +206,7 @@ static int h5_open(struct hci_uart *hu) ...@@ -204,7 +206,7 @@ static int h5_open(struct hci_uart *hu)
h5_reset_rx(h5); h5_reset_rx(h5);
setup_timer(&h5->timer, h5_timed_event, (unsigned long)hu); timer_setup(&h5->timer, h5_timed_event, 0);
h5->tx_win = H5_TX_WIN_MAX; h5->tx_win = H5_TX_WIN_MAX;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/serdev.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
...@@ -298,6 +299,12 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) ...@@ -298,6 +299,12 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
unsigned int set = 0; unsigned int set = 0;
unsigned int clear = 0; unsigned int clear = 0;
if (hu->serdev) {
serdev_device_set_flow_control(hu->serdev, !enable);
serdev_device_set_rts(hu->serdev, !enable);
return;
}
if (enable) { if (enable) {
/* Disable hardware flow control */ /* Disable hardware flow control */
ktermios = tty->termios; ktermios = tty->termios;
......
...@@ -242,7 +242,7 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu) ...@@ -242,7 +242,7 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu)
* perfectly safe to always send one. * perfectly safe to always send one.
*/ */
BT_DBG("dual wake-up-indication"); BT_DBG("dual wake-up-indication");
/* deliberate fall-through - do not add break */ /* fall through */
case HCILL_ASLEEP: case HCILL_ASLEEP:
/* acknowledge device wake up */ /* acknowledge device wake up */
if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) { if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
......
...@@ -307,10 +307,10 @@ static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work) ...@@ -307,10 +307,10 @@ static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work)
serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu); serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
} }
static void hci_ibs_tx_idle_timeout(unsigned long arg) static void hci_ibs_tx_idle_timeout(struct timer_list *t)
{ {
struct hci_uart *hu = (struct hci_uart *)arg; struct qca_data *qca = from_timer(qca, t, tx_idle_timer);
struct qca_data *qca = hu->priv; struct hci_uart *hu = qca->hu;
unsigned long flags; unsigned long flags;
BT_DBG("hu %p idle timeout in %d state", hu, qca->tx_ibs_state); BT_DBG("hu %p idle timeout in %d state", hu, qca->tx_ibs_state);
...@@ -342,10 +342,10 @@ static void hci_ibs_tx_idle_timeout(unsigned long arg) ...@@ -342,10 +342,10 @@ static void hci_ibs_tx_idle_timeout(unsigned long arg)
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
} }
static void hci_ibs_wake_retrans_timeout(unsigned long arg) static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
{ {
struct hci_uart *hu = (struct hci_uart *)arg; struct qca_data *qca = from_timer(qca, t, wake_retrans_timer);
struct qca_data *qca = hu->priv; struct hci_uart *hu = qca->hu;
unsigned long flags, retrans_delay; unsigned long flags, retrans_delay;
bool retransmit = false; bool retransmit = false;
...@@ -438,11 +438,10 @@ static int qca_open(struct hci_uart *hu) ...@@ -438,11 +438,10 @@ static int qca_open(struct hci_uart *hu)
hu->priv = qca; hu->priv = qca;
setup_timer(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
(u_long)hu);
qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS; qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
setup_timer(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, (u_long)hu); timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS; qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u", BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
......
...@@ -1944,7 +1944,7 @@ static int ca8210_skb_tx( ...@@ -1944,7 +1944,7 @@ static int ca8210_skb_tx(
) )
{ {
int status; int status;
struct ieee802154_hdr header = { 0 }; struct ieee802154_hdr header = { };
struct secspec secspec; struct secspec secspec;
unsigned int mac_len; unsigned int mac_len;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "ecdh_helper.h" #include "ecdh_helper.h"
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <crypto/kpp.h>
#include <crypto/ecdh.h> #include <crypto/ecdh.h>
struct ecdh_completion { struct ecdh_completion {
...@@ -50,55 +49,35 @@ static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits) ...@@ -50,55 +49,35 @@ static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
out[i] = __swab64(in[ndigits - 1 - i]); out[i] = __swab64(in[ndigits - 1 - i]);
} }
bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32], /* compute_ecdh_secret() - function assumes that the private key was
u8 secret[32]) * already set.
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @public_key: pair's ecc public key.
* secret: memory where the ecdh computed shared secret will be saved.
*
* Return: zero on success; error code in case of error.
*/
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
u8 secret[32])
{ {
struct crypto_kpp *tfm;
struct kpp_request *req; struct kpp_request *req;
struct ecdh p; u8 *tmp;
struct ecdh_completion result; struct ecdh_completion result;
struct scatterlist src, dst; struct scatterlist src, dst;
u8 *tmp, *buf; int err;
unsigned int buf_len;
int err = -ENOMEM;
tmp = kmalloc(64, GFP_KERNEL); tmp = kmalloc(64, GFP_KERNEL);
if (!tmp) if (!tmp)
return false; return -ENOMEM;
tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0); req = kpp_request_alloc(tfm, GFP_KERNEL);
if (IS_ERR(tfm)) { if (!req) {
pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n", err = -ENOMEM;
PTR_ERR(tfm));
goto free_tmp; goto free_tmp;
} }
req = kpp_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto free_kpp;
init_completion(&result.completion); init_completion(&result.completion);
/* Security Manager Protocol holds digits in litte-endian order
* while ECC API expect big-endian data
*/
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
p.key = (char *)tmp;
p.key_size = 32;
/* Set curve_id */
p.curve_id = ECC_CURVE_NIST_P256;
buf_len = crypto_ecdh_key_len(&p);
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf)
goto free_req;
crypto_ecdh_encode_key(buf, buf_len, &p);
/* Set A private Key */
err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len);
if (err)
goto free_all;
swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */ swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */ swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
...@@ -123,104 +102,129 @@ bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32], ...@@ -123,104 +102,129 @@ bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
memcpy(secret, tmp, 32); memcpy(secret, tmp, 32);
free_all: free_all:
kzfree(buf);
free_req:
kpp_request_free(req); kpp_request_free(req);
free_kpp:
crypto_free_kpp(tfm);
free_tmp: free_tmp:
kfree(tmp); kzfree(tmp);
return (err == 0); return err;
} }
bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32]) /* set_ecdh_privkey() - set or generate ecc private key.
*
* Function generates an ecc private key in the crypto subsystem when receiving
* a NULL private key or sets the received key when not NULL.
*
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @private_key: user's ecc private key. When not NULL, the key is expected
* in little endian format.
*
* Return: zero on success; error code in case of error.
*/
int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32])
{
u8 *buf, *tmp = NULL;
unsigned int buf_len;
int err;
struct ecdh p = {0};
p.curve_id = ECC_CURVE_NIST_P256;
if (private_key) {
tmp = kmalloc(32, GFP_KERNEL);
if (!tmp)
return -ENOMEM;
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
p.key = tmp;
p.key_size = 32;
}
buf_len = crypto_ecdh_key_len(&p);
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto free_tmp;
}
err = crypto_ecdh_encode_key(buf, buf_len, &p);
if (err)
goto free_all;
err = crypto_kpp_set_secret(tfm, buf, buf_len);
/* fall through */
free_all:
kzfree(buf);
free_tmp:
kzfree(tmp);
return err;
}
/* generate_ecdh_public_key() - function assumes that the private key was
* already set.
*
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @public_key: memory where the computed ecc public key will be saved.
*
* Return: zero on success; error code in case of error.
*/
int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64])
{ {
struct crypto_kpp *tfm;
struct kpp_request *req; struct kpp_request *req;
struct ecdh p; u8 *tmp;
struct ecdh_completion result; struct ecdh_completion result;
struct scatterlist dst; struct scatterlist dst;
u8 *tmp, *buf; int err;
unsigned int buf_len;
int err = -ENOMEM;
const unsigned short max_tries = 16;
unsigned short tries = 0;
tmp = kmalloc(64, GFP_KERNEL); tmp = kmalloc(64, GFP_KERNEL);
if (!tmp) if (!tmp)
return false; return -ENOMEM;
tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0); req = kpp_request_alloc(tfm, GFP_KERNEL);
if (IS_ERR(tfm)) { if (!req) {
pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n", err = -ENOMEM;
PTR_ERR(tfm));
goto free_tmp; goto free_tmp;
} }
req = kpp_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto free_kpp;
init_completion(&result.completion); init_completion(&result.completion);
sg_init_one(&dst, tmp, 64);
kpp_request_set_input(req, NULL, 0);
kpp_request_set_output(req, &dst, 64);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecdh_complete, &result);
/* Set curve_id */ err = crypto_kpp_generate_public_key(req);
p.curve_id = ECC_CURVE_NIST_P256; if (err == -EINPROGRESS) {
p.key_size = 32; wait_for_completion(&result.completion);
buf_len = crypto_ecdh_key_len(&p); err = result.err;
buf = kmalloc(buf_len, GFP_KERNEL); }
if (!buf) if (err < 0)
goto free_req; goto free_all;
do { /* The public key is handed back in little endian as expected by
if (tries++ >= max_tries) * the Security Manager Protocol.
goto free_all;
/* Set private Key */
p.key = (char *)private_key;
crypto_ecdh_encode_key(buf, buf_len, &p);
err = crypto_kpp_set_secret(tfm, buf, buf_len);
if (err)
goto free_all;
sg_init_one(&dst, tmp, 64);
kpp_request_set_input(req, NULL, 0);
kpp_request_set_output(req, &dst, 64);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecdh_complete, &result);
err = crypto_kpp_generate_public_key(req);
if (err == -EINPROGRESS) {
wait_for_completion(&result.completion);
err = result.err;
}
/* Private key is not valid. Regenerate */
if (err == -EINVAL)
continue;
if (err < 0)
goto free_all;
else
break;
} while (true);
/* Keys are handed back in little endian as expected by Security
* Manager Protocol
*/ */
swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */ swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */ swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
memcpy(private_key, tmp, 32);
free_all: free_all:
kzfree(buf);
free_req:
kpp_request_free(req); kpp_request_free(req);
free_kpp:
crypto_free_kpp(tfm);
free_tmp: free_tmp:
kfree(tmp); kfree(tmp);
return (err == 0); return err;
}
/* generate_ecdh_keys() - generate ecc key pair.
*
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @public_key: memory where the computed ecc public key will be saved.
*
* Return: zero on success; error code in case of error.
*/
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64])
{
int err;
err = set_ecdh_privkey(tfm, NULL);
if (err)
return err;
return generate_ecdh_public_key(tfm, public_key);
} }
...@@ -20,8 +20,11 @@ ...@@ -20,8 +20,11 @@
* COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
* SOFTWARE IS DISCLAIMED. * SOFTWARE IS DISCLAIMED.
*/ */
#include <crypto/kpp.h>
#include <linux/types.h> #include <linux/types.h>
bool compute_ecdh_secret(const u8 pub_a[64], const u8 priv_b[32], int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pair_public_key[64],
u8 secret[32]); u8 secret[32]);
bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32]); int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 *private_key);
int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]);
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]);
...@@ -138,12 +138,12 @@ static const u8 dhkey_3[32] __initconst = { ...@@ -138,12 +138,12 @@ static const u8 dhkey_3[32] __initconst = {
0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70, 0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70,
}; };
static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32], static int __init test_ecdh_sample(struct crypto_kpp *tfm, const u8 priv_a[32],
const u8 pub_a[64], const u8 pub_b[64], const u8 priv_b[32], const u8 pub_a[64],
const u8 dhkey[32]) const u8 pub_b[64], const u8 dhkey[32])
{ {
u8 *tmp, *dhkey_a, *dhkey_b; u8 *tmp, *dhkey_a, *dhkey_b;
int ret = 0; int ret;
tmp = kmalloc(64, GFP_KERNEL); tmp = kmalloc(64, GFP_KERNEL);
if (!tmp) if (!tmp)
...@@ -152,17 +152,30 @@ static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32], ...@@ -152,17 +152,30 @@ static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32],
dhkey_a = &tmp[0]; dhkey_a = &tmp[0];
dhkey_b = &tmp[32]; dhkey_b = &tmp[32];
compute_ecdh_secret(pub_b, priv_a, dhkey_a); ret = set_ecdh_privkey(tfm, priv_a);
compute_ecdh_secret(pub_a, priv_b, dhkey_b); if (ret)
goto out;
ret = compute_ecdh_secret(tfm, pub_b, dhkey_a);
if (ret)
goto out;
if (memcmp(dhkey_a, dhkey, 32)) { if (memcmp(dhkey_a, dhkey, 32)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
ret = set_ecdh_privkey(tfm, priv_b);
if (ret)
goto out;
ret = compute_ecdh_secret(tfm, pub_a, dhkey_b);
if (ret)
goto out;
if (memcmp(dhkey_b, dhkey, 32)) if (memcmp(dhkey_b, dhkey, 32))
ret = -EINVAL; ret = -EINVAL;
/* fall through*/
out: out:
kfree(tmp); kfree(tmp);
return ret; return ret;
...@@ -185,30 +198,43 @@ static const struct file_operations test_ecdh_fops = { ...@@ -185,30 +198,43 @@ static const struct file_operations test_ecdh_fops = {
static int __init test_ecdh(void) static int __init test_ecdh(void)
{ {
struct crypto_kpp *tfm;
ktime_t calltime, delta, rettime; ktime_t calltime, delta, rettime;
unsigned long long duration; unsigned long long duration = 0;
int err; int err;
calltime = ktime_get(); calltime = ktime_get();
err = test_ecdh_sample(priv_a_1, priv_b_1, pub_a_1, pub_b_1, dhkey_1); tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm)) {
BT_ERR("Unable to create ECDH crypto context");
err = PTR_ERR(tfm);
goto done;
}
err = test_ecdh_sample(tfm, priv_a_1, priv_b_1, pub_a_1, pub_b_1,
dhkey_1);
if (err) { if (err) {
BT_ERR("ECDH sample 1 failed"); BT_ERR("ECDH sample 1 failed");
goto done; goto done;
} }
err = test_ecdh_sample(priv_a_2, priv_b_2, pub_a_2, pub_b_2, dhkey_2); err = test_ecdh_sample(tfm, priv_a_2, priv_b_2, pub_a_2, pub_b_2,
dhkey_2);
if (err) { if (err) {
BT_ERR("ECDH sample 2 failed"); BT_ERR("ECDH sample 2 failed");
goto done; goto done;
} }
err = test_ecdh_sample(priv_a_3, priv_a_3, pub_a_3, pub_a_3, dhkey_3); err = test_ecdh_sample(tfm, priv_a_3, priv_a_3, pub_a_3, pub_a_3,
dhkey_3);
if (err) { if (err) {
BT_ERR("ECDH sample 3 failed"); BT_ERR("ECDH sample 3 failed");
goto done; goto done;
} }
crypto_free_kpp(tfm);
rettime = ktime_get(); rettime = ktime_get();
delta = ktime_sub(rettime, calltime); delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10; duration = (unsigned long long) ktime_to_ns(delta) >> 10;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <crypto/algapi.h> #include <crypto/algapi.h>
#include <crypto/b128ops.h> #include <crypto/b128ops.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include <crypto/kpp.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
...@@ -83,7 +84,6 @@ enum { ...@@ -83,7 +84,6 @@ enum {
struct smp_dev { struct smp_dev {
/* Secure Connections OOB data */ /* Secure Connections OOB data */
u8 local_pk[64]; u8 local_pk[64];
u8 local_sk[32];
u8 local_rand[16]; u8 local_rand[16];
bool debug_key; bool debug_key;
...@@ -92,6 +92,7 @@ struct smp_dev { ...@@ -92,6 +92,7 @@ struct smp_dev {
struct crypto_cipher *tfm_aes; struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac; struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
}; };
struct smp_chan { struct smp_chan {
...@@ -124,13 +125,13 @@ struct smp_chan { ...@@ -124,13 +125,13 @@ struct smp_chan {
/* Secure Connections variables */ /* Secure Connections variables */
u8 local_pk[64]; u8 local_pk[64];
u8 local_sk[32];
u8 remote_pk[64]; u8 remote_pk[64];
u8 dhkey[32]; u8 dhkey[32];
u8 mackey[16]; u8 mackey[16];
struct crypto_cipher *tfm_aes; struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac; struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
}; };
/* These debug key values are defined in the SMP section of the core /* These debug key values are defined in the SMP section of the core
...@@ -565,22 +566,22 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]) ...@@ -565,22 +566,22 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) { if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) {
BT_DBG("Using debug keys"); BT_DBG("Using debug keys");
err = set_ecdh_privkey(smp->tfm_ecdh, debug_sk);
if (err)
return err;
memcpy(smp->local_pk, debug_pk, 64); memcpy(smp->local_pk, debug_pk, 64);
memcpy(smp->local_sk, debug_sk, 32);
smp->debug_key = true; smp->debug_key = true;
} else { } else {
while (true) { while (true) {
/* Seed private key with random number */ /* Generate key pair for Secure Connections */
get_random_bytes(smp->local_sk, 32); err = generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk);
if (err)
/* Generate local key pair for Secure Connections */ return err;
if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
return -EIO;
/* This is unlikely, but we need to check that /* This is unlikely, but we need to check that
* we didn't accidentially generate a debug key. * we didn't accidentially generate a debug key.
*/ */
if (crypto_memneq(smp->local_sk, debug_sk, 32)) if (crypto_memneq(smp->local_pk, debug_pk, 64))
break; break;
} }
smp->debug_key = false; smp->debug_key = false;
...@@ -588,7 +589,6 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]) ...@@ -588,7 +589,6 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
SMP_DBG("OOB Public Key X: %32phN", smp->local_pk); SMP_DBG("OOB Public Key X: %32phN", smp->local_pk);
SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32); SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32);
SMP_DBG("OOB Private Key: %32phN", smp->local_sk);
get_random_bytes(smp->local_rand, 16); get_random_bytes(smp->local_rand, 16);
...@@ -771,6 +771,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn) ...@@ -771,6 +771,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
crypto_free_cipher(smp->tfm_aes); crypto_free_cipher(smp->tfm_aes);
crypto_free_shash(smp->tfm_cmac); crypto_free_shash(smp->tfm_cmac);
crypto_free_kpp(smp->tfm_ecdh);
/* Ensure that we don't leave any debug key around if debug key /* Ensure that we don't leave any debug key around if debug key
* support hasn't been explicitly enabled. * support hasn't been explicitly enabled.
...@@ -1391,16 +1392,19 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) ...@@ -1391,16 +1392,19 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
smp->tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); smp->tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(smp->tfm_aes)) { if (IS_ERR(smp->tfm_aes)) {
BT_ERR("Unable to create AES crypto context"); BT_ERR("Unable to create AES crypto context");
kzfree(smp); goto zfree_smp;
return NULL;
} }
smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0); smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
if (IS_ERR(smp->tfm_cmac)) { if (IS_ERR(smp->tfm_cmac)) {
BT_ERR("Unable to create CMAC crypto context"); BT_ERR("Unable to create CMAC crypto context");
crypto_free_cipher(smp->tfm_aes); goto free_cipher;
kzfree(smp); }
return NULL;
smp->tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(smp->tfm_ecdh)) {
BT_ERR("Unable to create ECDH crypto context");
goto free_shash;
} }
smp->conn = conn; smp->conn = conn;
...@@ -1413,6 +1417,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) ...@@ -1413,6 +1417,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
hci_conn_hold(conn->hcon); hci_conn_hold(conn->hcon);
return smp; return smp;
free_shash:
crypto_free_shash(smp->tfm_cmac);
free_cipher:
crypto_free_cipher(smp->tfm_aes);
zfree_smp:
kzfree(smp);
return NULL;
} }
static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16]) static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
...@@ -1883,7 +1895,6 @@ static u8 sc_send_public_key(struct smp_chan *smp) ...@@ -1883,7 +1895,6 @@ static u8 sc_send_public_key(struct smp_chan *smp)
smp_dev = chan->data; smp_dev = chan->data;
memcpy(smp->local_pk, smp_dev->local_pk, 64); memcpy(smp->local_pk, smp_dev->local_pk, 64);
memcpy(smp->local_sk, smp_dev->local_sk, 32);
memcpy(smp->lr, smp_dev->local_rand, 16); memcpy(smp->lr, smp_dev->local_rand, 16);
if (smp_dev->debug_key) if (smp_dev->debug_key)
...@@ -1894,22 +1905,20 @@ static u8 sc_send_public_key(struct smp_chan *smp) ...@@ -1894,22 +1905,20 @@ static u8 sc_send_public_key(struct smp_chan *smp)
if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) { if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) {
BT_DBG("Using debug keys"); BT_DBG("Using debug keys");
if (set_ecdh_privkey(smp->tfm_ecdh, debug_sk))
return SMP_UNSPECIFIED;
memcpy(smp->local_pk, debug_pk, 64); memcpy(smp->local_pk, debug_pk, 64);
memcpy(smp->local_sk, debug_sk, 32);
set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags); set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
} else { } else {
while (true) { while (true) {
/* Seed private key with random number */ /* Generate key pair for Secure Connections */
get_random_bytes(smp->local_sk, 32); if (generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk))
/* Generate local key pair for Secure Connections */
if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
/* This is unlikely, but we need to check that /* This is unlikely, but we need to check that
* we didn't accidentially generate a debug key. * we didn't accidentially generate a debug key.
*/ */
if (crypto_memneq(smp->local_sk, debug_sk, 32)) if (crypto_memneq(smp->local_pk, debug_pk, 64))
break; break;
} }
} }
...@@ -1917,7 +1926,6 @@ static u8 sc_send_public_key(struct smp_chan *smp) ...@@ -1917,7 +1926,6 @@ static u8 sc_send_public_key(struct smp_chan *smp)
done: done:
SMP_DBG("Local Public Key X: %32phN", smp->local_pk); SMP_DBG("Local Public Key X: %32phN", smp->local_pk);
SMP_DBG("Local Public Key Y: %32phN", smp->local_pk + 32); SMP_DBG("Local Public Key Y: %32phN", smp->local_pk + 32);
SMP_DBG("Local Private Key: %32phN", smp->local_sk);
smp_send_cmd(smp->conn, SMP_CMD_PUBLIC_KEY, 64, smp->local_pk); smp_send_cmd(smp->conn, SMP_CMD_PUBLIC_KEY, 64, smp->local_pk);
...@@ -2645,6 +2653,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -2645,6 +2653,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
struct l2cap_chan *chan = conn->smp; struct l2cap_chan *chan = conn->smp;
struct smp_chan *smp = chan->data; struct smp_chan *smp = chan->data;
struct hci_dev *hdev = hcon->hdev; struct hci_dev *hdev = hcon->hdev;
struct crypto_kpp *tfm_ecdh;
struct smp_cmd_pairing_confirm cfm; struct smp_cmd_pairing_confirm cfm;
int err; int err;
...@@ -2677,7 +2686,18 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -2677,7 +2686,18 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk); SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk);
SMP_DBG("Remote Public Key Y: %32phN", smp->remote_pk + 32); SMP_DBG("Remote Public Key Y: %32phN", smp->remote_pk + 32);
if (!compute_ecdh_secret(smp->remote_pk, smp->local_sk, smp->dhkey)) /* Compute the shared secret on the same crypto tfm on which the private
* key was set/generated.
*/
if (test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags)) {
struct smp_dev *smp_dev = chan->data;
tfm_ecdh = smp_dev->tfm_ecdh;
} else {
tfm_ecdh = smp->tfm_ecdh;
}
if (compute_ecdh_secret(tfm_ecdh, smp->remote_pk, smp->dhkey))
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
SMP_DBG("DHKey %32phN", smp->dhkey); SMP_DBG("DHKey %32phN", smp->dhkey);
...@@ -3169,6 +3189,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) ...@@ -3169,6 +3189,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
struct smp_dev *smp; struct smp_dev *smp;
struct crypto_cipher *tfm_aes; struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac; struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
if (cid == L2CAP_CID_SMP_BREDR) { if (cid == L2CAP_CID_SMP_BREDR) {
smp = NULL; smp = NULL;
...@@ -3194,8 +3215,18 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) ...@@ -3194,8 +3215,18 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
return ERR_CAST(tfm_cmac); return ERR_CAST(tfm_cmac);
} }
tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm_ecdh)) {
BT_ERR("Unable to create ECDH crypto context");
crypto_free_shash(tfm_cmac);
crypto_free_cipher(tfm_aes);
kzfree(smp);
return ERR_CAST(tfm_ecdh);
}
smp->tfm_aes = tfm_aes; smp->tfm_aes = tfm_aes;
smp->tfm_cmac = tfm_cmac; smp->tfm_cmac = tfm_cmac;
smp->tfm_ecdh = tfm_ecdh;
smp->min_key_size = SMP_MIN_ENC_KEY_SIZE; smp->min_key_size = SMP_MIN_ENC_KEY_SIZE;
smp->max_key_size = SMP_MAX_ENC_KEY_SIZE; smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
...@@ -3205,6 +3236,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) ...@@ -3205,6 +3236,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
if (smp) { if (smp) {
crypto_free_cipher(smp->tfm_aes); crypto_free_cipher(smp->tfm_aes);
crypto_free_shash(smp->tfm_cmac); crypto_free_shash(smp->tfm_cmac);
crypto_free_kpp(smp->tfm_ecdh);
kzfree(smp); kzfree(smp);
} }
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -3252,6 +3284,7 @@ static void smp_del_chan(struct l2cap_chan *chan) ...@@ -3252,6 +3284,7 @@ static void smp_del_chan(struct l2cap_chan *chan)
chan->data = NULL; chan->data = NULL;
crypto_free_cipher(smp->tfm_aes); crypto_free_cipher(smp->tfm_aes);
crypto_free_shash(smp->tfm_cmac); crypto_free_shash(smp->tfm_cmac);
crypto_free_kpp(smp->tfm_ecdh);
kzfree(smp); kzfree(smp);
} }
...@@ -3490,25 +3523,18 @@ void smp_unregister(struct hci_dev *hdev) ...@@ -3490,25 +3523,18 @@ void smp_unregister(struct hci_dev *hdev)
#if IS_ENABLED(CONFIG_BT_SELFTEST_SMP) #if IS_ENABLED(CONFIG_BT_SELFTEST_SMP)
static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits) static int __init test_debug_key(struct crypto_kpp *tfm_ecdh)
{ {
int i; u8 pk[64];
int err;
for (i = 0; i < ndigits; i++)
out[i] = __swab64(in[ndigits - 1 - i]);
}
static int __init test_debug_key(void)
{
u8 pk[64], sk[32];
swap_digits((u64 *)debug_sk, (u64 *)sk, 4);
if (!generate_ecdh_keys(pk, sk)) err = set_ecdh_privkey(tfm_ecdh, debug_sk);
return -EINVAL; if (err)
return err;
if (crypto_memneq(sk, debug_sk, 32)) err = generate_ecdh_public_key(tfm_ecdh, pk);
return -EINVAL; if (err)
return err;
if (crypto_memneq(pk, debug_pk, 64)) if (crypto_memneq(pk, debug_pk, 64))
return -EINVAL; return -EINVAL;
...@@ -3763,7 +3789,8 @@ static const struct file_operations test_smp_fops = { ...@@ -3763,7 +3789,8 @@ static const struct file_operations test_smp_fops = {
}; };
static int __init run_selftests(struct crypto_cipher *tfm_aes, static int __init run_selftests(struct crypto_cipher *tfm_aes,
struct crypto_shash *tfm_cmac) struct crypto_shash *tfm_cmac,
struct crypto_kpp *tfm_ecdh)
{ {
ktime_t calltime, delta, rettime; ktime_t calltime, delta, rettime;
unsigned long long duration; unsigned long long duration;
...@@ -3771,7 +3798,7 @@ static int __init run_selftests(struct crypto_cipher *tfm_aes, ...@@ -3771,7 +3798,7 @@ static int __init run_selftests(struct crypto_cipher *tfm_aes,
calltime = ktime_get(); calltime = ktime_get();
err = test_debug_key(); err = test_debug_key(tfm_ecdh);
if (err) { if (err) {
BT_ERR("debug_key test failed"); BT_ERR("debug_key test failed");
goto done; goto done;
...@@ -3848,6 +3875,7 @@ int __init bt_selftest_smp(void) ...@@ -3848,6 +3875,7 @@ int __init bt_selftest_smp(void)
{ {
struct crypto_cipher *tfm_aes; struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac; struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
int err; int err;
tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
...@@ -3863,10 +3891,19 @@ int __init bt_selftest_smp(void) ...@@ -3863,10 +3891,19 @@ int __init bt_selftest_smp(void)
return PTR_ERR(tfm_cmac); return PTR_ERR(tfm_cmac);
} }
err = run_selftests(tfm_aes, tfm_cmac); tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm_ecdh)) {
BT_ERR("Unable to create ECDH crypto context");
crypto_free_shash(tfm_cmac);
crypto_free_cipher(tfm_aes);
return PTR_ERR(tfm_ecdh);
}
err = run_selftests(tfm_aes, tfm_cmac, tfm_ecdh);
crypto_free_shash(tfm_cmac); crypto_free_shash(tfm_cmac);
crypto_free_cipher(tfm_aes); crypto_free_cipher(tfm_aes);
crypto_free_kpp(tfm_ecdh);
return err; return err;
} }
......
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