Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: btnxpuart: Add uevents for FW dump and FW download complete

This adds uevents which will be generated whenever FW dump is triggered,
FW dump is complete and FW (re)download is done.

This feature is needed for IW612 chipset, which is a tri-radio chipset,
where WLAN runs on CPU1 and BT and Zigbee runs on CPU2.

Currently, whenever BT FW crashes, and FW dump is in progress, there is
no way for 15.4 application to know that CPU2 is in bad state, and when
it will be recovered.

With the help of these uevents and udev rules, the 15.4 app, or any
userspace application can be alerted whenever CPU2 goes in bad state and
recoveres after BTNXPUART reloads the firmware.

[ 334.255154] Bluetooth: hci0: ==== Start FW dump ===
[ 334.261003] Bluetooth: hci0: ==== Send uevent: BTNXPUART_DEV=serial0-0:BTNXPUART_STATE=FW_DUMP_ACTIVE ===
[ 351.486048] Bluetooth: hci0: ==== FW dump complete ===
[ 351.491356] Bluetooth: hci0: ==== Send uevent: BTNXPUART_DEV=serial0-0:BTNXPUART_STATE=FW_DUMP_DONE ===
[ 352.028974] Bluetooth: hci0: ChipID: 7601, Version: 0
[ 352.034490] Bluetooth: hci0: Request Firmware: nxp/uartspi_n61x_v1.bin.se
[ 353.979977] Bluetooth: hci0: FW Download Complete: 417064 bytes
[ 355.197222] Bluetooth: hci0: ==== Send uevent: BTNXPUART_DEV=serial0-0:BTNXPUART_STATE=FW_READY ===

Tested this change by creating a simple udev rule to store the
BTNXPUART_STATE value in a ~/<BTNXPUART_DEV>/state file, and running
15.4 traffic.

The 15.4 packets were sent over SPI only when BTNXPUART_STATE was
FW_READY.

Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
Tested-by: Jean-Yves Salaün <jean-yves.salaun@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Neeraj Sanjay Kale and committed by
Luiz Augusto von Dentz
085ee7cf 634fd53a

+41 -1
+41 -1
drivers/bluetooth/btnxpuart.c
··· 1440 1440 static int nxp_setup(struct hci_dev *hdev) 1441 1441 { 1442 1442 struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 1443 + struct serdev_device *serdev = nxpdev->serdev; 1444 + char device_string[30]; 1445 + char event_string[50]; 1446 + char *envp[] = {device_string, event_string, NULL}; 1443 1447 int err = 0; 1444 1448 1445 1449 if (nxp_check_boot_sign(nxpdev)) { ··· 1455 1451 bt_dev_info(hdev, "FW already running."); 1456 1452 clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 1457 1453 } 1454 + 1455 + snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev)); 1456 + snprintf(event_string, 50, "BTNXPUART_STATE=FW_READY"); 1457 + bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string, 1458 + event_string); 1459 + kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); 1458 1460 1459 1461 serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); 1460 1462 nxpdev->current_baudrate = nxpdev->fw_init_baudrate; ··· 1782 1772 .write_wakeup = btnxpuart_write_wakeup, 1783 1773 }; 1784 1774 1775 + static void nxp_coredump_notify(struct hci_dev *hdev, int state) 1776 + { 1777 + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 1778 + struct serdev_device *serdev = nxpdev->serdev; 1779 + char device_string[30]; 1780 + char event_string[50]; 1781 + char *envp[] = {device_string, event_string, NULL}; 1782 + 1783 + snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev)); 1784 + switch (state) { 1785 + case HCI_DEVCOREDUMP_ACTIVE: 1786 + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_ACTIVE"); 1787 + break; 1788 + case HCI_DEVCOREDUMP_DONE: 1789 + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_DONE"); 1790 + break; 1791 + case HCI_DEVCOREDUMP_TIMEOUT: 1792 + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_TIMEOUT"); 1793 + break; 1794 + default: 1795 + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_STATE_%d", 1796 + state); 1797 + break; 1798 + } 1799 + bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string, 1800 + event_string); 1801 + kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); 1802 + } 1803 + 1785 1804 static int nxp_serdev_probe(struct serdev_device *serdev) 1786 1805 { 1787 1806 struct hci_dev *hdev; ··· 1907 1868 if (ps_setup(hdev)) 1908 1869 goto probe_fail; 1909 1870 1910 - hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, NULL); 1871 + hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, 1872 + nxp_coredump_notify); 1911 1873 1912 1874 return 0; 1913 1875