From patchwork Tue Aug 9 15:35:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manish Mandlik X-Patchwork-Id: 596869 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84D3CC19F2D for ; Tue, 9 Aug 2022 15:36:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242888AbiHIPgB (ORCPT ); Tue, 9 Aug 2022 11:36:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40426 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233527AbiHIPfm (ORCPT ); Tue, 9 Aug 2022 11:35:42 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DDF2A25F6 for ; Tue, 9 Aug 2022 08:35:40 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31f3959ba41so103755737b3.2 for ; Tue, 09 Aug 2022 08:35:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:mime-version:message-id:date:from:to:cc; bh=9waxFKEckRsksR/CxnLtO8m90vPWn0K31uAAo7MYkNw=; b=QtfuSAE6stzliaPoJKxzJzaBikU713Hfx91gcTP2JzAGReZCY+d6FvciQFr5T7EcPU tENWbnTjdO+QBSjAZdWGcReGy5kgvh8UZz26/Bl1N+WUyA9kZgl6A51S6D8WqASaHPKb q6XARQyIhZGlYcNTSXLJD4DvaPQh74RVK9rv5PaA95BKemlPUTI7MEKh7efCsfZvxeNT 2p5Vzaaj+vce1ZTc/jtHDfwlMC/zakzGKSOR12ae8FdKvI4jSvBQD0TxFmKxnlTP6u89 Sb+QojnyTfAQunzgPFb8MBGv+0eqTSX19ejWXkw3JUAxQ/ubzf5Hk23cvoulwuVrymMz rGdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:mime-version:message-id:date:x-gm-message-state :from:to:cc; bh=9waxFKEckRsksR/CxnLtO8m90vPWn0K31uAAo7MYkNw=; b=Pfb++7321Drk/tWW2jxnyoDl/VemCPlXR15PS+rdC7wHhPDnJDbtgv6M3q+4x3vs7P ey6i/R+hGFBZtrQpY/EFeVu0YCoBBF2zuWaRgCtOb3tC3m0CPHEublPMf/kgJIfsWDEY QWMJ1gQrbZ19IqAG7c7zCYGNygC2Y3LottIgRNqli33YYUHjSpPjqQ8AiYikbiA6KFSu V99LdvatCjK/T+pHoSvjdwyAt/IqxLF9Gbfv/Dut8wIX5JRfOy4Ubt4RJwzn9/owWLgX DvUu0PlZiUvD24UMtxKvMoM/2FaBPx2m6N8lMDniJWyLZXUWaGEeJQu/G3671Nvuxncm e8kg== X-Gm-Message-State: ACgBeo2bg8VIomvWEBursLGDFKk7bkPpEghIB/i5s7F5NyAPnDWpNUMb i+9i0nSdwzqwPDhF29wM0UxkmhehIKU1/g== X-Google-Smtp-Source: AA6agR6CcpP+mKN5E/cFGHb+4J+Pm/JesWcckehq4kilzJQLP38zePk0Sw8neW18CYPxoUtN/s9IMsWXuB/qlg== X-Received: from mmandlik.mtv.corp.google.com ([2620:15c:202:201:91a6:8007:96f6:3fb3]) (user=mmandlik job=sendgmr) by 2002:a81:9245:0:b0:31f:4e3e:363d with SMTP id j66-20020a819245000000b0031f4e3e363dmr23716836ywg.119.1660059340189; Tue, 09 Aug 2022 08:35:40 -0700 (PDT) Date: Tue, 9 Aug 2022 08:35:23 -0700 Message-Id: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> Mime-Version: 1.0 X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v4 1/5] sysfs: Add attribute info for /sys/devices/.../coredump_disabled From: Manish Mandlik To: Arend van Spriel , marcel@holtmann.org, luiz.dentz@gmail.com Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Manish Mandlik , Abhishek Pandit-Subedi , linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org This patch adds the specification for /sys/devices/.../coredump_disabled attribute which allows the userspace to enable/disable devcoredump for a particular device and drivers can use it to enable/disable functionality accordingly. It is available when the CONFIG_DEV_COREDUMP is enabled and driver has implemented the .coredump() callback. Signed-off-by: Manish Mandlik Reviewed-by: Abhishek Pandit-Subedi --- Hi Arend, The existing /sys/class/devcoredump/disabled provides only a one-way disable functionality for devcoredump. It also disables the devcoredump for everyone who is using it. This and the next patch provides a way to selectively enable/disable the devcoredump by creating a /sys/devices/.../coredump_disabled sysfs entry. The userspace can write 0/1 to it to enable/disable devcoredump for that particular device and drivers can use it accordingly. It will only be available along with the /sys/devices/.../coredump sysfs entry when the CONFIG_DEV_COREDUMP is enabled and the driver has implemented the .coredump() callback. Please let me know what you think about this. Thanks, Manish. Changes in v4: - New patch in the series Documentation/ABI/testing/sysfs-devices-coredump | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-devices-coredump b/Documentation/ABI/testing/sysfs-devices-coredump index e459368533a4..4bcfc7dbad67 100644 --- a/Documentation/ABI/testing/sysfs-devices-coredump +++ b/Documentation/ABI/testing/sysfs-devices-coredump @@ -8,3 +8,17 @@ Description: file will trigger the .coredump() callback. Available when CONFIG_DEV_COREDUMP is enabled. + +What: /sys/devices/.../coredump_disabled +Date: July 2022 +Contact: Manish Mandlik +Description: + The /sys/devices/.../coredump_disabled attribute can be used by + drivers to selectively enable/disable devcoredump functionality + for a device. The userspace can write 0/1 to it to control + enabling/disabling of devcoredump for that particular device. + This attribute is present only when the device is bound to a + driver which implements the .coredump() callback. The attribute + is readable and writeable. + + Available when CONFIG_DEV_COREDUMP is enabled. From patchwork Tue Aug 9 15:35:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manish Mandlik X-Patchwork-Id: 596261 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D0813C19F2D for ; Tue, 9 Aug 2022 15:36:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239967AbiHIPgC (ORCPT ); Tue, 9 Aug 2022 11:36:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242751AbiHIPfq (ORCPT ); Tue, 9 Aug 2022 11:35:46 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A671C25F6 for ; Tue, 9 Aug 2022 08:35:43 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id f4-20020a056a00228400b0052fdbb301ddso221073pfe.15 for ; Tue, 09 Aug 2022 08:35:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc; bh=f7QNBZGNnK5yYhhuUlGnKKkabxvWElh1Ug+FZ9u2MZY=; b=a+U4jExmeiVGPDVS/VtZgtsM5CgcPE/IppJwGzKXGunG6gLctOgbV/HwHLJiW4LqOn SkduGFbSnHJrnM0+2DTSS8ITe+UcjruXx4Bf7cg3Or/nalbfUZWrjcLZd1K1j2mZN0qj s/W+N9qND8wus4pLak1UdI6s+hBykKIFt5+MAq24nd5cpca/trMgJrihO0Gt94saBY36 ZRck6GFsg/r6zzlpvVGmXBBlxDAVwjj4A7iEKZs5HihhcXkISZu+lTvgTzrRcu1HLZyv V7Wgr65qpvLexzl4CF9YKaczOcHVai9aNfI/agbYm9X+0KtrGKm1F4Y2MQsQSLWeeJuR X0PA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc; bh=f7QNBZGNnK5yYhhuUlGnKKkabxvWElh1Ug+FZ9u2MZY=; b=W9kmNMjr+f7XnO1ZS65Ic6URLUZAXz4hvJM37hBXyRKVCmPhjdVFW6fCAal/3bvz8o Unk60+iFSttFwzXFNdqkLM9oG5bd9m4Dyou1L1+ZSw1O0Ac5S062rxcN/pNmuVylcgVE lvyHEQf4FyHfrfNbeAkd2VZjZVZLM8F+dIyUBTVgaBA2RGtXUsvxcusBgjcSwv2m9N1G oAW47sfRwe7jGjyOmXYDLVA7U/IyvWAyTuO1T+8d9xJw+LnE4MVSTArze3tcTHLypkQF C1pS145z2T99kJ95GwL2rHYai6cjrwGL3rDBP3Jl6At0HrCyha+xvRysehZ2aTgkByZE tMvQ== X-Gm-Message-State: ACgBeo1QsulOAwdg2P/2uwwk2H9bOkq/1vR5iiPJG+psu9IgqYc2QF2E 5FTvzNlSJzfyayHXwUp+KthP82nx7zsVbw== X-Google-Smtp-Source: AA6agR7TfjwH/GCmWvBBxw6G0/8wn4UVwrMJS5YLYSlniLXnKBsOpoBoqFMv0wVWEh8/dxTI14GFq1UlYV7LKA== X-Received: from mmandlik.mtv.corp.google.com ([2620:15c:202:201:91a6:8007:96f6:3fb3]) (user=mmandlik job=sendgmr) by 2002:a17:90b:394:b0:1f5:90a1:acf0 with SMTP id ga20-20020a17090b039400b001f590a1acf0mr21065299pjb.40.1660059343098; Tue, 09 Aug 2022 08:35:43 -0700 (PDT) Date: Tue, 9 Aug 2022 08:35:24 -0700 In-Reply-To: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> Message-Id: <20220809083112.v4.2.Ief1110784c6c1c3ac0ee5677c2d28d785af8686d@changeid> Mime-Version: 1.0 References: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v4 2/5] devcoredump: Add per device sysfs entry to enable/disable coredump From: Manish Mandlik To: Arend van Spriel , marcel@holtmann.org, luiz.dentz@gmail.com Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Manish Mandlik , Abhishek Pandit-Subedi , Dan Williams , Greg Kroah-Hartman , Jason Gunthorpe , Johannes Berg , "Rafael J. Wysocki" , Thomas Gleixner , Won Chung , linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org The /sys/class/devcoredump/disabled provides only one-way disable functionality. Also, disabling devcoredump using it disables the devcoredump functionality for everyone who is using it. Provide a way to selectively enable/disable devcoredump for the device which is bound to a driver that implements the '.coredump()' callback. This adds the 'coredump_disabled' driver attribute. When the driver implements the '.coredump()' callback, 'coredump_disabled' file is added along with the 'coredump' file in the sysfs folder of the device upon driver binding. The file is removed when the driver is unbound. Drivers can use this attribute to enable/disable devcoredump and the userspace can write 0 or 1 to /sys/devices/.../coredump_disabled sysfs entry to control enabling/disabling of devcoredump for that device. Signed-off-by: Manish Mandlik Reviewed-by: Abhishek Pandit-Subedi --- Changes in v4: - New patch in the series drivers/base/dd.c | 43 +++++++++++++++++++++++++++++++++++--- drivers/base/devcoredump.c | 2 +- include/linux/device.h | 4 ++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 11b0fb6414d3..c76d1145c6d9 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -426,6 +426,31 @@ static ssize_t coredump_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_WO(coredump); +static ssize_t coredump_disabled_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, 3, "%d\n", dev->coredump_disabled); +} + +static ssize_t coredump_disabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + long coredump_disabled; + + if (!kstrtol(buf, 10, &coredump_disabled)) { + /* Consider any non-zero value as true */ + if (coredump_disabled) + dev->coredump_disabled = true; + else + dev->coredump_disabled = false; + } + + return count; +} +static DEVICE_ATTR_RW(coredump_disabled); + static int driver_sysfs_add(struct device *dev) { int ret; @@ -448,9 +473,19 @@ static int driver_sysfs_add(struct device *dev) return 0; ret = device_create_file(dev, &dev_attr_coredump); - if (!ret) - return 0; + if (ret) + goto rm_driver; + + ret = device_create_file(dev, &dev_attr_coredump_disabled); + if (ret) + goto rm_coredump; + return 0; + +rm_coredump: + device_remove_file(dev, &dev_attr_coredump); + +rm_driver: sysfs_remove_link(&dev->kobj, "driver"); rm_dev: @@ -466,8 +501,10 @@ static void driver_sysfs_remove(struct device *dev) struct device_driver *drv = dev->driver; if (drv) { - if (drv->coredump) + if (drv->coredump) { + device_remove_file(dev, &dev_attr_coredump_disabled); device_remove_file(dev, &dev_attr_coredump); + } sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); } diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index f4d794d6bb85..c5e9af9f3181 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -255,7 +255,7 @@ void dev_coredumpm(struct device *dev, struct module *owner, struct devcd_entry *devcd; struct device *existing; - if (devcd_disabled) + if (devcd_disabled || dev->coredump_disabled) goto free; existing = class_find_device(&devcd_class, NULL, dev, diff --git a/include/linux/device.h b/include/linux/device.h index dc941997795c..120dd656f99d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -469,6 +469,8 @@ struct device_physical_location { * This identifies the device type and carries type-specific * information. * @mutex: Mutex to synchronize calls to its driver. + * @coredump_disabled: Can be used by drivers to selectively enable/disable the + * coredump for a particular device via sysfs entry. * @bus: Type of bus device is on. * @driver: Which driver has allocated this * @platform_data: Platform data specific to the device. @@ -561,6 +563,8 @@ struct device { const char *init_name; /* initial name of the device */ const struct device_type *type; + bool coredump_disabled; + struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ From patchwork Tue Aug 9 15:35:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manish Mandlik X-Patchwork-Id: 596868 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CD3FC19F2D for ; Tue, 9 Aug 2022 15:36:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243527AbiHIPgE (ORCPT ); Tue, 9 Aug 2022 11:36:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243928AbiHIPft (ORCPT ); Tue, 9 Aug 2022 11:35:49 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A3F29F17 for ; Tue, 9 Aug 2022 08:35:46 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-31f46b4759bso103689157b3.0 for ; Tue, 09 Aug 2022 08:35:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc; bh=TN3S716BnQAzSsjmpSn9ET0FH+ip18lHG8/S00TeVQM=; b=XnIjF8XxzA1AOg0/Be7Kfwo+zWyRImdzm719BspdEx03qjIcaf5Rqp1OBRw7v6cbLy i7MF/9kUqDyRaZiv/UZ43iNxywogbOBcSZfEl/Nx4Jb29OVQdn63w/lfYzCpFNtLtPrS /zpqni8t2farAFZusGHWffIXBEw3Io5jwWbpz0fgawxdgkYr/Bnsq6uBfoyt1PaYOo4O i03TuEOy93/VJY83YetL99Jb3oDnuoJu8ir7b+SqJXXDy59ploc7iwYAJZJSsptIvuKe qx1pJfFgrZQe6ibHrSK5eWCOEYGsM+pZuSOdvXxbg4VP77M8WsnvKRV//HWcgxNz/R07 GgGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc; bh=TN3S716BnQAzSsjmpSn9ET0FH+ip18lHG8/S00TeVQM=; b=QjTytqHgFmT4rJQ2DKx1Lp+h0U6D05qqspMOasoKrQJFWj7T9B8mFSEocUyIsOasV2 vbtbQSYK60REXrDKNsAs4oFZfq+lt6w7LV4dAxgwOku/WZHgeAGtmu/HiS+3qKQXfMYg M4OAn2DnbwmR2Kics/2lXMqHLumWeGY32F8p1wVbhiDY7001fQN62gUgwAWeyNCvMOdX iRZRcL8mC8HijPRLlrhsXJffqHPAyGuttkx1rsiVYloshyBMx20I6mVkTf4lq2RSSZRc Kloz/T+T3NyCoLenMKnvZPqmIvbBpMxK5BW+NkQjF6SFFyrchWFit95TIYpSH3nfBpS1 M+0g== X-Gm-Message-State: ACgBeo0xbBPRoBUQG9UvfNYDRkLUpNnQehAXG7z1n8Yex8LJCGnT4dUj wF2VFyun5EFSaxV6REIsHxx0vde1s7Kamw== X-Google-Smtp-Source: AA6agR4QQeEwGQ6rYlOKcc63noZwxou6BE+wbUwFGHWYdqCvIDxedYtwjhqL8x1Aqg0+ho3sxpBXkTj6UbrgFw== X-Received: from mmandlik.mtv.corp.google.com ([2620:15c:202:201:91a6:8007:96f6:3fb3]) (user=mmandlik job=sendgmr) by 2002:a0d:d902:0:b0:328:98c8:9284 with SMTP id b2-20020a0dd902000000b0032898c89284mr26046783ywe.131.1660059345976; Tue, 09 Aug 2022 08:35:45 -0700 (PDT) Date: Tue, 9 Aug 2022 08:35:25 -0700 In-Reply-To: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> Message-Id: <20220809083112.v4.3.Iaf638bb9f885f5880ab1b4e7ae2f73dd53a54661@changeid> Mime-Version: 1.0 References: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v4 3/5] Bluetooth: Add support for hci devcoredump From: Manish Mandlik To: Arend van Spriel , marcel@holtmann.org, luiz.dentz@gmail.com Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Abhishek Pandit-Subedi , Manish Mandlik , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Johan Hedberg , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Abhishek Pandit-Subedi Add devcoredump APIs to hci core so that drivers only have to provide the dump skbs instead of managing the synchronization and timeouts. The devcoredump APIs should be used in the following manner: - hci_devcoredump_init is called to allocate the dump. - hci_devcoredump_append is called to append any skbs with dump data OR hci_devcoredump_append_pattern is called to insert a pattern. - hci_devcoredump_complete is called when all dump packets have been sent OR hci_devcoredump_abort is called to indicate an error and cancel an ongoing dump collection. The high level APIs just prepare some skbs with the appropriate data and queue it for the dump to process. Packets part of the crashdump can be intercepted in the driver in interrupt context and forwarded directly to the devcoredump APIs. Internally, there are 5 states for the dump: idle, active, complete, abort and timeout. A devcoredump will only be in active state after it has been initialized. Once active, it accepts data to be appended, patterns to be inserted (i.e. memset) and a completion event or an abort event to generate a devcoredump. The timeout is initialized at the same time the dump is initialized (defaulting to 10s) and will be cleared either when the timeout occurs or the dump is complete or aborted. Signed-off-by: Abhishek Pandit-Subedi Signed-off-by: Manish Mandlik Reviewed-by: Abhishek Pandit-Subedi --- Changes in v4: - Add .enabled() and .coredump() to hci_devcoredump struct Changes in v3: - Add attribute to enable/disable and set default state to disabled Changes in v2: - Move hci devcoredump implementation to new files - Move dump queue and dump work to hci_devcoredump struct - Add CONFIG_DEV_COREDUMP conditional compile include/net/bluetooth/coredump.h | 119 +++++++ include/net/bluetooth/hci_core.h | 5 + net/bluetooth/Makefile | 2 + net/bluetooth/coredump.c | 524 +++++++++++++++++++++++++++++++ net/bluetooth/hci_core.c | 9 + net/bluetooth/hci_sync.c | 2 + 6 files changed, 661 insertions(+) create mode 100644 include/net/bluetooth/coredump.h create mode 100644 net/bluetooth/coredump.c diff --git a/include/net/bluetooth/coredump.h b/include/net/bluetooth/coredump.h new file mode 100644 index 000000000000..be09290927c0 --- /dev/null +++ b/include/net/bluetooth/coredump.h @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Google Corporation + */ + +#ifndef __COREDUMP_H +#define __COREDUMP_H + +#define DEVCOREDUMP_TIMEOUT msecs_to_jiffies(10000) /* 10 sec */ + +typedef bool (*coredump_enabled_t)(struct hci_dev *hdev); +typedef void (*coredump_t)(struct hci_dev *hdev); +typedef int (*dmp_hdr_t)(struct hci_dev *hdev, char *buf, size_t size); +typedef void (*notify_change_t)(struct hci_dev *hdev, int state); + +/* struct hci_devcoredump - Devcoredump state + * + * @supported: Indicates if FW dump collection is supported by driver + * @state: Current state of dump collection + * @alloc_size: Total size of the dump + * @head: Start of the dump + * @tail: Pointer to current end of dump + * @end: head + alloc_size for easy comparisons + * + * @dump_q: Dump queue for state machine to process + * @dump_rx: Devcoredump state machine work + * @dump_timeout: Devcoredump timeout work + * + * @enabled: Checks if the devcoredump is enabled for the device + * + * @coredump: Called from the driver's .coredump() function. + * @dmp_hdr: Create a dump header to identify controller/fw/driver info + * @notify_change: Notify driver when devcoredump state has changed + */ +struct hci_devcoredump { + bool supported; + + enum devcoredump_state { + HCI_DEVCOREDUMP_IDLE, + HCI_DEVCOREDUMP_ACTIVE, + HCI_DEVCOREDUMP_DONE, + HCI_DEVCOREDUMP_ABORT, + HCI_DEVCOREDUMP_TIMEOUT + } state; + + size_t alloc_size; + char *head; + char *tail; + char *end; + + struct sk_buff_head dump_q; + struct work_struct dump_rx; + struct delayed_work dump_timeout; + + coredump_enabled_t enabled; + + coredump_t coredump; + dmp_hdr_t dmp_hdr; + notify_change_t notify_change; +}; + +#ifdef CONFIG_DEV_COREDUMP + +void hci_devcoredump_reset(struct hci_dev *hdev); +void hci_devcoredump_rx(struct work_struct *work); +void hci_devcoredump_timeout(struct work_struct *work); + +int hci_devcoredump_register(struct hci_dev *hdev, coredump_t coredump, + dmp_hdr_t dmp_hdr, notify_change_t notify_change); +int hci_devcoredump_init(struct hci_dev *hdev, u32 dmp_size); +int hci_devcoredump_append(struct hci_dev *hdev, struct sk_buff *skb); +int hci_devcoredump_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len); +int hci_devcoredump_complete(struct hci_dev *hdev); +int hci_devcoredump_abort(struct hci_dev *hdev); + +#else + +static inline void hci_devcoredump_reset(struct hci_dev *hdev) {} +static inline void hci_devcoredump_rx(struct work_struct *work) {} +static inline void hci_devcoredump_timeout(struct work_struct *work) {} + +static inline int hci_devcoredump_register(struct hci_dev *hdev, + coredump_t coredump, + dmp_hdr_t dmp_hdr, + notify_change_t notify_change) +{ + return -EOPNOTSUPP; +} + +static inline int hci_devcoredump_init(struct hci_dev *hdev, u32 dmp_size) +{ + return -EOPNOTSUPP; +} + +static inline int hci_devcoredump_append(struct hci_dev *hdev, + struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + +static inline int hci_devcoredump_append_pattern(struct hci_dev *hdev, + u8 pattern, u32 len) +{ + return -EOPNOTSUPP; +} + +static inline int hci_devcoredump_complete(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +static inline int hci_devcoredump_abort(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +#endif /* CONFIG_DEV_COREDUMP */ + +#endif /* __COREDUMP_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e7862903187d..fb5ef1c6dd10 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -32,6 +32,7 @@ #include #include #include +#include /* HCI priority */ #define HCI_PRIO_MAX 7 @@ -585,6 +586,10 @@ struct hci_dev { const char *fw_info; struct dentry *debugfs; +#ifdef CONFIG_DEV_COREDUMP + struct hci_devcoredump dump; +#endif + struct device dev; struct rfkill *rfkill; diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 0e7b7db42750..141ac1fda0bf 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -17,6 +17,8 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \ eir.o hci_sync.o +bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o + bluetooth-$(CONFIG_BT_BREDR) += sco.o bluetooth-$(CONFIG_BT_LE) += iso.o bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o diff --git a/net/bluetooth/coredump.c b/net/bluetooth/coredump.c new file mode 100644 index 000000000000..b412056457c8 --- /dev/null +++ b/net/bluetooth/coredump.c @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Google Corporation + */ + +#include + +#include +#include + +enum hci_devcoredump_pkt_type { + HCI_DEVCOREDUMP_PKT_INIT, + HCI_DEVCOREDUMP_PKT_SKB, + HCI_DEVCOREDUMP_PKT_PATTERN, + HCI_DEVCOREDUMP_PKT_COMPLETE, + HCI_DEVCOREDUMP_PKT_ABORT, +}; + +struct hci_devcoredump_skb_cb { + u16 pkt_type; +}; + +struct hci_devcoredump_skb_pattern { + u8 pattern; + u32 len; +} __packed; + +#define hci_dmp_cb(skb) ((struct hci_devcoredump_skb_cb *)((skb)->cb)) + +#define MAX_DEVCOREDUMP_HDR_SIZE 512 /* bytes */ + +static int hci_devcoredump_update_hdr_state(char *buf, size_t size, int state) +{ + if (!buf) + return 0; + + return snprintf(buf, size, "Bluetooth devcoredump\nState: %d\n", state); +} + +/* Call with hci_dev_lock only. */ +static int hci_devcoredump_update_state(struct hci_dev *hdev, int state) +{ + hdev->dump.state = state; + + return hci_devcoredump_update_hdr_state(hdev->dump.head, + hdev->dump.alloc_size, state); +} + +static int hci_devcoredump_mkheader(struct hci_dev *hdev, char *buf, + size_t buf_size) +{ + char *ptr = buf; + size_t rem = buf_size; + size_t read = 0; + + read = hci_devcoredump_update_hdr_state(ptr, rem, HCI_DEVCOREDUMP_IDLE); + read += 1; /* update_hdr_state adds \0 at the end upon state rewrite */ + rem -= read; + ptr += read; + + if (hdev->dump.dmp_hdr) { + /* dmp_hdr() should return number of bytes written */ + read = hdev->dump.dmp_hdr(hdev, ptr, rem); + rem -= read; + ptr += read; + } + + read = snprintf(ptr, rem, "--- Start dump ---\n"); + rem -= read; + ptr += read; + + return buf_size - rem; +} + +/* Do not call with hci_dev_lock since this calls driver code. */ +static void hci_devcoredump_notify(struct hci_dev *hdev, int state) +{ + if (hdev->dump.notify_change) + hdev->dump.notify_change(hdev, state); +} + +/* Call with hci_dev_lock only. */ +void hci_devcoredump_reset(struct hci_dev *hdev) +{ + hdev->dump.head = NULL; + hdev->dump.tail = NULL; + hdev->dump.alloc_size = 0; + + hci_devcoredump_update_state(hdev, HCI_DEVCOREDUMP_IDLE); + + cancel_delayed_work(&hdev->dump.dump_timeout); + skb_queue_purge(&hdev->dump.dump_q); +} + +/* Call with hci_dev_lock only. */ +static void hci_devcoredump_free(struct hci_dev *hdev) +{ + if (hdev->dump.head) + vfree(hdev->dump.head); + + hci_devcoredump_reset(hdev); +} + +/* Call with hci_dev_lock only. */ +static int hci_devcoredump_alloc(struct hci_dev *hdev, u32 size) +{ + hdev->dump.head = vmalloc(size); + if (!hdev->dump.head) + return -ENOMEM; + + hdev->dump.alloc_size = size; + hdev->dump.tail = hdev->dump.head; + hdev->dump.end = hdev->dump.head + size; + + hci_devcoredump_update_state(hdev, HCI_DEVCOREDUMP_IDLE); + + return 0; +} + +/* Call with hci_dev_lock only. */ +static bool hci_devcoredump_copy(struct hci_dev *hdev, char *buf, u32 size) +{ + if (hdev->dump.tail + size > hdev->dump.end) + return false; + + memcpy(hdev->dump.tail, buf, size); + hdev->dump.tail += size; + + return true; +} + +/* Call with hci_dev_lock only. */ +static bool hci_devcoredump_memset(struct hci_dev *hdev, u8 pattern, u32 len) +{ + if (hdev->dump.tail + len > hdev->dump.end) + return false; + + memset(hdev->dump.tail, pattern, len); + hdev->dump.tail += len; + + return true; +} + +/* Call with hci_dev_lock only. */ +static int hci_devcoredump_prepare(struct hci_dev *hdev, u32 dump_size) +{ + char *dump_hdr; + int dump_hdr_size; + u32 size; + int err = 0; + + dump_hdr = vmalloc(MAX_DEVCOREDUMP_HDR_SIZE); + if (!dump_hdr) { + err = -ENOMEM; + goto hdr_free; + } + + dump_hdr_size = hci_devcoredump_mkheader(hdev, dump_hdr, + MAX_DEVCOREDUMP_HDR_SIZE); + size = dump_hdr_size + dump_size; + + if (hci_devcoredump_alloc(hdev, size)) { + err = -ENOMEM; + goto hdr_free; + } + + /* Insert the device header */ + if (!hci_devcoredump_copy(hdev, dump_hdr, dump_hdr_size)) { + bt_dev_err(hdev, "Failed to insert header"); + hci_devcoredump_free(hdev); + + err = -ENOMEM; + goto hdr_free; + } + +hdr_free: + if (dump_hdr) + vfree(dump_hdr); + + return err; +} + +/* Bluetooth devcoredump state machine. + * + * Devcoredump states: + * + * HCI_DEVCOREDUMP_IDLE: The default state. + * + * HCI_DEVCOREDUMP_ACTIVE: A devcoredump will be in this state once it has + * been initialized using hci_devcoredump_init(). Once active, the + * driver can append data using hci_devcoredump_append() or insert + * a pattern using hci_devcoredump_append_pattern(). + * + * HCI_DEVCOREDUMP_DONE: Once the dump collection is complete, the drive + * can signal the completion using hci_devcoredump_complete(). A + * devcoredump is generated indicating the completion event and + * then the state machine is reset to the default state. + * + * HCI_DEVCOREDUMP_ABORT: The driver can cancel ongoing dump collection in + * case of any error using hci_devcoredump_abort(). A devcoredump + * is still generated with the available data indicating the abort + * event and then the state machine is reset to the default state. + * + * HCI_DEVCOREDUMP_TIMEOUT: A timeout timer for HCI_DEVCOREDUMP_TIMEOUT sec + * is started during devcoredump initialization. Once the timeout + * occurs, the driver is notified, a devcoredump is generated with + * the available data indicating the timeout event and then the + * state machine is reset to the default state. + * + * The driver must register using hci_devcoredump_register() before using the + * hci devcoredump APIs. + */ +void hci_devcoredump_rx(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, dump.dump_rx); + struct sk_buff *skb; + struct hci_devcoredump_skb_pattern *pattern; + u32 dump_size; + int start_state; + +#define DBG_UNEXPECTED_STATE() \ + bt_dev_dbg(hdev, \ + "Unexpected packet (%d) for state (%d). ", \ + hci_dmp_cb(skb)->pkt_type, hdev->dump.state) + + while ((skb = skb_dequeue(&hdev->dump.dump_q))) { + hci_dev_lock(hdev); + start_state = hdev->dump.state; + + switch (hci_dmp_cb(skb)->pkt_type) { + case HCI_DEVCOREDUMP_PKT_INIT: + if (hdev->dump.state != HCI_DEVCOREDUMP_IDLE) { + DBG_UNEXPECTED_STATE(); + goto loop_continue; + } + + if (skb->len != sizeof(dump_size)) { + bt_dev_dbg(hdev, "Invalid dump init pkt"); + goto loop_continue; + } + + dump_size = *((u32 *)skb->data); + if (!dump_size) { + bt_dev_err(hdev, "Zero size dump init pkt"); + goto loop_continue; + } + + if (hci_devcoredump_prepare(hdev, dump_size)) { + bt_dev_err(hdev, "Failed to prepare for dump"); + goto loop_continue; + } + + hci_devcoredump_update_state(hdev, + HCI_DEVCOREDUMP_ACTIVE); + queue_delayed_work(hdev->workqueue, + &hdev->dump.dump_timeout, + DEVCOREDUMP_TIMEOUT); + break; + + case HCI_DEVCOREDUMP_PKT_SKB: + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { + DBG_UNEXPECTED_STATE(); + goto loop_continue; + } + + if (!hci_devcoredump_copy(hdev, skb->data, skb->len)) + bt_dev_dbg(hdev, "Failed to insert skb"); + break; + + case HCI_DEVCOREDUMP_PKT_PATTERN: + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { + DBG_UNEXPECTED_STATE(); + goto loop_continue; + } + + if (skb->len != sizeof(*pattern)) { + bt_dev_dbg(hdev, "Invalid pattern skb"); + goto loop_continue; + } + + pattern = (void *)skb->data; + + if (!hci_devcoredump_memset(hdev, pattern->pattern, + pattern->len)) + bt_dev_dbg(hdev, "Failed to set pattern"); + break; + + case HCI_DEVCOREDUMP_PKT_COMPLETE: + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { + DBG_UNEXPECTED_STATE(); + goto loop_continue; + } + + hci_devcoredump_update_state(hdev, + HCI_DEVCOREDUMP_DONE); + dump_size = hdev->dump.tail - hdev->dump.head; + + bt_dev_info(hdev, + "Devcoredump complete with size %u " + "(expect %u)", + dump_size, hdev->dump.alloc_size); + + dev_coredumpv(&hdev->dev, hdev->dump.head, dump_size, + GFP_KERNEL); + break; + + case HCI_DEVCOREDUMP_PKT_ABORT: + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { + DBG_UNEXPECTED_STATE(); + goto loop_continue; + } + + hci_devcoredump_update_state(hdev, + HCI_DEVCOREDUMP_ABORT); + dump_size = hdev->dump.tail - hdev->dump.head; + + bt_dev_info(hdev, + "Devcoredump aborted with size %u " + "(expect %u)", + dump_size, hdev->dump.alloc_size); + + /* Emit a devcoredump with the available data */ + dev_coredumpv(&hdev->dev, hdev->dump.head, dump_size, + GFP_KERNEL); + break; + + default: + bt_dev_dbg(hdev, + "Unknown packet (%d) for state (%d). ", + hci_dmp_cb(skb)->pkt_type, hdev->dump.state); + break; + } + +loop_continue: + kfree_skb(skb); + hci_dev_unlock(hdev); + + if (start_state != hdev->dump.state) + hci_devcoredump_notify(hdev, hdev->dump.state); + + hci_dev_lock(hdev); + if (hdev->dump.state == HCI_DEVCOREDUMP_DONE || + hdev->dump.state == HCI_DEVCOREDUMP_ABORT) + hci_devcoredump_reset(hdev); + hci_dev_unlock(hdev); + } +} +EXPORT_SYMBOL(hci_devcoredump_rx); + +void hci_devcoredump_timeout(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, + dump.dump_timeout.work); + u32 dump_size; + + hci_devcoredump_notify(hdev, HCI_DEVCOREDUMP_TIMEOUT); + + hci_dev_lock(hdev); + + cancel_work_sync(&hdev->dump.dump_rx); + + hci_devcoredump_update_state(hdev, HCI_DEVCOREDUMP_TIMEOUT); + dump_size = hdev->dump.tail - hdev->dump.head; + bt_dev_info(hdev, "Devcoredump timeout with size %u (expect %u)", + dump_size, hdev->dump.alloc_size); + + /* Emit a devcoredump with the available data */ + dev_coredumpv(&hdev->dev, hdev->dump.head, dump_size, GFP_KERNEL); + + hci_devcoredump_reset(hdev); + + hci_dev_unlock(hdev); +} +EXPORT_SYMBOL(hci_devcoredump_timeout); + +int hci_devcoredump_register(struct hci_dev *hdev, coredump_t coredump, + dmp_hdr_t dmp_hdr, notify_change_t notify_change) +{ + /* Driver must implement coredump() and dmp_hdr() functions for + * bluetooth devcoredump. The coredump() should trigger a coredump + * event on the controller when the device's coredump sysfs entry is + * written to. The dmp_hdr() should create a dump header to identify + * the controller/fw/driver info. + */ + if (!coredump || !dmp_hdr) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->dump.coredump = coredump; + hdev->dump.dmp_hdr = dmp_hdr; + hdev->dump.notify_change = notify_change; + hdev->dump.supported = true; + hci_dev_unlock(hdev); + + return 0; +} +EXPORT_SYMBOL(hci_devcoredump_register); + +static inline bool hci_devcoredump_enabled(struct hci_dev *hdev) +{ + /* The 'supported' flag is true when the driver registers with the HCI + * devcoredump API, whereas, the 'enabled' is controlled via a sysfs + * entry. For drivers like btusb which supports multiple vendor drivers, + * it is possible that the vendor driver does not support but the + * interface is provided by the base btusb driver. So, check both. + */ + if (hdev->dump.supported && hdev->dump.enabled) + return hdev->dump.enabled(hdev); + + return false; +} + +int hci_devcoredump_init(struct hci_dev *hdev, u32 dmp_size) +{ + struct sk_buff *skb = NULL; + + if (!hci_devcoredump_enabled(hdev)) + return -EOPNOTSUPP; + + skb = alloc_skb(sizeof(dmp_size), GFP_ATOMIC); + if (!skb) { + bt_dev_err(hdev, "Failed to allocate devcoredump init"); + return -ENOMEM; + } + + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_INIT; + skb_put_data(skb, &dmp_size, sizeof(dmp_size)); + + skb_queue_tail(&hdev->dump.dump_q, skb); + queue_work(hdev->workqueue, &hdev->dump.dump_rx); + + return 0; +} +EXPORT_SYMBOL(hci_devcoredump_init); + +int hci_devcoredump_append(struct hci_dev *hdev, struct sk_buff *skb) +{ + if (!skb) + return -ENOMEM; + + if (!hci_devcoredump_enabled(hdev)) { + kfree_skb(skb); + return -EOPNOTSUPP; + } + + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_SKB; + + skb_queue_tail(&hdev->dump.dump_q, skb); + queue_work(hdev->workqueue, &hdev->dump.dump_rx); + + return 0; +} +EXPORT_SYMBOL(hci_devcoredump_append); + +int hci_devcoredump_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len) +{ + struct hci_devcoredump_skb_pattern p; + struct sk_buff *skb = NULL; + + if (!hci_devcoredump_enabled(hdev)) + return -EOPNOTSUPP; + + skb = alloc_skb(sizeof(p), GFP_ATOMIC); + if (!skb) { + bt_dev_err(hdev, "Failed to allocate devcoredump pattern"); + return -ENOMEM; + } + + p.pattern = pattern; + p.len = len; + + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_PATTERN; + skb_put_data(skb, &p, sizeof(p)); + + skb_queue_tail(&hdev->dump.dump_q, skb); + queue_work(hdev->workqueue, &hdev->dump.dump_rx); + + return 0; +} +EXPORT_SYMBOL(hci_devcoredump_append_pattern); + +int hci_devcoredump_complete(struct hci_dev *hdev) +{ + struct sk_buff *skb = NULL; + + if (!hci_devcoredump_enabled(hdev)) + return -EOPNOTSUPP; + + skb = alloc_skb(0, GFP_ATOMIC); + if (!skb) { + bt_dev_err(hdev, "Failed to allocate devcoredump complete"); + return -ENOMEM; + } + + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_COMPLETE; + + skb_queue_tail(&hdev->dump.dump_q, skb); + queue_work(hdev->workqueue, &hdev->dump.dump_rx); + + return 0; +} +EXPORT_SYMBOL(hci_devcoredump_complete); + +int hci_devcoredump_abort(struct hci_dev *hdev) +{ + struct sk_buff *skb = NULL; + + if (!hci_devcoredump_enabled(hdev)) + return -EOPNOTSUPP; + + skb = alloc_skb(0, GFP_ATOMIC); + if (!skb) { + bt_dev_err(hdev, "Failed to allocate devcoredump abort"); + return -ENOMEM; + } + + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_ABORT; + + skb_queue_tail(&hdev->dump.dump_q, skb); + queue_work(hdev->workqueue, &hdev->dump.dump_rx); + + return 0; +} +EXPORT_SYMBOL(hci_devcoredump_abort); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b3a5a3cc9372..9a697190c7a8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2510,14 +2510,23 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) INIT_WORK(&hdev->tx_work, hci_tx_work); INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->error_reset, hci_error_reset); +#ifdef CONFIG_DEV_COREDUMP + INIT_WORK(&hdev->dump.dump_rx, hci_devcoredump_rx); +#endif hci_cmd_sync_init(hdev); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); +#ifdef CONFIG_DEV_COREDUMP + INIT_DELAYED_WORK(&hdev->dump.dump_timeout, hci_devcoredump_timeout); +#endif skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); skb_queue_head_init(&hdev->raw_q); +#ifdef CONFIG_DEV_COREDUMP + skb_queue_head_init(&hdev->dump.dump_q); +#endif init_waitqueue_head(&hdev->req_wait_q); diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index e6d804b82b67..09d74ae2b81c 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4337,6 +4337,8 @@ int hci_dev_open_sync(struct hci_dev *hdev) goto done; } + hci_devcoredump_reset(hdev); + set_bit(HCI_RUNNING, &hdev->flags); hci_sock_dev_event(hdev, HCI_DEV_OPEN); From patchwork Tue Aug 9 15:35:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manish Mandlik X-Patchwork-Id: 596260 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8612C25B0C for ; Tue, 9 Aug 2022 15:36:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243623AbiHIPgI (ORCPT ); Tue, 9 Aug 2022 11:36:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244518AbiHIPfu (ORCPT ); Tue, 9 Aug 2022 11:35:50 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5CFDA25F6 for ; Tue, 9 Aug 2022 08:35:49 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-32851d0f8beso104471027b3.22 for ; Tue, 09 Aug 2022 08:35:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc; bh=ufjJg4VVxq92WaQVQMCk9m8A9i0qlvuSNS+kFeik61o=; b=RXu3e9SK5+03ky70/ZSYqs7MjiZvc9YX8O0kcstuAXa9Vy+FUrLRu0P3u9RZbyS3GO uywN6ssmvzu30Orf42VVSWqugtBcqXvHbO8FJGI31043kSPsYS716n3vGr8BAJ9TASdz GQH5Ulz7Vt2ZkO3MryQ9PHpAw/exu8PIiXdNUmlAzpfpPM/G2vl1c1CuIDbvwMwy2N13 MzTq+yNDPsiezUtdKXjhsA9X4v5L2Af97WhuVXu4dYIKgXSRWU5s2zt6KvVNYJKAhEVU Zvx+YQxCBYTmKKhb5OvQrIH+TwprGSeVeemIngULueJd6P3ixMGdgKFaE7ecH7qPaSkx jSKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc; bh=ufjJg4VVxq92WaQVQMCk9m8A9i0qlvuSNS+kFeik61o=; b=B69EOinkgQs9K0aO9HeR5EDVSAANW+TJDDnMhJZifetTr0wqFUZGeyc0XyA8K0geR6 9D8X3/8bx1WOUkfrhEDF3mj7BlRP+r+blWh3chpBZyGErhnpTr3SqBDGmt1yoH7MItD6 jyDx9pnTjYwi/4cMHaEwrCaonHba427GuKo0ghD764ukp0K9Hfwi+ZwI/xSDtqidEdpy YExmiGpaZ6bER+TZZ6QjbMn2R+FiJE2JsfaoBfokbQyVp0J3FPO3bPUEZ+n6B0rGYfsS apPXVtpJdqjzluOjt8lkcW048tnmuWPOStB8dPX71K1YizxQAswKv6nKilGXUZCO0o+q TV3Q== X-Gm-Message-State: ACgBeo2m0UXbo2UZPxBeDqBIv2GNmBPBZoF/jU9sNAiiaHtvMLPyFHfU yUnQ64ZFZa6rXAmeULbkrKHB+EHrv8f9Iw== X-Google-Smtp-Source: AA6agR50yechnFMMM/5FXSXojXIsB/DsnQjLhjvw2CWMNyh2fsc0MANYCEgYqrlhNUHXxpVmIu+tPlAXSV59cw== X-Received: from mmandlik.mtv.corp.google.com ([2620:15c:202:201:91a6:8007:96f6:3fb3]) (user=mmandlik job=sendgmr) by 2002:a25:dc81:0:b0:67c:1421:12bc with SMTP id y123-20020a25dc81000000b0067c142112bcmr5401827ybe.267.1660059348675; Tue, 09 Aug 2022 08:35:48 -0700 (PDT) Date: Tue, 9 Aug 2022 08:35:26 -0700 In-Reply-To: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> Message-Id: <20220809083112.v4.4.Id0d6e772f00432d55f6bcbf68a50cb4ad89396c6@changeid> Mime-Version: 1.0 References: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v4 4/5] Bluetooth: btusb: Add btusb devcoredump support From: Manish Mandlik To: Arend van Spriel , marcel@holtmann.org, luiz.dentz@gmail.com Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Manish Mandlik , Abhishek Pandit-Subedi , Johan Hedberg , linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org This patch implements the btusb driver side .coredump() callback to trigger a devcoredump via sysfs and .enable_coredump() callback to check if the devcoredump functionality is enabled for a device. Signed-off-by: Manish Mandlik Reviewed-by: Abhishek Pandit-Subedi --- Changes in v4: - New patch in the series drivers/bluetooth/btusb.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 30dd443f395f..b00851327aa3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1510,6 +1510,15 @@ static void btusb_isoc_tx_complete(struct urb *urb) kfree_skb(skb); } +#ifdef CONFIG_DEV_COREDUMP +static bool btusb_coredump_enabled(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + + return !data->intf->dev.coredump_disabled; +} +#endif + static int btusb_open(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -3765,6 +3774,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame; hdev->notify = btusb_notify; hdev->wakeup = btusb_wakeup; +#ifdef CONFIG_DEV_COREDUMP + hdev->dump.enabled = btusb_coredump_enabled; +#endif #ifdef CONFIG_PM err = btusb_config_oob_wake(hdev); @@ -4180,6 +4192,17 @@ static int btusb_resume(struct usb_interface *intf) } #endif +#ifdef CONFIG_DEV_COREDUMP +static void btusb_coredump(struct device *dev) +{ + struct btusb_data *data = dev_get_drvdata(dev); + struct hci_dev *hdev = data->hdev; + + if (!dev->coredump_disabled && hdev->dump.coredump) + hdev->dump.coredump(hdev); +} +#endif + static struct usb_driver btusb_driver = { .name = "btusb", .probe = btusb_probe, @@ -4191,6 +4214,14 @@ static struct usb_driver btusb_driver = { .id_table = btusb_table, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, + +#ifdef CONFIG_DEV_COREDUMP + .drvwrap = { + .driver = { + .coredump = btusb_coredump, + }, + }, +#endif }; module_usb_driver(btusb_driver); From patchwork Tue Aug 9 15:35:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manish Mandlik X-Patchwork-Id: 596867 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D8425C19F2D for ; Tue, 9 Aug 2022 15:36:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244216AbiHIPgJ (ORCPT ); Tue, 9 Aug 2022 11:36:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244775AbiHIPfx (ORCPT ); Tue, 9 Aug 2022 11:35:53 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16F50F17 for ; Tue, 9 Aug 2022 08:35:52 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-31f4b76446aso103146317b3.7 for ; Tue, 09 Aug 2022 08:35:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc; bh=gPUi4gpOmnHynevr/2CEpqe/DchkBEzLt9FG3lvW+PY=; b=prz7LXyXu+djEJ4xCdID/YYoxEaR1BQYzZqgW0C0imYRjRSmDzF7qErRADSLAYqT18 v3ta3DE/n5Y9rTLCcq2+C2RnUTkF3R7ilZEejP8CagjsIE1uc2HXB5+bq+pgJOYXFN/+ 7dGq9zEdzoD0fvjajsEBJWCoFEOZ3h/CjiprZmbCGhjH346PEqvWwoxq2CDm/N07flOa W+DnsjUsTINxIW77OA9yeD3aLfi+tGbnfY86gXJNYW1acdL+9tfVEu4Q+NpHN5u5WUjq z76UbwFY8tirIZyJHMlS1zOX0aWPTTQsXIpPFXhcr5f1l0o5Q641VfUSUQPh7ccSHlzx Q/xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc; bh=gPUi4gpOmnHynevr/2CEpqe/DchkBEzLt9FG3lvW+PY=; b=pHQ15L82HEWKhq4iUdfUMA5QI6wwJTfjXdqa7ccRwdbSd0Y3E8lIXgUEAJ77gCfEXt lbnGpqY5ZbbZSQqaqswxAn1wXOUe1T3Q0s8uy+TYtrWSlEqqF39HWlpGgPe7Kb84ex2H uzal8PAKaAKTAxowWmijljLmuS5/ky8UvO+BoLjzBiKI+0wfxdURCe9KRUDj0DGUDhQa ydbkVSYRF5iyap6pygIZM47GM3JY0ewJuDRbHsP/MPaiY8l0ajQILCoJwlNRRkZpqL3/ wasKhUXgWuN8RFGR9Suon2kYEiyWuCznj4y8FQopb+IXTsvwNXiQAt0VLqqvHKodDPrS t6MQ== X-Gm-Message-State: ACgBeo1hPtjWPvYwBoKtpI6r4xEjG8BZ+GJkfGsvb5EFo/r1WZkShRYu VTuHnf6Wj3aeSm0u33TWgMfF0YfrYKUs+w== X-Google-Smtp-Source: AA6agR6+f07cwBT3OUA8O2ux6G3HsKQKHkKyNSnd6o2T/0Xw8avWUjZPA5aDWnDMrBlHvy/PUNqePyv8vTT79g== X-Received: from mmandlik.mtv.corp.google.com ([2620:15c:202:201:91a6:8007:96f6:3fb3]) (user=mmandlik job=sendgmr) by 2002:a81:5b54:0:b0:323:e6d5:f382 with SMTP id p81-20020a815b54000000b00323e6d5f382mr22935270ywb.28.1660059351408; Tue, 09 Aug 2022 08:35:51 -0700 (PDT) Date: Tue, 9 Aug 2022 08:35:27 -0700 In-Reply-To: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> Message-Id: <20220809083112.v4.5.I61857ea92be43418b8ce16839f79a4704cc89fa6@changeid> Mime-Version: 1.0 References: <20220809083112.v4.1.I5622b2a92dca4d2703a0f747e24f3ef19303e6df@changeid> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v4 5/5] Bluetooth: btintel: Add Intel devcoredump support From: Manish Mandlik To: Arend van Spriel , marcel@holtmann.org, luiz.dentz@gmail.com Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Abhishek Pandit-Subedi , Manish Mandlik , Chethan Tumkur Narayan , Johan Hedberg , linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Abhishek Pandit-Subedi Intercept debug exception events from the controller and put them into a devcoredump using hci devcoredump APIs. The debug exception contains data in a TLV format and it will be parsed in userspace. Signed-off-by: Abhishek Pandit-Subedi Signed-off-by: Manish Mandlik Reviewed-by: Abhishek Pandit-Subedi Reviewed-by: Chethan Tumkur Narayan --- Hi Luiz, The implementation of btintel_coredump() is currently under internal review. So I'll send it later as a separate patch. This patch includes only a placeholder for that. Thanks, Manish. Changes in v4: - Add btintel_coredump() placeholder Changes in v2: - Create a local struct to store coredump_info in btintel.c - Call btintel_register_devcoredump_support() from btintel.c - Fix strncpy() destination bound warning drivers/bluetooth/btintel.c | 73 ++++++++++++++++++++++++++++++++++++- drivers/bluetooth/btintel.h | 11 +++++- drivers/bluetooth/btusb.c | 51 ++++++++++++++++++++++---- 3 files changed, 125 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 818681c89db8..667cc11b19c3 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -32,6 +32,13 @@ struct cmd_write_boot_params { u8 fw_build_yy; } __packed; +#define DRIVER_NAME_LEN 16 +static struct { + char driver_name[DRIVER_NAME_LEN]; + u8 hw_variant; + u32 fw_build_num; +} coredump_info; + int btintel_check_bdaddr(struct hci_dev *hdev) { struct hci_rp_read_bd_addr *bda; @@ -304,6 +311,9 @@ int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) return -EINVAL; } + coredump_info.hw_variant = ver->hw_variant; + coredump_info.fw_build_num = ver->fw_build_num; + bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u", variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, ver->fw_build_num, ver->fw_build_ww, @@ -497,6 +507,9 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, return -EINVAL; } + coredump_info.hw_variant = INTEL_HW_VARIANT(version->cnvi_bt); + coredump_info.fw_build_num = version->build_num; + bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant, 2000 + (version->timestamp >> 8), version->timestamp & 0xff, version->build_type, version->build_num); @@ -1391,6 +1404,59 @@ int btintel_set_quality_report(struct hci_dev *hdev, bool enable) } EXPORT_SYMBOL_GPL(btintel_set_quality_report); +static void btintel_coredump(struct hci_dev *hdev) +{ + /* Trigger coredump */ +} + +static int btintel_dmp_hdr(struct hci_dev *hdev, char *buf, size_t size) +{ + char *ptr = buf; + size_t rem = size; + size_t read = 0; + + read = snprintf(ptr, rem, "Controller Name: 0x%X\n", + coredump_info.hw_variant); + rem -= read; + ptr += read; + + read = snprintf(ptr, rem, "Firmware Version: 0x%X\n", + coredump_info.fw_build_num); + rem -= read; + ptr += read; + + read = snprintf(ptr, rem, "Driver: %s\n", coredump_info.driver_name); + rem -= read; + ptr += read; + + read = snprintf(ptr, rem, "Vendor: Intel\n"); + rem -= read; + ptr += read; + + return size - rem; +} + +static int btintel_register_devcoredump_support(struct hci_dev *hdev) +{ + struct intel_debug_features features; + int err; + + err = btintel_read_debug_features(hdev, &features); + if (err) { + bt_dev_info(hdev, "Error reading debug features"); + return err; + } + + if (!(features.page1[0] & 0x3f)) { + bt_dev_info(hdev, "Telemetry exception format not supported"); + return -EOPNOTSUPP; + } + + hci_devcoredump_register(hdev, btintel_coredump, btintel_dmp_hdr, NULL); + + return err; +} + static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev, struct intel_version *ver) { @@ -2464,6 +2530,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) btintel_set_msft_opcode(hdev, ver.hw_variant); err = btintel_bootloader_setup(hdev, &ver); + btintel_register_devcoredump_support(hdev); break; default: bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", @@ -2538,6 +2605,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) btintel_set_msft_opcode(hdev, ver.hw_variant); err = btintel_bootloader_setup(hdev, &ver); + btintel_register_devcoredump_support(hdev); break; case 0x17: case 0x18: @@ -2560,6 +2628,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); + btintel_register_devcoredump_support(hdev); break; default: bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", @@ -2608,7 +2677,7 @@ static int btintel_shutdown_combined(struct hci_dev *hdev) return 0; } -int btintel_configure_setup(struct hci_dev *hdev) +int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name) { hdev->manufacturer = 2; hdev->setup = btintel_setup_combined; @@ -2617,6 +2686,8 @@ int btintel_configure_setup(struct hci_dev *hdev) hdev->set_diag = btintel_set_diag_combined; hdev->set_bdaddr = btintel_set_bdaddr; + strncpy(coredump_info.driver_name, driver_name, DRIVER_NAME_LEN - 1); + return 0; } EXPORT_SYMBOL_GPL(btintel_configure_setup); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index e0060e58573c..8e72e59b5bde 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -137,6 +137,12 @@ struct intel_offload_use_cases { __u8 preset[8]; } __packed; +#define INTEL_TLV_TYPE_ID 0x1 + +#define INTEL_TLV_SYSTEM_EXCEPTION 0x0 +#define INTEL_TLV_FATAL_EXCEPTION 0x1 +#define INTEL_TLV_DEBUG_EXCEPTION 0x2 + #define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8)) #define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16)) #define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff) @@ -206,7 +212,7 @@ int btintel_read_boot_params(struct hci_dev *hdev, struct intel_boot_params *params); int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver, const struct firmware *fw, u32 *boot_param); -int btintel_configure_setup(struct hci_dev *hdev); +int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name); void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len); void btintel_secure_send_result(struct hci_dev *hdev, const void *ptr, unsigned int len); @@ -287,7 +293,8 @@ static inline int btintel_download_firmware(struct hci_dev *dev, return -EOPNOTSUPP; } -static inline int btintel_configure_setup(struct hci_dev *hdev) +static inline int btintel_configure_setup(struct hci_dev *hdev, + const char *driver_name) { return -ENODEV; } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b00851327aa3..eb30f9188c25 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2213,16 +2213,44 @@ static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer, return btusb_recv_bulk(data, buffer, count); } +static int btusb_intel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct intel_tlv *tlv = (void *)&skb->data[5]; + + /* The first event is always an event type TLV */ + if (tlv->type != INTEL_TLV_TYPE_ID) + goto recv_frame; + + switch (tlv->val[0]) { + case INTEL_TLV_SYSTEM_EXCEPTION: + case INTEL_TLV_FATAL_EXCEPTION: + case INTEL_TLV_DEBUG_EXCEPTION: + /* Generate devcoredump from exception */ + if (!hci_devcoredump_init(hdev, skb->len)) { + hci_devcoredump_append(hdev, skb); + hci_devcoredump_complete(hdev); + } else { + bt_dev_err(hdev, "Failed to generate devcoredump"); + kfree_skb(skb); + } + return 0; + } + +recv_frame: + return hci_recv_frame(hdev, skb); +} + static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) { - if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { - struct hci_event_hdr *hdr = (void *)skb->data; + struct hci_event_hdr *hdr = (void *)skb->data; + const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 }; - if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && - hdr->plen > 0) { - const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; - unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; + if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && + hdr->plen > 0) { + const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; + unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; + if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { switch (skb->data[2]) { case 0x02: /* When switching to the operational firmware @@ -2241,6 +2269,15 @@ static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) break; } } + + /* Handle all diagnostics events separately. May still call + * hci_recv_frame. + */ + if (len >= sizeof(diagnostics_hdr) && + memcmp(&skb->data[2], diagnostics_hdr, + sizeof(diagnostics_hdr)) == 0) { + return btusb_intel_diagnostics(hdev, skb); + } } return hci_recv_frame(hdev, skb); @@ -3822,7 +3859,7 @@ static int btusb_probe(struct usb_interface *intf, /* Combined Intel Device setup to support multiple setup routine */ if (id->driver_info & BTUSB_INTEL_COMBINED) { - err = btintel_configure_setup(hdev); + err = btintel_configure_setup(hdev, btusb_driver.name); if (err) goto out_free_dev;