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 <[email protected]>
---
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
Karthik M <[email protected]> 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 <[email protected]>
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.
--
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches