diff mbox series

wifi: ath12k: Encoding regdb.bin in board-2.bin

Message ID 20230131123422.24985-1-quic_karm@quicinc.com
State New
Headers show
Series wifi: ath12k: Encoding regdb.bin in board-2.bin | expand

Commit Message

Karthik M Jan. 31, 2023, 12:34 p.m. UTC
Currently regulatory database information are in regdb.bin outside
the board-2.bin.

In this implementation, Add support to encode the secured regdb.bin
in board-2.bin along with the bdf files.

New api(ath12k_core_fetch_regdb) fetches the board specific regdb
from board-2.bin. If it fails, it downloads the default regdb.

Firmware receives the binary over QMI and verifies the signing.
If it is authentic, the binary will be used.

Renumbered the enum ATH12K_BD_IE_BOARD_EXT to '2' since it is
not used in the code. ATH12K_BD_IE_REGDB enum will take the value '1'
as per the ath11k upstream design.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Karthik M <quic_karm@quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 212 +++++++++++++++++++------
 drivers/net/wireless/ath/ath12k/core.h |  23 +++
 drivers/net/wireless/ath/ath12k/hw.h   |  23 ++-
 drivers/net/wireless/ath/ath12k/qmi.c  |   6 +-
 4 files changed, 213 insertions(+), 51 deletions(-)

Comments

Kalle Valo Oct. 3, 2023, 2:56 p.m. UTC | #1
Karthik M <quic_karm@quicinc.com> wrote:

> Currently regulatory database information are in regdb.bin outside
> the board-2.bin.
> 
> In this implementation, Add support to encode the secured regdb.bin
> in board-2.bin along with the bdf files.
> 
> New api(ath12k_core_fetch_regdb) fetches the board specific regdb
> from board-2.bin. If it fails, it downloads the default regdb.
> 
> Firmware receives the binary over QMI and verifies the signing.
> If it is authentic, the binary will be used.
> 
> Renumbered the enum ATH12K_BD_IE_BOARD_EXT to '2' since it is
> not used in the code. ATH12K_BD_IE_REGDB enum will take the value '1'
> as per the ath11k upstream design.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Karthik M <quic_karm@quicinc.com>

It's a long time since I tested this and this doesn't apply anymore so I
cannot give you any detailed report. But IIRC I noticed in my test that
having just board.bin didn't work anymore. Please double check that, rebase and
submit v2.

Patch set to Changes Requested.
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index a89e66653f04..6b447244d0d3 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -83,8 +83,9 @@  int ath12k_core_resume(struct ath12k_base *ab)
 	return 0;
 }
 
