From ef5a3345d6af58fbfa5d9b1ae2df11d6ac259498 Mon Sep 17 00:00:00 2001 From: spycat88 Date: Thu, 23 Jan 2025 15:18:25 +0000 Subject: [PATCH] drivers: use soc serial for wifi and bluetooth --- drivers/bluetooth/btqca.c | 100 ++++++++++++++++++++++- drivers/soc/qcom/socinfo.c | 10 +++ drivers/net/wireless/ath/ath12k/mac.c | 109 ++++++++++++++++++++++++-- 3 files changed, 209 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index dfbbac92242a..dbe838040a67 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -13,6 +13,78 @@ #include "btqca.h" +extern const char *qcom_serial_number; + +/* Define a static, predefined BD_ADDR structure */ +static const bdaddr_t static_bdaddr = { + .b = { 0x00, 0x03, 0x7F, 0x33, 0x22, 0x11 } +}; + +/** + * generate_bdaddr_from_serial - Generates a BD_ADDR using the serial number + * @bdaddr: Pointer to bdaddr_t structure to populate + * + * This function sets the first 3 bytes to 00:03:7F and the last 3 bytes + * are derived from the last 6 characters of qcom_serial_number in reversed order. + * + * Returns 0 on success, negative error code on failure. + */ +static int generate_bdaddr_from_serial(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + size_t serial_len; + const char *serial = qcom_serial_number; + char last6[7] = {0}; // 6 characters + null terminator + int i; + int ret; + + if (!serial) { + bt_dev_err(hdev, "qcom_serial_number is NULL"); + return -EINVAL; + } + + serial_len = strlen(serial); + if (serial_len < 6) { + bt_dev_err(hdev, "qcom_serial_number is too short: %zu characters", serial_len); + return -EINVAL; + } + + // Extract the last 6 characters + strncpy(last6, serial + serial_len - 6, 6); + + // Initialize the first 3 bytes + bdaddr->b[5] = 0x00; + bdaddr->b[4] = 0x03; + bdaddr->b[3] = 0x7F; + + // Convert the last 6 characters into 3 bytes in reversed order + for (i = 0; i < 3; i++) { + char byte_str[3] = {0}; + u8 byte_val; + + byte_str[0] = last6[i * 2]; + byte_str[1] = last6[i * 2 + 1]; + + if (!isxdigit(byte_str[0]) || !isxdigit(byte_str[1])) { + bt_dev_err(hdev, "Invalid hex characters in serial number: %c%c", + byte_str[0], byte_str[1]); + return -EINVAL; + } + + ret = kstrtou8(byte_str, 16, &byte_val); + if (ret < 0) { + bt_dev_err(hdev, "Failed to convert hex string to u8: %c%c", + byte_str[0], byte_str[1]); + return ret; + } + + bdaddr->b[i] = byte_val; // Assign to bytes 0,1,2 (reversed order) + } + + bt_dev_info(hdev, "Generated BD_ADDR: %pMR", bdaddr); + + return 0; +} + int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver, enum qca_btsoc_type soc_type) { @@ -668,7 +740,7 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); -static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config) +static int __maybe_unused qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config) { struct hci_rp_read_bd_addr *bda; struct sk_buff *skb; @@ -739,6 +811,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, u8 rom_ver = 0; u32 soc_ver; u16 boardid = 0; + bdaddr_t generated_bdaddr; bt_dev_dbg(hdev, "QCA setup on UART"); @@ -918,9 +991,30 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, break; } - err = qca_check_bdaddr(hdev, &config); - if (err) + /* Generate BD_ADDR from qcom_serial_number */ + err = generate_bdaddr_from_serial(hdev, &generated_bdaddr); + if (err) { + bt_dev_err(hdev, "Failed to generate BD_ADDR from serial number"); + return err; + } + + /* Set the generated BD_ADDR */ + err = qca_set_bdaddr(hdev, &generated_bdaddr); + if (err) { + bt_dev_err(hdev, "Failed to set the generated BD_ADDR from serial number"); return err; + } + + /* Update hdev->public_addr and hdev->bdaddr */ + bacpy(&hdev->public_addr, &generated_bdaddr); + bacpy(&hdev->bdaddr, &generated_bdaddr); + bt_dev_info(hdev, "BD_ADDR set to %pMR", &hdev->public_addr); + + + /* Disable reading BD_ADDR from NVM */ + //err = qca_check_bdaddr(hdev, &config); + //if (err) + // return err; bt_dev_info(hdev, "QCA setup on UART is completed"); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index ecfd3da9d5e8..238f804e7fe0 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -163,6 +163,10 @@ struct smem_image_version { }; #endif /* CONFIG_DEBUG_FS */ +/* Global variable to hold the serial number */ +const char *qcom_serial_number; +EXPORT_SYMBOL(qcom_serial_number); + struct qcom_socinfo { struct soc_device *soc_dev; struct soc_device_attribute attr; @@ -795,6 +799,9 @@ static int qcom_socinfo_probe(struct platform_device *pdev) le32_to_cpu(info->serial_num)); if (!qs->attr.serial_number) return -ENOMEM; + + /* Assign the serial number to the global variable */ + qcom_serial_number = qs->attr.serial_number; } qs->soc_dev = soc_device_register(&qs->attr); @@ -818,6 +825,9 @@ static void qcom_socinfo_remove(struct platform_device *pdev) soc_device_unregister(qs->soc_dev); socinfo_debugfs_exit(qs); + + /* Clear the global serial number */ + qcom_serial_number = NULL; } static struct platform_driver qcom_socinfo_driver = { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d493ec812055..0e535e96e27b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -159,6 +159,91 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = { CHAN6G(233, 7115, 0), }; +extern const char *qcom_serial_number; + +/* Define a small struct for storing a 6-byte MAC address array */ +struct macaddr_t { + u8 b[ETH_ALEN]; +}; + +/* Define a static, predefined MAC_ADDR structure */ +static const struct macaddr_t static_macaddr = { + .b = { 0x00, 0x03, 0x7F, 0x11, 0x22, 0x33 } +}; + +/** + * generate_macaddr_from_serial - Generates a MAC_ADDR using the serial number + * @macaddr: Pointer to macaddr_t structure to populate + * + * This function sets the first 3 bytes to 00:03:7F and the last 3 bytes + * are derived from the last 6 characters of qcom_serial_number. + * + * Returns 0 on success, negative error code on failure. + */ +static int generate_macaddr_from_serial(struct ath12k *ar, struct macaddr_t *macaddr) +{ + size_t serial_len; + const char *serial = qcom_serial_number; + char last6[7] = {0}; // 6 characters + null terminator + int i; + int ret; + + if (!serial) { + ath12k_err(ar->ab, "qcom_serial_number is NULL"); + return -EINVAL; + } + + serial_len = strlen(serial); + if (serial_len < 6) { + ath12k_err(ar->ab, "qcom_serial_number is too short: %zu characters", serial_len); + return -EINVAL; + } + + // Extract the last 6 characters + strncpy(last6, serial + serial_len - 6, 6); + + // Initialize the first 3 bytes + macaddr->b[5] = 0x00; + macaddr->b[4] = 0x03; + macaddr->b[3] = 0x7F; + + // Convert the last 6 characters into 3 bytes + for (i = 0; i < 3; i++) { + char byte_str[3] = {0}; + u8 byte_val; + + byte_str[0] = last6[i * 2]; + byte_str[1] = last6[i * 2 + 1]; + + if (!isxdigit(byte_str[0]) || !isxdigit(byte_str[1])) { + ath12k_err(ar->ab, "Invalid hex characters in serial number: %c%c", + byte_str[0], byte_str[1]); + return -EINVAL; + } + + ret = kstrtou8(byte_str, 16, &byte_val); + if (ret < 0) { + ath12k_err(ar->ab, "Failed to convert hex string to u8: %c%c", + byte_str[0], byte_str[1]); + return ret; + } + + macaddr->b[2 - i] = byte_val; // Assign to bytes 2,1,0 + } + + ath12k_info(ar->ab, "Generated MAC_ADDR: %pMR", macaddr); + + return 0; +} + +static void ath12k_reverse_mac(u8 *dst, const u8 *src) +{ + int i; + + for (i = 0; i < ETH_ALEN; i++) + dst[i] = src[ETH_ALEN - 1 - i]; +} + static struct ieee80211_rate ath12k_legacy_rates[] = { { .bitrate = 10, .hw_value = ATH12K_HW_RATE_CCK_LP_1M }, @@ -9533,6 +9618,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev; struct ath12k_pdev_cap *cap; + struct macaddr_t generated_macaddr; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, @@ -9556,11 +9642,17 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) u32 ht_cap_info = 0; pdev = ar->pdev; - if (ar->ab->pdevs_macaddr_valid) { - ether_addr_copy(ar->mac_addr, pdev->mac_addr); + ret = generate_macaddr_from_serial(ar, &generated_macaddr); + if (ret) { + if (ar->ab->pdevs_macaddr_valid) { + ether_addr_copy(ar->mac_addr, pdev->mac_addr); + } else { + ether_addr_copy(ar->mac_addr, ar->ab->mac_addr); + ar->mac_addr[4] += ar->pdev_idx; + } } else { - ether_addr_copy(ar->mac_addr, ar->ab->mac_addr); - ar->mac_addr[4] += ar->pdev_idx; + ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b); + ath12k_info(ab, "MAC_ADDR set to %pMR", generated_macaddr.b); } ret = ath12k_mac_setup_register(ar, &ht_cap_info, hw->wiphy->bands);