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@xxxxxxxxxxx> --- 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(-) 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: -- 2.17.1