-static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
-					 size_t name_len)
+static int ath12k_core_create_board_name(struct ath12k_base *ab,
+					 char *boardname,
+					 char *defaultboardname)
 {
 	/* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
 	char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
@@ -92,15 +93,70 @@  static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
 	if (ab->qmi.target.bdf_ext[0] != '\0')
 		scnprintf(variant, sizeof(variant), ",variant=%s",
 			  ab->qmi.target.bdf_ext);
+	switch (ab->id.bdf_search) {
+	case ATH12K_BDF_SEARCH_BUS_AND_BOARD:
+		if (snprintf(boardname, BOARD_NAME_SIZE,
+				     "bus=%s,vendor=%04x,device=%04x,"
+				     "subsystem-vendor=%04x,"
+				     "subsystem-device=%04x,qmi-chip-id=%d,"
+				     "qmi-board-id=%d%s",
+				     ath12k_bus_str(ab->hif.bus),
+				     ab->id.vendor, ab->id.device,
+				     ab->id.subsystem_vendor,
+				     ab->id.subsystem_device,
+				     ab->qmi.target.chip_id,
+				     ab->qmi.target.board_id,
+				     variant) >= BOARD_NAME_SIZE) {
+			ath12k_dbg(ab, ATH12K_DBG_BOOT,
+				   "buffer overflowed for boardname\n");
+			return -EOVERFLOW;
+		}
+		if (snprintf(defaultboardname, BOARD_NAME_SIZE,
+				     "bus=%s,vendor=%04x,device=%04x,"
+				     "subsystem-vendor=%04x,"
+				     "subsystem-device=%04x,qmi-chip-id=%d,"
+				     "qmi-board-id=%d%s",
+				     ath12k_bus_str(ab->hif.bus),
+				     ab->id.vendor, ab->id.device,
+				     ab->id.subsystem_vendor,
+				     ab->id.subsystem_device,
+				     ab->qmi.target.chip_id,
+				     ab->qmi.target.board_id,
+				     variant) >= BOARD_NAME_SIZE) {
+			ath12k_dbg(ab, ATH12K_DBG_BOOT,
+				   "buffer overflowed for default boardname\n");
+			return -EOVERFLOW;
+		}
+		break;
+	default:
+		if (snprintf(boardname, BOARD_NAME_SIZE,
+				     "bus=%s,qmi-chip-id=%d,"
+				     "qmi-board-id=%d%s",
+				     ath12k_bus_str(ab->hif.bus),
+				     ab->qmi.target.chip_id,
+				     ab->qmi.target.board_id,
+				     variant) >= BOARD_NAME_SIZE) {
+			ath12k_dbg(ab, ATH12K_DBG_BOOT,
+				   "buffer overflowed for boardname\n");
+			return -EOVERFLOW;
+		}
+		if (snprintf(defaultboardname, BOARD_NAME_SIZE,
+				     "bus=%s,qmi-chip-id=%d,"
+				     "qmi-board-id=%d%s",
+				     ath12k_bus_str(ab->hif.bus),
+				     ab->qmi.target.chip_id,
+				     ATH12K_DEFAULT_ID,
+				     variant) >= BOARD_NAME_SIZE) {
+			ath12k_dbg(ab, ATH12K_DBG_BOOT,
+				   "buffer overflowed for default boardname\n");
+			return -EOVERFLOW;
+		}
+		break;
+	}
 
-	scnprintf(name, name_len,
-		  "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
-		  ath12k_bus_str(ab->hif.bus),
-		  ab->qmi.target.chip_id,
-		  ab->qmi.target.board_id, variant);
-
-	ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name '%s'\n", name);
-
+	ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name : '%s'\t"
+		   "default boardname : '%s'\n", boardname,
+		   defaultboardname);
 	return 0;
 }
 
@@ -136,9 +192,7 @@  void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
 
 static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
 					 struct ath12k_board_data *bd,
-					 const void *buf, size_t buf_len,
-					 const char *boardname,
-					 int bd_ie_type)
+					 const void *buf, size_t buf_len)
 {
 	const struct ath12k_fw_ie *hdr;
 	bool name_match_found;
@@ -148,7 +202,7 @@  static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
 
 	name_match_found = false;
 
-	/* go through ATH12K_BD_IE_BOARD_ elements */
+	/* go through ATH12K_BD_IE_BOARD_/ATH12K_BD_IE_REGDB_ elements */
 	while (buf_len > sizeof(struct ath12k_fw_ie)) {
 		hdr = buf;
 		board_ie_id = le32_to_cpu(hdr->id);
@@ -159,48 +213,51 @@  static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
 		buf += sizeof(*hdr);
 
 		if (buf_len < ALIGN(board_ie_len, 4)) {
-			ath12k_err(ab, "invalid ATH12K_BD_IE_BOARD length: %zu < %zu\n",
+			ath12k_err(ab, "invalid %s length: %zu < %zu\n",
+				   ath12k_bd_ie_type_str(bd->ie_id),
 				   buf_len, ALIGN(board_ie_len, 4));
 			ret = -EINVAL;
 			goto out;
 		}
 
-		switch (board_ie_id) {
-		case ATH12K_BD_IE_BOARD_NAME:
+		if (board_ie_id == bd->name_id) {
 			ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "board name", "",
 					board_ie_data, board_ie_len);
 
-			if (board_ie_len != strlen(boardname))
-				break;
+			if (board_ie_len != strlen(bd->boardname))
+				goto next;
 
-			ret = memcmp(board_ie_data, boardname, strlen(boardname));
+			ret = memcmp(board_ie_data, bd->boardname, strlen(bd->boardname));
 			if (ret)
-				break;
+				goto next;
 
 			name_match_found = true;
 			ath12k_dbg(ab, ATH12K_DBG_BOOT,
-				   "boot found match for name '%s'",
-				   boardname);
-			break;
-		case ATH12K_BD_IE_BOARD_DATA:
+				   "boot found match %s for name '%s'",
+				   ath12k_bd_ie_type_str(bd->ie_id),
+				   bd->boardname);
+		} else if (board_ie_id == bd->data_id) {
 			if (!name_match_found)
 				/* no match found */
-				break;
+				goto next;
 
 			ath12k_dbg(ab, ATH12K_DBG_BOOT,
-				   "boot found board data for '%s'", boardname);
+				   "boot found %s for '%s'",
+				   ath12k_bd_ie_type_str(bd->ie_id),
+				   bd->boardname);
 
 			bd->data = board_ie_data;
 			bd->len = board_ie_len;
 
 			ret = 0;
 			goto out;
-		default:
-			ath12k_warn(ab, "unknown ATH12K_BD_IE_BOARD found: %d\n",
+		} else {
+			ath12k_warn(ab, "unknown %s id found: %d\n",
+				    ath12k_bd_ie_type_str(bd->ie_id),
 				    board_ie_id);
-			break;
 		}
 
+next:
 		/* jump over the padding */
 		board_ie_len = ALIGN(board_ie_len, 4);
 
@@ -216,8 +273,7 @@  static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
 }
 
 static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
-					      struct ath12k_board_data *bd,
-					      const char *boardname)
+					      struct ath12k_board_data *bd)
 {
 	size_t len, magic_len;
 	const u8 *data;
@@ -282,15 +338,12 @@  static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
 			goto err;
 		}
 
