Files
build/patch/kernel/archive/sm8550-6.12/9998-fix-wifi-and-bt-mac.patch
2025-03-15 10:29:56 +01:00

306 lines
8.9 KiB
Diff

From ef5a3345d6af58fbfa5d9b1ae2df11d6ac259498 Mon Sep 17 00:00:00 2001
From: spycat88 <spycat88@users.noreply.github.com>
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);