[PATCH v6] Bluetooth: btintel_pcie: Add vendor_reset PCI sysfs for PLDR
Chandrashekar Devegowda <[email protected]> Mon, 27 Jul 2026 10:51:02 +0530
| Newsgroups | org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
Add a read-write sysfs entry at /sys/bus/pci/devices/<BDF>/vendor_reset to allow userspace to trigger PLDR (Product Level Device Reset). Reading the attribute displays supported reset types. Writing integer 0 triggers PLDR. Any other input is rejected with -EINVAL and a warning log. Signed-off-by: Chandrashekar Devegowda <[email protected]> --- Changes in v6: - Fixed .driver.dev_groups -> .dev_groups on struct pci_driver (__pci_register_driver overwrites .driver.dev_groups with .dev_groups) - Removed unrelated schedule_work() failure handling from btintel_pcie_request_reset() that caused CI context mismatch Changes in v5: - Renamed sysfs from vendor_rst to vendor_reset (reviewer feedback) - Switched from device_create_file() to driver dev_groups for automatic race-free sysfs lifecycle management - Added ABI doc at Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie - Added WiFi impact description to ABI documentation - Added MAINTAINERS F: entry for ABI doc - v5: https://lore.kernel.org/all/[email protected]/ Changes in v4: - Rebased on latest bluetooth-next to fix CI apply failure - v4: https://lore.kernel.org/all/[email protected]/ Changes in v3: - Dropped reset_type parameter approach from hdev->reset() - Directly call btintel_pcie_request_reset() instead of manual flag manipulation and schedule_work() - Accept only integer 0 for PLDR trigger - v3: https://lore.kernel.org/all/[email protected]/ Changes in v2: - Added reset_type parameter to hdev->reset() callback (1/2) - vendor_rst sysfs used reset_type to select PLDR (2/2) - v2: https://lore.kernel.org/all/[email protected]/ Changes in v1: - Initial implementation - v1: https://lore.kernel.org/all/[email protected]/ .../sysfs-bus-pci-drivers-btintel_pcie | 15 ++++++++ MAINTAINERS | 1 + drivers/bluetooth/btintel_pcie.c | 38 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie b/Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie new file mode 100644 index 000000000000..cceec6ac96bc --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie @@ -0,0 +1,15 @@ +What: /sys/bus/pci/devices/<BDF>/vendor_reset +Date: 22-Jul-2026 +KernelVersion: 6.17 +Contact: [email protected] +Description: This read-write attribute allows userspace to trigger a + Product Level Device Reset (PLDR) on Intel PCIe Bluetooth + controllers. Reading the attribute displays the supported + reset type. Writing integer 0 triggers PLDR. Any other + input is rejected with -EINVAL. + + PLDR resets the entire on-chip platform shared between + Bluetooth and WiFi. This means any driver attached to + the WiFi device that shares hardware with this Bluetooth + device will be released, the platform will be reset, and + both the Bluetooth and WiFi devices will be re-probed. diff --git a/MAINTAINERS b/MAINTAINERS index eb8cdcc76324..39d390f1ceb4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4625,6 +4625,7 @@ S: Supported W: http://www.bluez.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git +F: Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie F: Documentation/devicetree/bindings/net/bluetooth/ F: drivers/bluetooth/ diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index ef42b8d11d4d..005c77a4f5eb 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -2790,6 +2790,43 @@ static void btintel_pcie_hci_reset(struct hci_dev *hdev) btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR); } +static ssize_t vendor_reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val; + struct pci_dev *pdev = to_pci_dev(dev); + struct btintel_pcie_data *data = pci_get_drvdata(pdev); + + if (!data || !data->hdev) + return -ENODEV; + + if (kstrtouint(buf, 10, &val) || val != 0) { + bt_dev_warn(data->hdev, "PLDR rejected: invalid input"); + return -EINVAL; + } + + bt_dev_info(data->hdev, "PLDR triggered via sysfs"); + btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_PLDR); + + return count; +} + +static ssize_t vendor_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "0 - PLDR\n"); +} + +static DEVICE_ATTR_RW(vendor_reset); + +static struct attribute *btintel_pcie_attrs[] = { + &dev_attr_vendor_reset.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(btintel_pcie); + static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) { struct btintel_pcie_dev_recovery *rec; @@ -3250,6 +3287,7 @@ static struct pci_driver btintel_pcie_driver = { .probe = btintel_pcie_probe, .remove = btintel_pcie_remove, .driver.pm = pm_sleep_ptr(&btintel_pcie_pm_ops), + .dev_groups = btintel_pcie_groups, #ifdef CONFIG_DEV_COREDUMP .driver.coredump = btintel_pcie_coredump #endif -- 2.43.0