-		switch (ie_id) {
-		case ATH12K_BD_IE_BOARD:
+		if (ie_id == bd->ie_id) {
 			ret = ath12k_core_parse_bd_ie_board(ab, bd, data,
-							    ie_len,
-							    boardname,
-							    ATH12K_BD_IE_BOARD);
+							    ie_len);
 			if (ret == -ENOENT)
 				/* no match found, continue */
-				break;
+				goto next;
 			else if (ret)
 				/* there was an error, bail out */
 				goto err;
@@ -298,6 +351,7 @@  static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
 			goto out;
 		}
 
+next:
 		/* jump over the padding */
 		ie_len = ALIGN(ie_len, 4);
 
@@ -307,9 +361,10 @@  static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
 
 out:
 	if (!bd->data || !bd->len) {
-		ath12k_err(ab,
-			   "failed to fetch board data for %s from %s\n",
-			   boardname, filepath);
+		ath12k_dbg(ab, ATH12K_DBG_BOOT,
+			   "failed to fetch %s for %s from %s\n",
+			   ath12k_bd_ie_type_str(bd->ie_id),
+			   bd->boardname, filepath);
 		ret = -ENODATA;
 		goto err;
 	}
@@ -317,7 +372,8 @@  static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
 	return 0;
 
 err:
-	ath12k_core_free_bdf(ab, bd);
+	if (bd->retry)
+		ath12k_core_free_bdf(ab, bd);
 	return ret;
 }
 
@@ -326,6 +382,7 @@  int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
 				       char *filename)
 {
 	bd->fw = ath12k_core_firmware_request(ab, filename);
+
 	if (IS_ERR(bd->fw))
 		return PTR_ERR(bd->fw);
 
@@ -335,28 +392,89 @@  int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
 	return 0;
 }
 
