From patchwork Wed Mar 4 01:06:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 197315 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 181DAC3F2C6 for ; Wed, 4 Mar 2020 01:07:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D30A82073B for ; Wed, 4 Mar 2020 01:07:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="MCQYn/yz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387564AbgCDBHT (ORCPT ); Tue, 3 Mar 2020 20:07:19 -0500 Received: from mail-pf1-f195.google.com ([209.85.210.195]:42590 "EHLO mail-pf1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387470AbgCDBHB (ORCPT ); Tue, 3 Mar 2020 20:07:01 -0500 Received: by mail-pf1-f195.google.com with SMTP id f5so49890pfk.9 for ; Tue, 03 Mar 2020 17:06:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5tQW6IIZTiEE/7w7rYSblz9K9YpAzfJmG3Peiq+HwDA=; b=MCQYn/yzbQrMb2XpoV29yJVfl32waAjnAgA+oSz2g3tayVCQ15PO7CCm+xgfx8V19y /caLRvZhmwRQMWp2ruKLZzbPNSDpbs2eBkwNOAHL8q6nYpHXtolWEw+JjJlV4gzC0fwJ csCVtEykMlRME9BK4RDDS5e2vCDDmf7xdREWc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5tQW6IIZTiEE/7w7rYSblz9K9YpAzfJmG3Peiq+HwDA=; b=JcKVUSqFMOaHLg3T/u2/aVnQEUjBWrb0Kvmo4te3W9aYiOK10G/VUfFWlGY3mJN9Kp E1FOGZq1glU8d6H0VfU1dfRpl2CaWuXfPE1xVONHJWk1cU2lTxTditSE7eWSkRvn4dR3 HLpqyJjEkVysislLj4BqJjfx6IzLrThUlvZ2uIn5YSZh0AicX0ngXxHV0lzlwFqsyd7t +ydC/D92WPERUpwk3CS1PVVJ7xO7jrnWk3mzTdd2HiZNhYupS+onLrmYjHpEynVzi1tB OP6tLxTqAk88KLSMxgd40NRylrzia7pcC0M0NC8SwwuzTkEqwWH58EUE2remQkTwn4bg gcWA== X-Gm-Message-State: ANhLgQ1tvWaD7FDb/9GOESw3UG0xDHUCtOjzXBwFSw9+9uG6hm7Y/497 GukxJmzUIbTMjUhDK/+BHFQ1RM/a+gY= X-Google-Smtp-Source: ADFU+vtijU31N/s/q98n18FnTrHBJKxxB192IFocLtPdCGUu2qEvqGyMpeGjae88mlBxGUgo5OsXKQ== X-Received: by 2002:a65:63d1:: with SMTP id n17mr200533pgv.298.1583284018765; Tue, 03 Mar 2020 17:06:58 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id w2sm17780889pfb.138.2020.03.03.17.06.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2020 17:06:58 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v4 1/5] Bluetooth: Add mgmt op set_wake_capable Date: Tue, 3 Mar 2020 17:06:46 -0800 Message-Id: <20200303170610.RFC.v4.1.I797e2f4cb824299043e771f3ab9cef86ee09f4db@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200304010650.259961-1-abhishekpandit@chromium.org> References: <20200304010650.259961-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org When the system is suspended, only some connected Bluetooth devices cause user input that should wake the system (mostly HID devices). Add a list to keep track of devices that can wake the system and add a management API to let userspace tell the kernel whether a device is wake capable or not. For LE devices, the wakeable property is added to the connection parameter and can only be modified after calling add_device. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v4: None Changes in v3: * Added wakeable property to le_conn_param * Use wakeable list for BR/EDR and wakeable property for LE Changes in v2: None include/net/bluetooth/hci_core.h | 2 ++ include/net/bluetooth/mgmt.h | 7 +++++ net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 51 ++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index dcc0dc6e2624..9d9ada5bc9d4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -394,6 +394,7 @@ struct hci_dev { struct list_head mgmt_pending; struct list_head blacklist; struct list_head whitelist; + struct list_head wakeable; struct list_head uuids; struct list_head link_keys; struct list_head long_term_keys; @@ -575,6 +576,7 @@ struct hci_conn_params { struct hci_conn *conn; bool explicit_connect; + bool wakeable; }; extern struct list_head hci_dev_list; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index f69f88e8e109..42ad5c44ad5a 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -672,6 +672,13 @@ struct mgmt_cp_set_blocked_keys { } __packed; #define MGMT_OP_SET_BLOCKED_KEYS_SIZE 2 +#define MGMT_OP_SET_WAKE_CAPABLE 0x0047 +#define MGMT_SET_WAKE_CAPABLE_SIZE 8 +struct mgmt_cp_set_wake_capable { + struct mgmt_addr_info addr; + u8 wake_capable; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4e6d61a95b20..b0b0308127a3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3299,6 +3299,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->mgmt_pending); INIT_LIST_HEAD(&hdev->blacklist); INIT_LIST_HEAD(&hdev->whitelist); + INIT_LIST_HEAD(&hdev->wakeable); INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1002c657768a..f6751ce0d561 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -107,6 +107,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_READ_EXT_INFO, MGMT_OP_SET_APPEARANCE, MGMT_OP_SET_BLOCKED_KEYS, + MGMT_OP_SET_WAKE_CAPABLE, }; static const u16 mgmt_events[] = { @@ -4667,6 +4668,48 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, return err; } +static int set_wake_capable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_set_wake_capable *cp = data; + struct hci_conn_params *params; + int err; + u8 status = MGMT_STATUS_FAILED; + u8 addr_type = cp->addr.type == BDADDR_BREDR ? + cp->addr.type : + le_addr_type(cp->addr.type); + + BT_DBG("Set wake capable %pMR (type 0x%x) = 0x%x\n", &cp->addr.bdaddr, + addr_type, cp->wake_capable); + + if (cp->addr.type == BDADDR_BREDR) { + if (cp->wake_capable) + err = hci_bdaddr_list_add(&hdev->wakeable, + &cp->addr.bdaddr, addr_type); + else + err = hci_bdaddr_list_del(&hdev->wakeable, + &cp->addr.bdaddr, addr_type); + + if (!err || err == -EEXIST || err == -ENOENT) + status = MGMT_STATUS_SUCCESS; + + goto done; + } + + /* Add wakeable param to le connection parameters */ + params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type); + if (params) { + params->wakeable = cp->wake_capable; + status = MGMT_STATUS_SUCCESS; + } + +done: + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_WAKE_CAPABLE, status, + cp, sizeof(*cp)); + + return err; +} + static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct mgmt_pending_cmd *cmd; @@ -5795,6 +5838,13 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, err = hci_bdaddr_list_del(&hdev->whitelist, &cp->addr.bdaddr, cp->addr.type); + + /* Don't check result since it either succeeds or device + * wasn't there (not wakeable or invalid params as + * covered by deleting from whitelist). + */ + hci_bdaddr_list_del(&hdev->wakeable, &cp->addr.bdaddr, + cp->addr.type); if (err) { err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, @@ -6994,6 +7044,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE }, { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE, HCI_MGMT_VAR_LEN }, + { set_wake_capable, MGMT_SET_WAKE_CAPABLE_SIZE }, }; void mgmt_index_added(struct hci_dev *hdev) From patchwork Wed Mar 4 01:06:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 197317 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EEDCBC3F2D7 for ; Wed, 4 Mar 2020 01:07:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A962720836 for ; Wed, 4 Mar 2020 01:07:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="IDePic5F" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387499AbgCDBHC (ORCPT ); Tue, 3 Mar 2020 20:07:02 -0500 Received: from mail-pf1-f193.google.com ([209.85.210.193]:40878 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387472AbgCDBHC (ORCPT ); Tue, 3 Mar 2020 20:07:02 -0500 Received: by mail-pf1-f193.google.com with SMTP id l184so53970pfl.7 for ; Tue, 03 Mar 2020 17:07:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=TZYWFU//6XNH8xsyUpNDXcXn9d8YA13QJI1iOPCaVt0=; b=IDePic5Fdv1oCM1SzBMqzHuuSY/jRF6eXC4mhJghJ0Cc21Dur9GGumcMnN1XhHF4yq oB0YTzsSAMGmUq7HQR4PTXgpTh5MGecPgzfKI1BShFslZPzS9ejb6+efp/oYZVU99wnm m6kklYBG0obDYKEhPDJivswi/HXrGGvVjDRmc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=TZYWFU//6XNH8xsyUpNDXcXn9d8YA13QJI1iOPCaVt0=; b=ttzLbDteET/te7HZC1pUFvix8gPMoZFTHJtR4NDd4l4Sn4W5Jbz5oi6+Yg8MXUJ92H xvKKDnzMhEE5QtoO+LbVAUU7wW27h4BoEy1DIv/Kl2qOm/JANj2XDmTgw52vZhXMDGYK nn16BHCHoFa/cReosmFUzQjgh5G3n0prKNmSuVSrzDzzKwAW+6Sd0JlG7H5/K9cDzQt/ ueAkgFKwIrBHYHrT9Me/WsNcBRRs8GozGibjA7e6ZQhWLAUlgDib1oe9l7CDQVNDxu4J iiKEZoGzl5nWGhHYXmxjSXh8M8hmnc2ZGwty8hEB85ER+Kbv3OZBx9PGEOjLeB/aF1v2 AUQA== X-Gm-Message-State: ANhLgQ0q4irNdGYhBl4gTsR+xTkSvDHMxrmLPrMOyE6aDotzW8/oalWx +BFvXt7+yxmnWIXGg9WCb48XNw== X-Google-Smtp-Source: ADFU+vu0dV8H0SNw4j6I8MP47IzIzhcKBHExbfdiLZ64l3HZesFd8DXtKcJna/3Akg9dBp98n05fKA== X-Received: by 2002:aa7:864e:: with SMTP id a14mr509193pfo.240.1583284019970; Tue, 03 Mar 2020 17:06:59 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id w2sm17780889pfb.138.2020.03.03.17.06.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2020 17:06:59 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v4 2/5] Bluetooth: Handle PM_SUSPEND_PREPARE and PM_POST_SUSPEND Date: Tue, 3 Mar 2020 17:06:47 -0800 Message-Id: <20200303170610.RFC.v4.2.I62f17edc39370044c75ad43a55a7382b4b8a5ceb@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200304010650.259961-1-abhishekpandit@chromium.org> References: <20200304010650.259961-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Register for PM_SUSPEND_PREPARE and PM_POST_SUSPEND to make sure the Bluetooth controller is prepared correctly for suspend/resume. Implement the registration, scheduling and task handling portions only in this patch. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v4: * Added check for mgmt_powering_down and hdev_is_powered in notifier Changes in v3: None Changes in v2: * Moved pm notifier registration into its own patch and moved params out of separate suspend_state include/net/bluetooth/hci_core.h | 23 +++++++++ net/bluetooth/hci_core.c | 86 ++++++++++++++++++++++++++++++++ net/bluetooth/hci_request.c | 19 +++++++ net/bluetooth/hci_request.h | 2 + 4 files changed, 130 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9d9ada5bc9d4..b82a89b88d1b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -88,6 +88,20 @@ struct discovery_state { unsigned long scan_duration; }; +#define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ + +enum suspend_tasks { + SUSPEND_POWERING_DOWN, + + SUSPEND_PREPARE_NOTIFIER, + __SUSPEND_NUM_TASKS +}; + +enum suspended_state { + BT_RUNNING = 0, + BT_SUSPENDED, +}; + struct hci_conn_hash { struct list_head list; unsigned int acl_num; @@ -389,6 +403,15 @@ struct hci_dev { void *smp_bredr_data; struct discovery_state discovery; + + struct notifier_block suspend_notifier; + struct work_struct suspend_prepare; + enum suspended_state suspend_state_next; + enum suspended_state suspend_state; + + wait_queue_head_t suspend_wait_q; + DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS); + struct hci_conn_hash conn_hash; struct list_head mgmt_pending; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b0b0308127a3..ad89ff3f8f57 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -1764,6 +1766,9 @@ int hci_dev_do_close(struct hci_dev *hdev) clear_bit(HCI_RUNNING, &hdev->flags); hci_sock_dev_event(hdev, HCI_DEV_CLOSE); + if (test_and_clear_bit(SUSPEND_POWERING_DOWN, hdev->suspend_tasks)) + wake_up(&hdev->suspend_wait_q); + /* After this point our queues are empty * and no tasks are scheduled. */ hdev->close(hdev); @@ -3241,6 +3246,78 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, } } +static int hci_suspend_wait_event(struct hci_dev *hdev) +{ +#define WAKE_COND \ + (find_first_bit(hdev->suspend_tasks, __SUSPEND_NUM_TASKS) == \ + __SUSPEND_NUM_TASKS) + + int i; + int ret = wait_event_timeout(hdev->suspend_wait_q, + WAKE_COND, SUSPEND_NOTIFIER_TIMEOUT); + + if (ret == 0) { + BT_DBG("Timed out waiting for suspend"); + for (i = 0; i < __SUSPEND_NUM_TASKS; ++i) { + if (test_bit(i, hdev->suspend_tasks)) + BT_DBG("Bit %d is set", i); + clear_bit(i, hdev->suspend_tasks); + } + + ret = -ETIMEDOUT; + } else { + ret = 0; + } + + return ret; +} + +static void hci_prepare_suspend(struct work_struct *work) +{ + struct hci_dev *hdev = + container_of(work, struct hci_dev, suspend_prepare); + + hci_dev_lock(hdev); + hci_req_prepare_suspend(hdev, hdev->suspend_state_next); + hci_dev_unlock(hdev); +} + +static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct hci_dev *hdev = + container_of(nb, struct hci_dev, suspend_notifier); + int ret = 0; + + /* If powering down, wait for completion. */ + if (mgmt_powering_down(hdev)) { + set_bit(SUSPEND_POWERING_DOWN, hdev->suspend_tasks); + ret = hci_suspend_wait_event(hdev); + if (ret) + goto done; + } + + /* Suspend notifier should only act on events when powered. */ + if (!hdev_is_powered(hdev)) + goto done; + + if (action == PM_SUSPEND_PREPARE) { + hdev->suspend_state_next = BT_SUSPENDED; + set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + queue_work(hdev->req_workqueue, &hdev->suspend_prepare); + + ret = hci_suspend_wait_event(hdev); + } else if (action == PM_POST_SUSPEND) { + hdev->suspend_state_next = BT_RUNNING; + set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + queue_work(hdev->req_workqueue, &hdev->suspend_prepare); + + ret = hci_suspend_wait_event(hdev); + } + +done: + return ret ? notifier_from_errno(-EBUSY) : NOTIFY_STOP; +} /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { @@ -3319,6 +3396,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_WORK(&hdev->tx_work, hci_tx_work); INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->error_reset, hci_error_reset); + INIT_WORK(&hdev->suspend_prepare, hci_prepare_suspend); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); @@ -3327,6 +3405,7 @@ struct hci_dev *hci_alloc_dev(void) skb_queue_head_init(&hdev->raw_q); init_waitqueue_head(&hdev->req_wait_q); + init_waitqueue_head(&hdev->suspend_wait_q); INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout); @@ -3438,6 +3517,11 @@ int hci_register_dev(struct hci_dev *hdev) hci_sock_dev_event(hdev, HCI_DEV_REG); hci_dev_hold(hdev); + hdev->suspend_notifier.notifier_call = hci_suspend_notifier; + error = register_pm_notifier(&hdev->suspend_notifier); + if (error) + goto err_wqueue; + queue_work(hdev->req_workqueue, &hdev->power_on); return id; @@ -3471,6 +3555,8 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_dev_do_close(hdev); + unregister_pm_notifier(&hdev->suspend_notifier); + if (!test_bit(HCI_INIT, &hdev->flags) && !hci_dev_test_flag(hdev, HCI_SETUP) && !hci_dev_test_flag(hdev, HCI_CONFIG)) { diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 2a1b64dbf76e..08908469c043 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -918,6 +918,25 @@ static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance) return adv_instance->scan_rsp_len; } +/* Call with hci_dev_lock */ +void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) +{ + int old_state; + struct hci_conn *conn; + struct hci_request req; + + if (next == hdev->suspend_state) { + BT_DBG("Same state before and after: %d", next); + goto done; + } + + hdev->suspend_state = next; + +done: + clear_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + wake_up(&hdev->suspend_wait_q); +} + static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev) { u8 instance = hdev->cur_adv_instance; diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index a7019fbeadd3..0e81614d235e 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -68,6 +68,8 @@ void __hci_req_update_eir(struct hci_request *req); void hci_req_add_le_scan_disable(struct hci_request *req); void hci_req_add_le_passive_scan(struct hci_request *req); +void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next); + void hci_req_reenable_advertising(struct hci_dev *hdev); void __hci_req_enable_advertising(struct hci_request *req); void __hci_req_disable_advertising(struct hci_request *req); From patchwork Wed Mar 4 01:06:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 197316 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC17BC3F2C6 for ; Wed, 4 Mar 2020 01:07:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7440B20728 for ; Wed, 4 Mar 2020 01:07:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="fuOzDyed" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387533AbgCDBHH (ORCPT ); Tue, 3 Mar 2020 20:07:07 -0500 Received: from mail-pg1-f195.google.com ([209.85.215.195]:43777 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387519AbgCDBHF (ORCPT ); Tue, 3 Mar 2020 20:07:05 -0500 Received: by mail-pg1-f195.google.com with SMTP id u12so142224pgb.10 for ; Tue, 03 Mar 2020 17:07:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=nD+wnBhhfQhuDyVD/p4juSDEz0XYbWsV3xmvIsrSGoU=; b=fuOzDyedOT41VselIwWAdvNYMWy9E/KizTuApFA/s5v7ACZ07hGKbeSmlg/ey40Kxs ZRpCYtouebwtC7xBQFquifnlBFOeX3wZJf8WNSEnrFCN0lJ9TqNA3cl7nIQfsxqjroO6 iAeVm39vTW4To8RSn7UED3s6Apz5RGOrg6N/Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=nD+wnBhhfQhuDyVD/p4juSDEz0XYbWsV3xmvIsrSGoU=; b=d0nm/NS0g+iHLIc0G1CwjOhNrrBZQ4Id4vzHfffVELZAjroapinKyzaySZeHc3otTX FrjnYZjbDonUMxVl8HM7sZuRtV9dKtaY9qnqokW626UagQs1BGKcpDQnjp7KF5H80gVm E9tGrqJnt4LRSwGu/Q5zqTsDhR0M5nRLop+rPBEabel1qcJakp/gWjb2DpmOxocWf0O9 /VjFH3dYkvA7cQDE85HDmckjVO50zk7WviRSYHAwMyBTXztjspD3TDMhE/ScWJrEQ8cT xQKfOpDTXOeZPG/6jZjydxy+2VKmFdIXczJgttZhgG4S5XvVidSR+W+G7qwEB0OTu56u HNAA== X-Gm-Message-State: ANhLgQ22zwx/KNA3tq0FzOVGnIxpicE2R0+iz6uDKs3zo3CYkC/MN9WD f3OukXmFi0YxlbvtuXWXUhS8Hg== X-Google-Smtp-Source: ADFU+vsiaY96ILHdMFTfDO71SnXViDlXug3o6LVMBkUChm8M7lLilDq660pblxYNL4fKFnPbFOzsgA== X-Received: by 2002:a63:8f17:: with SMTP id n23mr195471pgd.161.1583284024010; Tue, 03 Mar 2020 17:07:04 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id w2sm17780889pfb.138.2020.03.03.17.07.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2020 17:07:03 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v4 5/5] Bluetooth: Pause discovery and advertising during suspend Date: Tue, 3 Mar 2020 17:06:50 -0800 Message-Id: <20200303170610.RFC.v4.5.Iccdad520469ca3524a7e5966c5f88e5bca756e13@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200304010650.259961-1-abhishekpandit@chromium.org> References: <20200304010650.259961-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org To prevent spurious wake ups, we disable any discovery or advertising when we enter suspend and restore it when we exit suspend. While paused, we disable any management requests to modify discovery or advertising. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v4: None Changes in v3: None Changes in v2: * Refactored pause discovery + advertising into its own patch include/net/bluetooth/hci_core.h | 11 ++++++++ net/bluetooth/hci_request.c | 43 ++++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 41 ++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4eb5b2786048..af264a247636 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -91,6 +91,12 @@ struct discovery_state { #define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ enum suspend_tasks { + SUSPEND_PAUSE_DISCOVERY, + SUSPEND_UNPAUSE_DISCOVERY, + + SUSPEND_PAUSE_ADVERTISING, + SUSPEND_UNPAUSE_ADVERTISING, + SUSPEND_SCAN_DISABLE, SUSPEND_SCAN_ENABLE, SUSPEND_DISCONNECTING, @@ -409,6 +415,11 @@ struct hci_dev { struct discovery_state discovery; + int discovery_old_state; + bool discovery_paused; + int advertising_old_state; + bool advertising_paused; + struct notifier_block suspend_notifier; struct work_struct suspend_prepare; enum suspended_state suspend_state_next; diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 88fd95d70f89..e25cfb6fd9aa 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1036,6 +1036,28 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) /* Mark device as suspended */ hdev->suspended = true; + /* Pause discovery if not already stopped */ + old_state = hdev->discovery.state; + if (old_state != DISCOVERY_STOPPED) { + set_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks); + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + queue_work(hdev->req_workqueue, &hdev->discov_update); + } + + hdev->discovery_paused = true; + hdev->discovery_old_state = old_state; + + /* Stop advertising */ + old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING); + if (old_state) { + set_bit(SUSPEND_PAUSE_ADVERTISING, hdev->suspend_tasks); + cancel_delayed_work(&hdev->discov_off); + queue_delayed_work(hdev->req_workqueue, + &hdev->discov_off, 0); + } + + hdev->advertising_paused = true; + hdev->advertising_old_state = old_state; /* Disable page scan */ page_scan = SCAN_DISABLED; hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan); @@ -1081,6 +1103,27 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) hci_req_clear_event_filter(&req); /* Reset passive/background scanning to normal */ hci_req_config_le_suspend_scan(&req); + + /* Unpause advertising */ + hdev->advertising_paused = false; + if (hdev->advertising_old_state) { + set_bit(SUSPEND_UNPAUSE_ADVERTISING, + hdev->suspend_tasks); + hci_dev_set_flag(hdev, HCI_ADVERTISING); + queue_work(hdev->req_workqueue, + &hdev->discoverable_update); + hdev->advertising_old_state = 0; + } + + /* Unpause discovery */ + hdev->discovery_paused = false; + if (hdev->discovery_old_state != DISCOVERY_STOPPED && + hdev->discovery_old_state != DISCOVERY_STOPPING) { + set_bit(SUSPEND_UNPAUSE_DISCOVERY, hdev->suspend_tasks); + hci_discovery_set_state(hdev, DISCOVERY_STARTING); + queue_work(hdev->req_workqueue, &hdev->discov_update); + } + hci_req_run(&req, suspend_req_complete); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f6751ce0d561..28572579c06d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1387,6 +1387,12 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } + if (hdev->advertising_paused) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, + MGMT_STATUS_BUSY); + goto failed; + } + if (!hdev_is_powered(hdev)) { bool changed = false; @@ -3870,6 +3876,13 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status) } hci_dev_unlock(hdev); + + /* Handle suspend notifier */ + if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY, + hdev->suspend_tasks)) { + BT_DBG("Unpaused discovery"); + wake_up(&hdev->suspend_wait_q); + } } static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type, @@ -3931,6 +3944,13 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev, goto failed; } + /* Can't start discovery when it is paused */ + if (hdev->discovery_paused) { + err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY, + &cp->type, sizeof(cp->type)); + goto failed; + } + /* Clear the discovery filter first to free any previously * allocated memory for the UUID list. */ @@ -4098,6 +4118,12 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status) } hci_dev_unlock(hdev); + + /* Handle suspend notifier */ + if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) { + BT_DBG("Paused discovery"); + wake_up(&hdev->suspend_wait_q); + } } static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, @@ -4329,6 +4355,17 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status, if (match.sk) sock_put(match.sk); + /* Handle suspend notifier */ + if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING, + hdev->suspend_tasks)) { + BT_DBG("Paused advertising"); + wake_up(&hdev->suspend_wait_q); + } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING, + hdev->suspend_tasks)) { + BT_DBG("Unpaused advertising"); + wake_up(&hdev->suspend_wait_q); + } + /* If "Set Advertising" was just disabled and instance advertising was * set up earlier, then re-enable multi-instance advertising. */ @@ -4380,6 +4417,10 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING, MGMT_STATUS_INVALID_PARAMS); + if (hdev->advertising_paused) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING, + MGMT_STATUS_BUSY); + hci_dev_lock(hdev); val = !!cp->val;