Bluetooth: btintel_pcie: Add vendor_reset PCI sysfs for PLDR

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 <chandrashekar.devegowda@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Chandrashekar Devegowda
2026-07-27 10:51:02 +05:30
committed by Luiz Augusto von Dentz
parent 80718e2e0f
commit 39bbe7b738
3 changed files with 54 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
What: /sys/bus/pci/devices/<BDF>/vendor_reset
Date: 22-Jul-2026
KernelVersion: 6.17
Contact: linux-bluetooth@vger.kernel.org
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.

View File

@@ -4719,6 +4719,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/

View File

@@ -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