-#define BOARD_NAME_SIZE 100
 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
 {
-	char boardname[BOARD_NAME_SIZE];
+	char boardname[BOARD_NAME_SIZE] = {0},
+	     defaultboardname[BOARD_NAME_SIZE] = {0};
 	int ret;
 
-	ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
+	ret = ath12k_core_create_board_name(ab, boardname,
+					    defaultboardname);
 	if (ret) {
 		ath12k_err(ab, "failed to create board name: %d", ret);
 		return ret;
 	}
 
 	ab->bd_api = 2;
-	ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname);
+	bd->ie_id = ATH12K_BD_IE_BOARD;
+	bd->name_id = ATH12K_BD_IE_BOARD_NAME;
+	bd->data_id = ATH12K_BD_IE_BOARD_DATA;
+	memcpy(bd->boardname, boardname, BOARD_NAME_SIZE);
+
+	ret = ath12k_core_fetch_board_data_api_n(ab, bd);
+	if (!ret)
+		goto success;
+
+	bd->retry = 1;
+	memcpy(bd->boardname, defaultboardname, BOARD_NAME_SIZE);
+
+	ret = ath12k_core_fetch_board_data_api_n(ab, bd);
 	if (!ret)
 		goto success;
 
 	ab->bd_api = 1;
 	ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_DEFAULT_BOARD_FILE);
 	if (ret) {
-		ath12k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n",
+		ath12k_err(ab, "failed to fetch board.bin from %s\n",
 			   ab->hw_params->fw.dir);
+	} else {
+		ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_BOARD_API2_FILE);
+		if (ret)
+			ath12k_err(ab, "failed to fetch board-2.bin from %s\n",
+				   ab->hw_params->fw.dir);
+		return ret;
+	}
+
+success:
+	ath12k_dbg(ab, ATH12K_DBG_BOOT, "using board api %d\n", ab->bd_api);
+	return 0;
+}
+
+int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd)
+{
+	char regdbname[BOARD_NAME_SIZE] = {0},
+	     defaultregdbname[BOARD_NAME_SIZE] = {0};
+	int ret;
+
+	ret = ath12k_core_create_board_name(ab, regdbname,
+					    defaultregdbname);
+	if (ret) {
+		ath12k_err(ab, "failed to create regdb name: %d", ret);
+		return ret;
+	}
+
+	ab->bd_api = 2;
+	bd->ie_id = ATH12K_BD_IE_REGDB;
+	bd->name_id = ATH12K_BD_IE_REGDB_NAME;
+	bd->data_id = ATH12K_BD_IE_REGDB_DATA;
+	memcpy(bd->boardname, regdbname, BOARD_NAME_SIZE);
+
+	ret = ath12k_core_fetch_board_data_api_n(ab, bd);
+	if (!ret)
+		goto success;
+
+	bd->retry = 1;
+	memcpy(bd->boardname, defaultregdbname, BOARD_NAME_SIZE);
+
+	ret = ath12k_core_fetch_board_data_api_n(ab, bd);
+	if (!ret)
+		goto success;
+
+	ab->bd_api = 1;
+	ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_REGDB_FILE_NAME);
+	if (ret) {
+		ath12k_err(ab, "failed to fetch %s file from %s\n",
+			   ATH12K_REGDB_FILE_NAME, ab->hw_params->fw.dir);
 		return ret;
 	}
 
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index a54ae74543c1..361d23406a58 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -44,6 +44,11 @@ 
 #define ATH12K_RECONFIGURE_TIMEOUT_HZ		(10 * HZ)
 #define ATH12K_RECOVER_START_TIMEOUT_HZ		(20 * HZ)
 
+enum ath12k_bdf_search {
+	ATH12K_BDF_SEARCH_DEFAULT,
+	ATH12K_BDF_SEARCH_BUS_AND_BOARD,
+};
+
 enum wme_ac {
 	WME_AC_BE,
 	WME_AC_BK,
@@ -612,10 +617,24 @@  struct ath12k_pdev {
 	struct mlo_timestamp timestamp;
 };
 
+#define BOARD_NAME_SIZE 100
 struct ath12k_board_data {
 	const struct firmware *fw;
 	const void *data;
 	size_t len;
+	char boardname[BOARD_NAME_SIZE];
+	u32 ie_id;
+	u32 name_id;
+	u32 data_id;
+	u32 retry;
+};
+
+struct vendor_info {
+	enum ath12k_bdf_search bdf_search;
+	u32 vendor;
+	u32 device;
+	u32 subsystem_vendor;
+	u32 subsystem_device;
 };
 
 struct ath12k_soc_dp_tx_err_stats {
@@ -735,6 +754,8 @@  struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct vendor_info id;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
@@ -751,6 +772,8 @@  int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
 				       char *filename);
 int ath12k_core_fetch_bdf(struct ath12k_base *ath12k,
 			  struct ath12k_board_data *bd);
+int ath12k_core_fetch_regdb(struct ath12k_base *ath12k,
+			    struct ath12k_board_data *bd);
 void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd);
 int ath12k_core_check_dt(struct ath12k_base *ath12k);
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e3461004188b..2e3108a518a3 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -81,6 +81,7 @@ 
 #define ATH12K_AMSS_FILE		"amss.bin"
 #define ATH12K_M3_FILE			"m3.bin"
 #define ATH12K_REGDB_FILE_NAME		"regdb.bin"
+#define ATH12K_DEFAULT_ID		255
 
 enum ath12k_hw_rate_cck {
 	ATH12K_HW_RATE_CCK_LP_11M = 0,
@@ -234,12 +235,32 @@  enum ath12k_bd_ie_board_type {
 	ATH12K_BD_IE_BOARD_DATA = 1,
 };
 
+enum ath12k_bd_ie_regdb_type {
+	ATH12K_BD_IE_REGDB_NAME = 0,
+	ATH12K_BD_IE_REGDB_DATA = 1,
+};
+
 enum ath12k_bd_ie_type {
 	/* contains sub IEs of enum ath12k_bd_ie_board_type */
 	ATH12K_BD_IE_BOARD = 0,
-	ATH12K_BD_IE_BOARD_EXT = 1,
+	ATH12K_BD_IE_REGDB = 1,
+	ATH12K_BD_IE_BOARD_EXT = 2,
 };
 
+static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type)
+{
+	switch (type) {
+	case ATH12K_BD_IE_BOARD:
+		return "board data";
+	case ATH12K_BD_IE_REGDB:
+		return "regdb data";
+	case ATH12K_BD_IE_BOARD_EXT:
+		return "board data ext";
+	}
+
+	return "unknown";
+}
+
 struct ath12k_hw_regs {
 	u32 hal_tcl1_ring_id;
 	u32 hal_tcl1_ring_misc;
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index 979a63f2e2ab..457ae1be41ee 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -2416,12 +2416,12 @@  static int ath12k_qmi_load_bdf_qmi(struct ath12k_base *ab,
 
 		break;
 	case ATH12K_QMI_BDF_TYPE_REGDB:
-		ret = ath12k_core_fetch_board_data_api_1(ab, &bd,
-							 ATH12K_REGDB_FILE_NAME);
+		ret = ath12k_core_fetch_regdb(ab, &bd);
 		if (ret) {
-			ath12k_warn(ab, "qmi failed to load regdb bin:\n");
+			ath12k_warn(ab, "qmi failed to load regdb:\n");
 			goto out;
 		}
+		type = ATH12K_QMI_BDF_TYPE_REGDB;
 		break;
 	case ATH12K_QMI_BDF_TYPE_CALIBRATION: