* [PATCH 4/8] rsi: change in device init frame sequence for 9116
From: Siva Rebbagondla @ 2019-04-03 4:13 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, amitkarwar, krishna.pedda, Ganapathiraju Kondraju,
Siva Rebbagondla
In-Reply-To: <20190403041309.12829-1-siva8118@gmail.com>
Initial frame exchange sequence has been changed for 9116 chip. Getting MAC
address using EEPROM read frame will be once common device configuration is
done and RESET_MAC frame is sending after bootup parameters confirmation is
received, which are different from RS9113 device
Signed-off-by: Siva Rebbagondla <siva8118@gmail.com>
---
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 38 +++++++++++++++++++------
1 file changed, 30 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 844f2fac298f..9eb60a5501a2 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1766,15 +1766,26 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n",
__func__);
if (common->fsm_state == FSM_BOOT_PARAMS_SENT) {
- adapter->eeprom.length = (IEEE80211_ADDR_LEN +
- WLAN_MAC_MAGIC_WORD_LEN +
- WLAN_HOST_MODE_LEN);
- adapter->eeprom.offset = WLAN_MAC_EEPROM_ADDR;
- if (rsi_eeprom_read(common)) {
- common->fsm_state = FSM_CARD_NOT_READY;
- goto out;
+ if (adapter->device_model == RSI_DEV_9116) {
+ common->band = NL80211_BAND_5GHZ;
+ common->num_supp_bands = 2;
+
+ if (rsi_send_reset_mac(common))
+ goto out;
+ else
+ common->fsm_state = FSM_RESET_MAC_SENT;
+ } else {
+ adapter->eeprom.length =
+ (IEEE80211_ADDR_LEN +
+ WLAN_MAC_MAGIC_WORD_LEN +
+ WLAN_HOST_MODE_LEN);
+ adapter->eeprom.offset = WLAN_MAC_EEPROM_ADDR;
+ if (rsi_eeprom_read(common)) {
+ common->fsm_state = FSM_CARD_NOT_READY;
+ goto out;
+ }
+ common->fsm_state = FSM_EEPROM_READ_MAC_ADDR;
}
- common->fsm_state = FSM_EEPROM_READ_MAC_ADDR;
} else {
rsi_dbg(INFO_ZONE,
"%s: Received bootup params cfm in %d state\n",
@@ -1936,6 +1947,17 @@ int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
case FSM_COMMON_DEV_PARAMS_SENT:
rsi_dbg(INIT_ZONE, "Card ready indication from WLAN HAL\n");
+ if (common->priv->device_model == RSI_DEV_9116) {
+ if (msg[16] != MAGIC_WORD) {
+ rsi_dbg(FSM_ZONE,
+ "%s: [EEPROM_READ] Invalid token\n",
+ __func__);
+ common->fsm_state = FSM_CARD_NOT_READY;
+ return -EINVAL;
+ }
+ memcpy(common->mac_addr, &msg[20], ETH_ALEN);
+ rsi_dbg(INIT_ZONE, "MAC Addr %pM", common->mac_addr);
+ }
/* Get usb buffer status register address */
common->priv->usb_buffer_status_reg = *(u32 *)&msg[8];
rsi_dbg(INFO_ZONE, "USB buffer status register = %x\n",
--
2.17.1
^ permalink raw reply related
* [PATCH 3/8] rsi: add firmware loading for 9116 device
From: Siva Rebbagondla @ 2019-04-03 4:13 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, amitkarwar, krishna.pedda, Ganapathiraju Kondraju,
Siva Rebbagondla
In-Reply-To: <20190403041309.12829-1-siva8118@gmail.com>
New firmware files and firmware loading method are added for 9116.
Signed-off-by: Siva Rebbagondla <siva8118@gmail.com>
---
drivers/net/wireless/rsi/rsi_91x_hal.c | 145 ++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_sdio.c | 65 +++++++++++
drivers/net/wireless/rsi/rsi_hal.h | 27 +++++
drivers/net/wireless/rsi/rsi_main.h | 1 +
drivers/net/wireless/rsi/rsi_sdio.h | 2 +-
5 files changed, 239 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index b85ffb5595bc..f84250bdb8cf 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -31,6 +31,13 @@ static struct ta_metadata metadata_flash_content[] = {
};
+static struct ta_metadata metadata[] = {{"pmemdata_dummy", 0x00000000},
+ {"rsi/rs9116_wlan.rps", 0x00000000},
+ {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000},
+ {"rsi/pmemdata_dummy", 0x00000000},
+ {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000}
+};
+
int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
{
struct rsi_hw *adapter = common->priv;
@@ -989,6 +996,133 @@ static int rsi_load_9113_firmware(struct rsi_hw *adapter)
return status;
}
+static int rsi_load_9116_firmware(struct rsi_hw *adapter)
+{
+ struct rsi_common *common = adapter->priv;
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+ const struct firmware *fw_entry;
+ struct ta_metadata *metadata_p;
+ u8 *ta_firmware, *fw_p;
+ struct bootload_ds bootload_ds;
+ u32 instructions_sz, base_address;
+ u16 block_size = adapter->block_size;
+ u32 dest, len;
+ int status, cnt;
+
+ rsi_dbg(INIT_ZONE, "***** Load 9116 TA Instructions *****\n");
+
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
+ status = bl_cmd(adapter, POLLING_MODE, CMD_PASS,
+ "POLLING_MODE");
+ if (status < 0)
+ return status;
+ }
+
+ status = hif_ops->master_reg_write(adapter, MEM_ACCESS_CTRL_FROM_HOST,
+ RAM_384K_ACCESS_FROM_TA,
+ RSI_9116_REG_SIZE);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to access full RAM memory\n",
+ __func__);
+ return status;
+ }
+
+ metadata_p = &metadata[adapter->priv->coex_mode];
+ rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name);
+ status = request_firmware(&fw_entry, metadata_p->name, adapter->device);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
+ __func__, metadata_p->name);
+ return status;
+ }
+
+ ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ if (!ta_firmware)
+ goto fail_release_fw;
+ fw_p = ta_firmware;
+ instructions_sz = fw_entry->size;
+ rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz);
+
+ common->lmac_ver.major = ta_firmware[LMAC_VER_OFFSET_9116];
+ common->lmac_ver.minor = ta_firmware[LMAC_VER_OFFSET_9116 + 1];
+ common->lmac_ver.release_num = ta_firmware[LMAC_VER_OFFSET_9116 + 2];
+ common->lmac_ver.patch_num = ta_firmware[LMAC_VER_OFFSET_9116 + 3];
+ common->lmac_ver.ver.info.fw_ver[0] =
+ ta_firmware[LMAC_VER_OFFSET_9116 + 4];
+
+ if (instructions_sz % FW_ALIGN_SIZE)
+ instructions_sz +=
+ (FW_ALIGN_SIZE - (instructions_sz % FW_ALIGN_SIZE));
+ rsi_dbg(INFO_ZONE, "instructions_sz : %d\n", instructions_sz);
+
+ if (*(u16 *)fw_p == RSI_9116_FW_MAGIC_WORD) {
+ memcpy(&bootload_ds, fw_p, sizeof(struct bootload_ds));
+ fw_p += le16_to_cpu(bootload_ds.offset);
+ rsi_dbg(INFO_ZONE, "FW start = %x\n", *(u32 *)fw_p);
+
+ cnt = 0;
+ do {
+ rsi_dbg(ERR_ZONE, "%s: Loading chunk %d\n",
+ __func__, cnt);
+
+ dest = le32_to_cpu(bootload_ds.bl_entry[cnt].dst_addr);
+ len = le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
+ RSI_BL_CTRL_LEN_MASK;
+ rsi_dbg(INFO_ZONE, "length %d destination %x\n",
+ len, dest);
+
+ status = hif_ops->load_data_master_write(adapter, dest,
+ len,
+ block_size,
+ fw_p);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "Failed to load chunk %d\n", cnt);
+ break;
+ }
+ fw_p += len;
+ if (le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
+ RSI_BL_CTRL_LAST_ENTRY)
+ break;
+ cnt++;
+ } while (1);
+ } else {
+ base_address = metadata_p->address;
+ status = hif_ops->load_data_master_write(adapter,
+ base_address,
+ instructions_sz,
+ block_size,
+ ta_firmware);
+ }
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to load %s blk\n",
+ __func__, metadata_p->name);
+ goto fail_free_fw;
+ }
+
+ rsi_dbg(INIT_ZONE, "%s: Successfully loaded %s instructions\n",
+ __func__, metadata_p->name);
+
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) {
+ if (hif_ops->ta_reset(adapter))
+ rsi_dbg(ERR_ZONE, "Unable to put ta in reset\n");
+ } else {
+ if (bl_cmd(adapter, JUMP_TO_ZERO_PC,
+ CMD_PASS, "JUMP_TO_ZERO") < 0)
+ rsi_dbg(INFO_ZONE, "Jump to zero command failed\n");
+ else
+ rsi_dbg(INFO_ZONE, "Jump to zero command successful\n");
+ }
+
+fail_free_fw:
+ kfree(ta_firmware);
+fail_release_fw:
+ release_firmware(fw_entry);
+
+ return status;
+}
+
int rsi_hal_device_init(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
@@ -1006,6 +1140,17 @@ int rsi_hal_device_init(struct rsi_hw *adapter)
return -EINVAL;
}
break;
+ case RSI_DEV_9116:
+ status = rsi_hal_prepare_fwload(adapter);
+ if (status < 0)
+ return status;
+ if (rsi_load_9116_firmware(adapter)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to load firmware to 9116 device\n",
+ __func__);
+ return -EINVAL;
+ }
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 2f4bc25d93ca..e9a2af0a1a80 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -923,6 +923,70 @@ static int rsi_sdio_reinit_device(struct rsi_hw *adapter)
return 0;
}
+static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
+{
+ int status;
+ u32 addr;
+ u8 *data;
+
+ status = rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "Unable to set ms word to common reg\n");
+ return status;
+ }
+
+ rsi_dbg(INIT_ZONE, "%s: Bring TA out of reset\n", __func__);
+ put_unaligned_le32(TA_HOLD_THREAD_VALUE, data);
+ addr = TA_HOLD_THREAD_REG | RSI_SD_REQUEST_MASTER;
+ status = rsi_sdio_write_register_multiple(adapter, addr,
+ (u8 *)&data,
+ RSI_9116_REG_SIZE);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "Unable to hold TA threads\n");
+ return status;
+ }
+
+ put_unaligned_le32(TA_SOFT_RST_CLR, data);
+ addr = TA_SOFT_RESET_REG | RSI_SD_REQUEST_MASTER;
+ status = rsi_sdio_write_register_multiple(adapter, addr,
+ (u8 *)&data,
+ RSI_9116_REG_SIZE);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "Unable to get TA out of reset\n");
+ return status;
+ }
+
+ put_unaligned_le32(TA_PC_ZERO, data);
+ addr = TA_TH0_PC_REG | RSI_SD_REQUEST_MASTER;
+ status = rsi_sdio_write_register_multiple(adapter, addr,
+ (u8 *)&data,
+ RSI_9116_REG_SIZE);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "Unable to Reset TA PC value\n");
+ return -EINVAL;
+ }
+
+ put_unaligned_le32(TA_RELEASE_THREAD_VALUE, data);
+ addr = TA_RELEASE_THREAD_REG | RSI_SD_REQUEST_MASTER;
+ status = rsi_sdio_write_register_multiple(adapter, addr,
+ (u8 *)&data,
+ RSI_9116_REG_SIZE);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "Unable to release TA threads\n");
+ return status;
+ }
+
+ status = rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n");
+ return status;
+ }
+ rsi_dbg(INIT_ZONE, "***** TA Reset done *****\n");
+
+ return 0;
+}
+
static struct rsi_host_intf_ops sdio_host_intf_ops = {
.write_pkt = rsi_sdio_host_intf_write_pkt,
.read_pkt = rsi_sdio_host_intf_read_pkt,
@@ -933,6 +997,7 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = {
.master_reg_write = rsi_sdio_master_reg_write,
.load_data_master_write = rsi_sdio_load_data_master_write,
.reinit_device = rsi_sdio_reinit_device,
+ .ta_reset = rsi_sdio_ta_reset,
};
/**
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
index f6dc55625516..c07b1a006d3f 100644
--- a/drivers/net/wireless/rsi/rsi_hal.h
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -114,8 +114,17 @@
#define FW_FLASH_OFFSET 0x820
#define LMAC_VER_OFFSET_9113 (FW_FLASH_OFFSET + 0x200)
+#define LMAC_VER_OFFSET_9116 0x22C2
#define MAX_DWORD_ALIGN_BYTES 64
#define RSI_COMMON_REG_SIZE 2
+#define RSI_9116_REG_SIZE 4
+#define FW_ALIGN_SIZE 4
+#define RSI_9116_FW_MAGIC_WORD 0x5aa5
+
+#define MEM_ACCESS_CTRL_FROM_HOST 0x41300000
+#define RAM_384K_ACCESS_FROM_TA (BIT(2) | BIT(3) | BIT(4) | BIT(5) | \
+ BIT(20) | BIT(21) | BIT(22) | \
+ BIT(23) | BIT(24) | BIT(25))
struct bl_header {
__le32 flags;
@@ -130,6 +139,24 @@ struct ta_metadata {
unsigned int address;
};
+#define RSI_BL_CTRL_LEN_MASK 0xFFFFFF
+#define RSI_BL_CTRL_SPI_32BIT_MODE BIT(27)
+#define RSI_BL_CTRL_REL_TA_SOFTRESET BIT(28)
+#define RSI_BL_CTRL_START_FROM_ROM_PC BIT(29)
+#define RSI_BL_CTRL_SPI_8BIT_MODE BIT(30)
+#define RSI_BL_CTRL_LAST_ENTRY BIT(31)
+struct bootload_entry {
+ __le32 control;
+ __le32 dst_addr;
+} __packed;
+
+struct bootload_ds {
+ __le16 fixed_pattern;
+ __le16 offset;
+ __le32 reserved;
+ struct bootload_entry bl_entry[7];
+} __packed;
+
struct rsi_mgmt_desc {
__le16 len_qno;
u8 frame_type;
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 077cc97dbe6f..e35c6e5151c3 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -385,6 +385,7 @@ struct rsi_host_intf_ops {
u32 instructions_size, u16 block_size,
u8 *fw);
int (*reinit_device)(struct rsi_hw *adapter);
+ int (*ta_reset)(struct rsi_hw *adapter);
};
enum rsi_host_intf rsi_get_host_intf(void *priv);
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index 838e929f7235..c5cfb6238f73 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -92,7 +92,7 @@ enum sdio_interrupt_type {
#define TA_SOFT_RST_SET BIT(0)
#define TA_PC_ZERO 0
#define TA_HOLD_THREAD_VALUE 0xF
-#define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF)
+#define TA_RELEASE_THREAD_VALUE 0xF
#define TA_BASE_ADDR 0x2200
#define MISC_CFG_BASE_ADDR 0x4105
--
2.17.1
^ permalink raw reply related
* [PATCH 2/8] rsi: move common part of firmware load to separate function
From: Siva Rebbagondla @ 2019-04-03 4:13 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, amitkarwar, krishna.pedda, Ganapathiraju Kondraju,
Siva Rebbagondla
In-Reply-To: <20190403041309.12829-1-siva8118@gmail.com>
Till software bootloader ready state, communication with device is common
for 9113 and 9116. Hence moved that part of firmware loading to separate
function rsi_prepare_fw_load(). Also LMAC_VER_OFFSET is different for 9113
and 9116, so renamed existing macro to LMAC_VER_OFFSET_9113
Signed-off-by: Siva Rebbagondla <siva8118@gmail.com>
---
drivers/net/wireless/rsi/rsi_91x_hal.c | 54 +++++++++++++++++---------
drivers/net/wireless/rsi/rsi_hal.h | 2 +-
2 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 1dbaab2a96b7..b85ffb5595bc 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -829,21 +829,18 @@ static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content,
return 0;
}
-static int rsi_load_firmware(struct rsi_hw *adapter)
+static int rsi_hal_prepare_fwload(struct rsi_hw *adapter)
{
- struct rsi_common *common = adapter->priv;
struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
- const struct firmware *fw_entry = NULL;
- u32 regout_val = 0, content_size;
- u16 tmp_regout_val = 0;
- struct ta_metadata *metadata_p;
+ u32 regout_val = 0;
int status;
bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
while (!adapter->blcmd_timer_expired) {
status = hif_ops->master_reg_read(adapter, SWBL_REGOUT,
- ®out_val, 2);
+ ®out_val,
+ RSI_COMMON_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE,
"%s: REGOUT read failed\n", __func__);
@@ -865,13 +862,26 @@ static int rsi_load_firmware(struct rsi_hw *adapter)
(regout_val & 0xff));
status = hif_ops->master_reg_write(adapter, SWBL_REGOUT,
- (REGOUT_INVALID | REGOUT_INVALID << 8),
- 2);
- if (status < 0) {
+ (REGOUT_INVALID |
+ REGOUT_INVALID << 8),
+ RSI_COMMON_REG_SIZE);
+ if (status < 0)
rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__);
- return status;
- }
- mdelay(1);
+ else
+ rsi_dbg(INFO_ZONE,
+ "===> Device is ready to load firmware <===\n");
+
+ return status;
+}
+
+static int rsi_load_9113_firmware(struct rsi_hw *adapter)
+{
+ struct rsi_common *common = adapter->priv;
+ const struct firmware *fw_entry = NULL;
+ u32 content_size;
+ u16 tmp_regout_val = 0;
+ struct ta_metadata *metadata_p;
+ int status;
status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS,
"AUTO_READ_CMD");
@@ -902,13 +912,15 @@ static int rsi_load_firmware(struct rsi_hw *adapter)
/* Get the firmware version */
common->lmac_ver.ver.info.fw_ver[0] =
- fw_entry->data[LMAC_VER_OFFSET] & 0xFF;
+ fw_entry->data[LMAC_VER_OFFSET_9113] & 0xFF;
common->lmac_ver.ver.info.fw_ver[1] =
- fw_entry->data[LMAC_VER_OFFSET + 1] & 0xFF;
- common->lmac_ver.major = fw_entry->data[LMAC_VER_OFFSET + 2] & 0xFF;
+ fw_entry->data[LMAC_VER_OFFSET_9113 + 1] & 0xFF;
+ common->lmac_ver.major =
+ fw_entry->data[LMAC_VER_OFFSET_9113 + 2] & 0xFF;
common->lmac_ver.release_num =
- fw_entry->data[LMAC_VER_OFFSET + 3] & 0xFF;
- common->lmac_ver.minor = fw_entry->data[LMAC_VER_OFFSET + 4] & 0xFF;
+ fw_entry->data[LMAC_VER_OFFSET_9113 + 3] & 0xFF;
+ common->lmac_ver.minor =
+ fw_entry->data[LMAC_VER_OFFSET_9113 + 4] & 0xFF;
common->lmac_ver.patch_num = 0;
rsi_print_version(common);
@@ -980,10 +992,14 @@ static int rsi_load_firmware(struct rsi_hw *adapter)
int rsi_hal_device_init(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
+ int status;
switch (adapter->device_model) {
case RSI_DEV_9113:
- if (rsi_load_firmware(adapter)) {
+ status = rsi_hal_prepare_fwload(adapter);
+ if (status < 0)
+ return status;
+ if (rsi_load_9113_firmware(adapter)) {
rsi_dbg(ERR_ZONE,
"%s: Failed to load TA instructions\n",
__func__);
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
index 327638cdd30b..f6dc55625516 100644
--- a/drivers/net/wireless/rsi/rsi_hal.h
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -113,7 +113,7 @@
#define BBP_INFO_40MHZ 0x6
#define FW_FLASH_OFFSET 0x820
-#define LMAC_VER_OFFSET (FW_FLASH_OFFSET + 0x200)
+#define LMAC_VER_OFFSET_9113 (FW_FLASH_OFFSET + 0x200)
#define MAX_DWORD_ALIGN_BYTES 64
#define RSI_COMMON_REG_SIZE 2
--
2.17.1
^ permalink raw reply related
* [PATCH 1/8] rsi: add new device model for 9116
From: Siva Rebbagondla @ 2019-04-03 4:13 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, amitkarwar, krishna.pedda, Ganapathiraju Kondraju,
Siva Rebbagondla
In-Reply-To: <20190403041309.12829-1-siva8118@gmail.com>
9116 device id entry is added in both SDIO and USB interfaces.
New enumberation value taken for the device model. Based on the
device model detected run time, few device specific operations
needs to be performed.
adding rsi_dev_model to get device type in run time, as we can use
same driver for 9113 and 9116 except few firmware load changes.
Signed-off-by: Siva Rebbagondla <siva8118@gmail.com>
---
drivers/net/wireless/rsi/rsi_91x_sdio.c | 19 +++++++++++++++++--
drivers/net/wireless/rsi/rsi_91x_usb.c | 15 ++++++++++++++-
drivers/net/wireless/rsi/rsi_main.h | 8 ++++++--
drivers/net/wireless/rsi/rsi_sdio.h | 3 ++-
drivers/net/wireless/rsi/rsi_usb.h | 3 ++-
5 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 3430d7a0899e..2f4bc25d93ca 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -949,7 +949,7 @@ static int rsi_probe(struct sdio_func *pfunction,
{
struct rsi_hw *adapter;
struct rsi_91x_sdiodev *sdev;
- int status;
+ int status = -EINVAL;
rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
@@ -968,6 +968,20 @@ static int rsi_probe(struct sdio_func *pfunction,
status = -EIO;
goto fail_free_adapter;
}
+
+ if (pfunction->device == RSI_SDIO_PID_9113) {
+ rsi_dbg(ERR_ZONE, "%s: 9113 module detected\n", __func__);
+ adapter->device_model = RSI_DEV_9113;
+ } else if (pfunction->device == RSI_SDIO_PID_9116) {
+ rsi_dbg(ERR_ZONE, "%s: 9116 module detected\n", __func__);
+ adapter->device_model = RSI_DEV_9116;
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unsupported RSI device id 0x%x\n", __func__,
+ pfunction->device);
+ goto fail_free_adapter;
+ }
+
sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
rsi_init_event(&sdev->rx_thread.event);
status = rsi_create_kthread(adapter->priv, &sdev->rx_thread,
@@ -1415,7 +1429,8 @@ static const struct dev_pm_ops rsi_pm_ops = {
#endif
static const struct sdio_device_id rsi_dev_table[] = {
- { SDIO_DEVICE(RSI_SDIO_VID_9113, RSI_SDIO_PID_9113) },
+ { SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9113) },
+ { SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9116) },
{ /* Blank */},
};
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index ac0ef5ea6ffb..7d9b85925150 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -763,6 +763,18 @@ static int rsi_probe(struct usb_interface *pfunction,
rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__);
+ if (id && id->idProduct == RSI_USB_PID_9113) {
+ rsi_dbg(INIT_ZONE, "%s: 9113 module detected\n", __func__);
+ adapter->device_model = RSI_DEV_9113;
+ } else if (id && id->idProduct == RSI_USB_PID_9116) {
+ rsi_dbg(INIT_ZONE, "%s: 9116 module detected\n", __func__);
+ adapter->device_model = RSI_DEV_9116;
+ } else {
+ rsi_dbg(ERR_ZONE, "%s: Unsupported RSI device id 0x%x\n",
+ __func__, id->idProduct);
+ goto err1;
+ }
+
dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2);
@@ -845,7 +857,8 @@ static int rsi_resume(struct usb_interface *intf)
#endif
static const struct usb_device_id rsi_dev_table[] = {
- { USB_DEVICE(RSI_USB_VID_9113, RSI_USB_PID_9113) },
+ { USB_DEVICE(RSI_USB_VENDOR_ID, RSI_USB_PID_9113) },
+ { USB_DEVICE(RSI_USB_VENDOR_ID, RSI_USB_PID_9116) },
{ /* Blank */},
};
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 35d13f35e9b0..077cc97dbe6f 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -111,9 +111,13 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define RSI_WOW_ENABLED BIT(0)
#define RSI_WOW_NO_CONNECTION BIT(1)
-#define RSI_DEV_9113 1
#define RSI_MAX_RX_PKTS 64
+enum rsi_dev_model {
+ RSI_DEV_9113 = 0,
+ RSI_DEV_9116
+};
+
struct version_info {
u16 major;
u16 minor;
@@ -329,7 +333,7 @@ struct eeprom_read {
struct rsi_hw {
struct rsi_common *priv;
- u8 device_model;
+ enum rsi_dev_model device_model;
struct ieee80211_hw *hw;
struct ieee80211_vif *vifs[RSI_MAX_VIFS];
struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES];
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index 66dcd2ec9051..838e929f7235 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -28,8 +28,9 @@
#include <linux/mmc/sdio_ids.h>
#include "rsi_main.h"
-#define RSI_SDIO_VID_9113 0x041B
+#define RSI_SDIO_VENDOR_ID 0x041B
#define RSI_SDIO_PID_9113 0x9330
+#define RSI_SDIO_PID_9116 0x9116
enum sdio_interrupt_type {
BUFFER_FULL = 0x0,
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index 5b2eddd1a2ee..8702f434b569 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -22,8 +22,9 @@
#include "rsi_main.h"
#include "rsi_common.h"
-#define RSI_USB_VID_9113 0x1618
+#define RSI_USB_VENDOR_ID 0x1618
#define RSI_USB_PID_9113 0x9113
+#define RSI_USB_PID_9116 0x9116
#define USB_INTERNAL_REG_1 0x25000
#define RSI_USB_READY_MAGIC_NUM 0xab
--
2.17.1
^ permalink raw reply related
* [PATCH 0/8] rsi: driver changes for new 9116 chipset.
From: Siva Rebbagondla @ 2019-04-03 4:13 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, amitkarwar, krishna.pedda, Ganapathiraju Kondraju,
Siva Rebbagondla
This series of patches consists driver changes for new redpine
9116 chipset and some miscallaneous changes.
Siva Rebbagondla (8):
rsi: add new device model for 9116
rsi: move common part of firmware load to separate function
rsi: add firmware loading for 9116 device
rsi: change in device init frame sequence for 9116
rsi: new bootup parameters for 9116
rsi: send new tx command frame wlan9116 features
rsi: reset device changes for 9116
rsi: miscallaneous changes for 9116 and common
drivers/net/wireless/rsi/rsi_91x_hal.c | 199 ++++++++++++++++--
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 232 +++++++++++++++++++--
drivers/net/wireless/rsi/rsi_91x_sdio.c | 129 ++++++++++--
drivers/net/wireless/rsi/rsi_91x_usb.c | 96 ++++++---
drivers/net/wireless/rsi/rsi_boot_params.h | 63 ++++++
drivers/net/wireless/rsi/rsi_hal.h | 44 +++-
drivers/net/wireless/rsi/rsi_main.h | 21 +-
drivers/net/wireless/rsi/rsi_mgmt.h | 26 +++
drivers/net/wireless/rsi/rsi_sdio.h | 5 +-
drivers/net/wireless/rsi/rsi_usb.h | 3 +-
10 files changed, 732 insertions(+), 86 deletions(-)
--
2.17.1
^ permalink raw reply
* [PATCH] ath10k: add peer id check in ath10k_peer_find_by_id
From: Wen Gong @ 2019-04-03 3:01 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
For some SDIO chip, the peer id is 65535 for MPDU with error status,
then test_bit will trigger buffer overflow for peer's memory, if kasan
enabled, it will report error.
Add check for overflow the size of peer's peer_ids will avoid the buffer
overflow access.
Call trace of kasan:
dump_backtrace+0x0/0x2ec
show_stack+0x20/0x2c
__dump_stack+0x20/0x28
dump_stack+0xc8/0xec
print_address_description+0x74/0x240
kasan_report+0x250/0x26c
__asan_report_load8_noabort+0x20/0x2c
ath10k_peer_find_by_id+0x180/0x1e4 [ath10k_core]
ath10k_htt_t2h_msg_handler+0x100c/0x2fd4 [ath10k_core]
ath10k_htt_htc_t2h_msg_handler+0x20/0x34 [ath10k_core]
ath10k_sdio_irq_handler+0xcc8/0x1678 [ath10k_sdio]
process_sdio_pending_irqs+0xec/0x370
sdio_run_irqs+0x68/0xe4
sdio_irq_work+0x1c/0x28
process_one_work+0x3d8/0x8b0
worker_thread+0x508/0x7cc
kthread+0x24c/0x264
ret_from_fork+0x10/0x18
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
drivers/net/wireless/ath/ath10k/txrx.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 23606b6..33de9e1 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -157,6 +157,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)
{
struct ath10k_peer *peer;
+ if (peer_id >= sizeof(peer->peer_ids) * BITS_PER_BYTE)
+ return NULL;
+
lockdep_assert_held(&ar->data_lock);
list_for_each_entry(peer, &ar->peers, list)
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v4 3/3] ath10k: add support for controlling tx power to a station
From: Bob Copeland @ 2019-04-02 22:37 UTC (permalink / raw)
To: Balaji Pothunoori; +Cc: johannes, ath10k, linux-wireless, Ashok Raj Nagarajan
In-Reply-To: <1553856587-21611-1-git-send-email-bpothuno@codeaurora.org>
On Fri, Mar 29, 2019 at 04:19:47PM +0530, Balaji Pothunoori wrote:
> From: Ashok Raj Nagarajan <arnagara@codeaurora.org>
>
> This patch will add the support to control the transmit power for traffic
> to a station associated with the AP.
>
> Underlying firmware will enforce that the maximum tx power will be based
> on the regulatory requirements. If the user given transmit power is greater
> than the allowed tx power in the given channel, then the firmware will use
> the maximum tx power in the same channel.
>
> When 0 is sent to the firmware as tx power, it will revert to the default
> tx power for the station.
>
> Tested Hardware : QCA9984
> Tested Firmware : 10.4-3.9.0.1-00013
I tried this on qca9984 with 10.4-3.9.0.2-00040, which claims to support
this feature, and it didn't seem to work:
- with global tx power limit set to 30 dBm, I started an iperf from station
A -> B
- while iperf underway, I did tcpdump on a monitor on B and looked at signal
level in radiotap, in this case around -75 dBm
- on A, changed the per-sta txpwr limit for B to something (tried as low as
1 dBm). verified via printk that it went through to the driver / firmware
command and reported no error
-> result: signal level unchanged
- on A, changed the global tx power limit to 1 dBm
-> result: signal level dropped to ~ -95 dBm
Reading the description above, now I'm wondering if the txpower is
max(sta-power,global-power)? If so, that seems a bit unintuitive to me,
or at least isn't what I hoped for. I'd prefer to have per-sta power
setting override the global power.
--
Bob Copeland %% https://bobcopeland.com/
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: Sebastian Gottschall @ 2019-04-02 16:33 UTC (permalink / raw)
To: John Crispin, Johannes Berg, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <204cbbd7-fefc-52da-bd0f-c1302d609682@phrozen.org>
take care about dealing with it. my first private attempt crashed
everything :-)
Am 02.04.2019 um 16:39 schrieb John Crispin:
>
> On 02/04/2019 11:31, Sebastian Gottschall wrote:
>> the introduced control field hw_80211_encap in ieee80211_tx_info
>> leads to a compile assert
>> /include/linux/compiler.h:522:38: error: call to
>> '__compiletime_assert_1307' declared with attribute error:
>> BUILD_BUG_ON failed: sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)
>>
>> skb->cb is to small on x64 devices
>> i suggest to implement hw_80211_encap in ieee80211_vif which is a
>> member of control in ieee80211_tx_info
>>
>> Sebastian
>
> Hi Sebastian,
>
> stumbled across that aswell while testing on arm64 today. I'll fix it
> in V4, Thanks
>
> John
>
>
>>
>> Am 01.04.2019 um 15:14 schrieb John Crispin:
>>> From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
>>>
>>> This patch adds a new transmit path for hardware that supports 802.11
>>> encapsulation offloading. In those cases 802.3a frames get passed
>>> directly to the driver allowing to hardware to handle the
>>> encapsulation.
>>>
>>> Certain features wont work and the patch masks these out.
>>> * monitor interfaces are not supported if any of the vif is in encap
>>> mode.
>>> * amsdu/non-linear frames wont work in encap offloading mode.
>>> * TKIP countermeasures cannot be triggered and hence those keys are not
>>> accepted.
>>>
>>> The patch defines a secondary netdev_ops struct that the device is
>>> assigned
>>> to the device if 802.11 encap support is available and enabled. The
>>> driver
>>> needs to enable the support on a per vif basis if it finds that all
>>> pre-reqs are meet.
>>>
>>> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
>>> Signed-off-by: John Crispin <john@phrozen.org>
>>> ---
>>> include/net/mac80211.h | 25 ++++++
>>> net/mac80211/cfg.c | 12 ++-
>>> net/mac80211/debugfs.c | 1 +
>>> net/mac80211/ieee80211_i.h | 10 +++
>>> net/mac80211/iface.c | 54 +++++++++++++
>>> net/mac80211/key.c | 3 +
>>> net/mac80211/main.c | 10 ++-
>>> net/mac80211/status.c | 79 +++++++++++++++++++
>>> net/mac80211/tx.c | 188
>>> +++++++++++++++++++++++++++++++++++++++++++--
>>> 9 files changed, 373 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
>>> index ac2ed8ec662b..3e8929770839 100644
>>> --- a/include/net/mac80211.h
>>> +++ b/include/net/mac80211.h
>>> @@ -1021,6 +1021,7 @@ struct ieee80211_tx_info {
>>> struct ieee80211_key_conf *hw_key;
>>> u32 flags;
>>> codel_time_t enqueue_time;
>>> + u8 hw_80211_encap;
>>> } control;
>>> struct {
>>> u64 cookie;
>>> @@ -2243,6 +2244,9 @@ struct ieee80211_txq {
>>> * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports
>>> multi BSSID
>>> * only for HE APs. Applies if
>>> @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
>>> *
>>> + * @IEEE80211_HW_SUPPORTS_80211_ENCAP: Hardware/driver supports 802.11
>>> + * encap for data frames.
>>> + *
>>> * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for
>>> sizing arrays
>>> */
>>> enum ieee80211_hw_flags {
>>> @@ -2294,6 +2298,7 @@ enum ieee80211_hw_flags {
>>> IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
>>> IEEE80211_HW_SUPPORTS_MULTI_BSSID,
>>> IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
>>> + IEEE80211_HW_SUPPORTS_80211_ENCAP,
>>> /* keep last, obviously */
>>> NUM_IEEE80211_HW_FLAGS
>>> @@ -4587,6 +4592,25 @@ void ieee80211_tx_status_irqsafe(struct
>>> ieee80211_hw *hw,
>>> struct sk_buff *skb);
>>> /**
>>> + * ieee80211_tx_status_8023 - transmit status callback for 802.3
>>> frame format
>>> + *
>>> + * Call this function for all transmitted data frames after their
>>> transmit
>>> + * completion. This callback should only be called for data frames
>>> which
>>> + * are are using driver's (or hardware's) offload capability of
>>> encap/decap
>>> + * 802.11 frames.
>>> + *
>>> + * This function may not be called in IRQ context. Calls to this
>>> function
>>> + * for a single hardware must be synchronized against each other.
>>> + *
>>> + * @hw: the hardware the frame was transmitted by
>>> + * @vif: the interface for which the frame was transmitted
>>> + * @skb: the frame that was transmitted, owned by mac80211 after
>>> this call
>>> + */
>>> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
>>> + struct ieee80211_vif *vif,
>>> + struct sk_buff *skb);
>>> +
>>> +/**
>>> * ieee80211_report_low_ack - report non-responding station
>>> *
>>> * When operating in AP-mode, call this function to report a
>>> non-responding
>>> @@ -6359,4 +6383,5 @@ void ieee80211_nan_func_match(struct
>>> ieee80211_vif *vif,
>>> struct cfg80211_nan_match_params *match,
>>> gfp_t gfp);
>>> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool
>>> enable);
>>> #endif /* MAC80211_H */
>>> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
>>> index 09dd1c2860fc..53b56f8fcdfc 100644
>>> --- a/net/mac80211/cfg.c
>>> +++ b/net/mac80211/cfg.c
>>> @@ -367,8 +367,15 @@ static int ieee80211_add_key(struct wiphy
>>> *wiphy, struct net_device *dev,
>>> /* reject WEP and TKIP keys if WEP failed to initialize */
>>> switch (params->cipher) {
>>> - case WLAN_CIPHER_SUITE_WEP40:
>>> case WLAN_CIPHER_SUITE_TKIP:
>>> + /* countermeasures wont work on encap offload mode so reject
>>> + * TKIP keys
>>> + */
>>> + if (ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
>>> + return -EINVAL;
>>> +
>>> + /* drop through */
>>> + case WLAN_CIPHER_SUITE_WEP40:
>>> case WLAN_CIPHER_SUITE_WEP104:
>>> if (IS_ERR(local->wep_tx_tfm))
>>> return -EINVAL;
>>> @@ -2379,6 +2386,9 @@ static int ieee80211_set_wiphy_params(struct
>>> wiphy *wiphy, u32 changed)
>>> if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
>>> ieee80211_check_fast_xmit_all(local);
>>> + if (ieee80211_is_hw_80211_encap(local))
>>> + return -EINVAL;
>>> +
>>> err = drv_set_frag_threshold(local, wiphy->frag_threshold);
>>> if (err) {
>>> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
>>> index 2d43bc127043..a4df6bca192f 100644
>>> --- a/net/mac80211/debugfs.c
>>> +++ b/net/mac80211/debugfs.c
>>> @@ -221,6 +221,7 @@ static const char *hw_flag_names[] = {
>>> FLAG(TX_STATUS_NO_AMPDU_LEN),
>>> FLAG(SUPPORTS_MULTI_BSSID),
>>> FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
>>> + FLAG(SUPPORTS_80211_ENCAP),
>>> #undef FLAG
>>> };
>>> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
>>> index e170f986d226..d7569a455a06 100644
>>> --- a/net/mac80211/ieee80211_i.h
>>> +++ b/net/mac80211/ieee80211_i.h
>>> @@ -987,6 +987,8 @@ struct ieee80211_sub_if_data {
>>> } debugfs;
>>> #endif
>>> + bool hw_80211_encap;
>>> +
>>> /* must be last, dynamically sized area in this! */
>>> struct ieee80211_vif vif;
>>> };
>>> @@ -1732,6 +1734,7 @@ int ieee80211_if_add(struct ieee80211_local
>>> *local, const char *name,
>>> struct vif_params *params);
>>> int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
>>> enum nl80211_iftype type);
>>> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local);
>>> void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
>>> void ieee80211_remove_interfaces(struct ieee80211_local *local);
>>> u32 ieee80211_idle_off(struct ieee80211_local *local);
>>> @@ -1759,6 +1762,8 @@ netdev_tx_t
>>> ieee80211_monitor_start_xmit(struct sk_buff *skb,
>>> struct net_device *dev);
>>> netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
>>> struct net_device *dev);
>>> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
>>> + struct net_device *dev);
>>> void __ieee80211_subif_start_xmit(struct sk_buff *skb,
>>> struct net_device *dev,
>>> u32 info_flags);
>>> @@ -1933,6 +1938,11 @@ void __ieee80211_tx_skb_tid_band(struct
>>> ieee80211_sub_if_data *sdata,
>>> struct sk_buff *skb, int tid,
>>> enum nl80211_band band, u32 txdata_flags);
>>> +/* sta_out needs to be checked for ERR_PTR() before using */
>>> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
>>> + struct sk_buff *skb,
>>> + struct sta_info **sta_out);
>>> +
>>> static inline void
>>> ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
>>> struct sk_buff *skb, int tid,
>>> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
>>> index 4a6ff1482a9f..4090c2c5fde0 100644
>>> --- a/net/mac80211/iface.c
>>> +++ b/net/mac80211/iface.c
>>> @@ -1177,6 +1177,59 @@ static const struct net_device_ops
>>> ieee80211_dataif_ops = {
>>> .ndo_get_stats64 = ieee80211_get_stats64,
>>> };
>>> +static const struct net_device_ops ieee80211_dataif_8023_ops = {
>>> + .ndo_open = ieee80211_open,
>>> + .ndo_stop = ieee80211_stop,
>>> + .ndo_uninit = ieee80211_uninit,
>>> + .ndo_start_xmit = ieee80211_subif_start_xmit_8023,
>>> + .ndo_set_rx_mode = ieee80211_set_multicast_list,
>>> + .ndo_set_mac_address = ieee80211_change_mac,
>>> + .ndo_select_queue = ieee80211_netdev_select_queue,
>>> + .ndo_get_stats64 = ieee80211_get_stats64,
>>> +};
>>> +
>>> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool
>>> enable)
>>> +{
>>> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
>>> + struct ieee80211_local *local = sdata->local;
>>> +
>>> + if (!sdata->dev)
>>> + return;
>>> +
>>> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
>>> + enable = 0;
>>> +
>>> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
>>> + (local->hw.wiphy->frag_threshold != (u32)-1))
>>> + enable = 0;
>>> +
>>> + if (enable) {
>>> + sdata->dev->netdev_ops = &ieee80211_dataif_8023_ops;
>>> + sdata->hw_80211_encap = true;
>>> + } else {
>>> + sdata->dev->netdev_ops = &ieee80211_dataif_ops;
>>> + sdata->hw_80211_encap = false;
>>> + }
>>> +}
>>> +EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
>>> +
>>> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local)
>>> +{
>>> + struct ieee80211_sub_if_data *sdata;
>>> + bool offloaded = false;
>>> +
>>> + mutex_lock(&local->iflist_mtx);
>>> + list_for_each_entry(sdata, &local->interfaces, list) {
>>> + if (sdata->hw_80211_encap) {
>>> + offloaded = true;
>>> + break;
>>> + }
>>> + }
>>> + mutex_unlock(&local->iflist_mtx);
>>> +
>>> + return offloaded;
>>> +}
>>> +
>>> static u16 ieee80211_monitor_select_queue(struct net_device *dev,
>>> struct sk_buff *skb,
>>> struct net_device *sb_dev,
>>> @@ -1409,6 +1462,7 @@ static void ieee80211_setup_sdata(struct
>>> ieee80211_sub_if_data *sdata,
>>> sdata->vif.bss_conf.idle = true;
>>> sdata->noack_map = 0;
>>> + sdata->hw_80211_encap = false;
>>> /* only monitor/p2p-device differ */
>>> if (sdata->dev) {
>>> diff --git a/net/mac80211/key.c b/net/mac80211/key.c
>>> index 4700718e010f..861b67d43eb7 100644
>>> --- a/net/mac80211/key.c
>>> +++ b/net/mac80211/key.c
>>> @@ -197,6 +197,9 @@ static int ieee80211_key_enable_hw_accel(struct
>>> ieee80211_key *key)
>>> key->conf.keyidx,
>>> sta ? sta->sta.addr : bcast_addr, ret);
>>> + if (sdata->hw_80211_encap)
>>> + return -EINVAL;
>>> +
>>> out_unsupported:
>>> switch (key->conf.cipher) {
>>> case WLAN_CIPHER_SUITE_WEP40:
>>> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
>>> index 800e67615e2a..a49bcec3891e 100644
>>> --- a/net/mac80211/main.c
>>> +++ b/net/mac80211/main.c
>>> @@ -1000,9 +1000,13 @@ int ieee80211_register_hw(struct ieee80211_hw
>>> *hw)
>>> hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
>>> }
>>> - /* mac80211 always supports monitor */
>>> - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
>>> - hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
>>> + if (ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)) {
>>> + /* mac80211 always supports monitor unless we do 802.11
>>> + * encapsulation offloading.
>>> + */
>>> + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
>>> + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
>>> + }
>>> /* mac80211 doesn't support more than one IBSS interface
>>> right now */
>>> for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
>>> diff --git a/net/mac80211/status.c b/net/mac80211/status.c
>>> index 5b9952b1caf3..8feafaab88a4 100644
>>> --- a/net/mac80211/status.c
>>> +++ b/net/mac80211/status.c
>>> @@ -1019,6 +1019,85 @@ void ieee80211_tx_rate_update(struct
>>> ieee80211_hw *hw,
>>> }
>>> EXPORT_SYMBOL(ieee80211_tx_rate_update);
>>> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
>>> + struct ieee80211_vif *vif,
>>> + struct sk_buff *skb)
>>> +{
>>> + struct ieee80211_local *local = hw_to_local(hw);
>>> + struct ieee80211_sub_if_data *sdata;
>>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>>> + struct sta_info *sta;
>>> + int retry_count;
>>> + int rates_idx;
>>> + bool acked;
>>> +
>>> + if (WARN_ON(!ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)))
>>> + goto skip_stats_update;
>>> +
>>> + sdata = vif_to_sdata(vif);
>>> +
>>> + acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
>>> + rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
>>> +
>>> + rcu_read_lock();
>>> +
>>> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
>>> + rcu_read_unlock();
>>> + goto counters_update;
>>> + }
>>> +
>>> + if (!sta || IS_ERR(sta)) {
>>> + rcu_read_unlock();
>>> + goto counters_update;
>>> + }
>>> +
>>> + if (!acked)
>>> + sta->status_stats.retry_failed++;
>>> +
>>> + if (rates_idx != -1)
>>> + sta->tx_stats.last_rate = info->status.rates[rates_idx];
>>> +
>>> + sta->status_stats.retry_count += retry_count;
>>> +
>>> + if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
>>> + if (acked && vif->type == NL80211_IFTYPE_STATION)
>>> + ieee80211_sta_reset_conn_monitor(sdata);
>>> +
>>> + sta->status_stats.last_ack = jiffies;
>>> + if (info->flags & IEEE80211_TX_STAT_ACK) {
>>> + if (sta->status_stats.lost_packets)
>>> + sta->status_stats.lost_packets = 0;
>>> +
>>> + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
>>> + sta->status_stats.last_tdls_pkt_time = jiffies;
>>> + } else {
>>> + ieee80211_lost_packet(sta, info);
>>> + }
>>> + }
>>> +
>>> + rcu_read_unlock();
>>> +
>>> +counters_update:
>>> + ieee80211_led_tx(local);
>>> +
>>> + if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
>>> + !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
>>> + goto skip_stats_update;
>>> +
>>> + I802_DEBUG_INC(local->dot11TransmittedFrameCount);
>>> + if (is_multicast_ether_addr(skb->data))
>>> + I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
>>> + if (retry_count > 0)
>>> + I802_DEBUG_INC(local->dot11RetryCount);
>>> + if (retry_count > 1)
>>> + I802_DEBUG_INC(local->dot11MultipleRetryCount);
>>> +
>>> +skip_stats_update:
>>> + ieee80211_report_used_skb(local, skb, false);
>>> + dev_kfree_skb(skb);
>>> +}
>>> +EXPORT_SYMBOL(ieee80211_tx_status_8023);
>>> +
>>> void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32
>>> num_packets)
>>> {
>>> struct sta_info *sta = container_of(pubsta, struct sta_info,
>>> sta);
>>> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
>>> index 8a49a74c0a37..85356c208c02 100644
>>> --- a/net/mac80211/tx.c
>>> +++ b/net/mac80211/tx.c
>>> @@ -1253,7 +1253,8 @@ static struct txq_info
>>> *ieee80211_get_txq(struct ieee80211_local *local,
>>> (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
>>> return NULL;
>>> - if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
>>> + if (!info->control.hw_80211_encap &&
>>> + unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
>>> if ((!ieee80211_is_mgmt(hdr->frame_control) ||
>>> ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
>>> vif->type == NL80211_IFTYPE_STATION) &&
>>> @@ -1400,6 +1401,7 @@ static void ieee80211_txq_enqueue(struct
>>> ieee80211_local *local,
>>> struct fq *fq = &local->fq;
>>> struct fq_tin *tin = &txqi->tin;
>>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>>> ieee80211_set_skb_enqueue_time(skb);
>>> fq_tin_enqueue(fq, tin, skb,
>>> fq_skb_free_func,
>>> @@ -2357,9 +2359,9 @@ static inline bool
>>> ieee80211_is_tdls_setup(struct sk_buff *skb)
>>> skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
>>> }
>>> -static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data
>>> *sdata,
>>> - struct sk_buff *skb,
>>> - struct sta_info **sta_out)
>>> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
>>> + struct sk_buff *skb,
>>> + struct sta_info **sta_out)
>>> {
>>> struct sta_info *sta;
>>> @@ -2855,7 +2857,9 @@ void ieee80211_check_fast_xmit(struct
>>> sta_info *sta)
>>> struct ieee80211_chanctx_conf *chanctx_conf;
>>> __le16 fc;
>>> - if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT))
>>> + /* check for driver support and ieee80211 encap offload */
>>> + if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT) ||
>>> + sdata->hw_80211_encap)
>>> return;
>>> /* Locking here protects both the pointer itself, and
>>> against concurrent
>>> @@ -3554,6 +3558,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct
>>> ieee80211_hw *hw,
>>> hdr = (struct ieee80211_hdr *)skb->data;
>>> info = IEEE80211_SKB_CB(skb);
>>> + if (info->control.hw_80211_encap)
>>> + goto out;
>>> +
>>> memset(&tx, 0, sizeof(tx));
>>> __skb_queue_head_init(&tx.skbs);
>>> tx.local = local;
>>> @@ -4003,6 +4010,167 @@ netdev_tx_t
>>> ieee80211_subif_start_xmit(struct sk_buff *skb,
>>> return NETDEV_TX_OK;
>>> }
>>> +static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
>>> + struct sk_buff *skb, int led_len,
>>> + struct sta_info *sta,
>>> + bool txpending)
>>> +{
>>> + struct ieee80211_local *local = sdata->local;
>>> + struct ieee80211_tx_control control = {};
>>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>>> + struct ieee80211_sta *pubsta = NULL;
>>> + unsigned long flags;
>>> + int q = info->hw_queue;
>>> +
>>> + if (ieee80211_queue_skb(local, sdata, sta, skb))
>>> + return true;
>>> +
>>> + spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
>>> +
>>> + if (local->queue_stop_reasons[q] ||
>>> + (!txpending && !skb_queue_empty(&local->pending[q]))) {
>>> + if (txpending)
>>> + skb_queue_head(&local->pending[q], skb);
>>> + else
>>> + skb_queue_tail(&local->pending[q], skb);
>>> +
>>> + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
>>> +
>>> + return false;
>>> + }
>>> +
>>> + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
>>> +
>>> + if (sta && sta->uploaded)
>>> + pubsta = &sta->sta;
>>> +
>>> + control.sta = pubsta;
>>> +
>>> + drv_tx(local, &control, skb);
>>> +
>>> + return true;
>>> +}
>>> +
>>> +static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
>>> + struct net_device *dev, struct sta_info *sta,
>>> + struct sk_buff *skb)
>>> +{
>>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>>> + struct ethhdr *ehdr = (struct ethhdr *)skb->data;
>>> + struct ieee80211_local *local = sdata->local;
>>> + bool authorized = false;
>>> + bool multicast;
>>> + bool tdls_peer;
>>> + unsigned char *ra = NULL;
>>> +
>>> + if (IS_ERR(sta) || (sta && !sta->uploaded))
>>> + sta = NULL;
>>> +
>>> + if (sdata->vif.type == NL80211_IFTYPE_STATION) {
>>> + tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER);
>>> + if (tdls_peer)
>>> + ra = skb->data;
>>> + else
>>> + ra = sdata->u.mgd.bssid;
>>> + } else {
>>> + ra = ehdr->h_dest;
>>> + }
>>> +
>>> + if (!ra)
>>> + goto out_free;
>>> + multicast = is_multicast_ether_addr(ra);
>>> +
>>> + if (sta)
>>> + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
>>> +
>>> + if (!multicast && !authorized &&
>>> + ((ehdr->h_proto != sdata->control_port_protocol) ||
>>> + !ether_addr_equal(sdata->vif.addr, ehdr->h_source)))
>>> + goto out_free;
>>> +
>>> + if (multicast && sdata->vif.type == NL80211_IFTYPE_AP &&
>>> + !atomic_read(&sdata->u.ap.num_mcast_sta))
>>> + goto out_free;
>>> +
>>> + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
>>> + test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
>>> + goto out_free;
>>> +
>>> + /* TODO: Handle frames requiring wifi tx status to be notified */
>>> +
>>> + memset(info, 0, sizeof(*info));
>>> +
>>> + if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) {
>>> + if (sdata->control_port_no_encrypt)
>>> + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
>>> + info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
>>> + }
>>> +
>>> + if (multicast)
>>> + info->flags |= IEEE80211_TX_CTL_NO_ACK;
>>> +
>>> + info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
>>> +
>>> + ieee80211_tx_stats(dev, skb->len);
>>> +
>>> + if (sta) {
>>> + sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
>>> + sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
>>> + }
>>> +
>>> + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
>>> + sdata = container_of(sdata->bss,
>>> + struct ieee80211_sub_if_data, u.ap);
>>> +
>>> + info->control.hw_80211_encap = true;
>>> + info->control.vif = &sdata->vif;
>>> +
>>> + ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
>>> +
>>> + return;
>>> +
>>> +out_free:
>>> + kfree_skb(skb);
>>> +}
>>> +
>>> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
>>> + struct net_device *dev)
>>> +{
>>> + struct ieee80211_sub_if_data *sdata =
>>> IEEE80211_DEV_TO_SUB_IF(dev);
>>> + struct sta_info *sta;
>>> +
>>> + if (WARN_ON(unlikely(!sdata->hw_80211_encap))) {
>>> + kfree_skb(skb);
>>> + return NETDEV_TX_OK;
>>> + }
>>> +
>>> + if (unlikely(skb->len < ETH_HLEN)) {
>>> + kfree_skb(skb);
>>> + return NETDEV_TX_OK;
>>> + }
>>> +
>>> + if (WARN_ON(dev->ieee80211_ptr->use_4addr)) {
>>> + kfree_skb(skb);
>>> + return NETDEV_TX_OK;
>>> + }
>>> +
>>> + rcu_read_lock();
>>> +
>>> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
>>> + goto out_free;
>>> +
>>> + ieee80211_8023_xmit(sdata, dev, sta, skb);
>>> +
>>> + goto out;
>>> +
>>> +out_free:
>>> + kfree_skb(skb);
>>> +out:
>>> + rcu_read_unlock();
>>> +
>>> + return NETDEV_TX_OK;
>>> +}
>>> +
>>> struct sk_buff *
>>> ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
>>> struct sk_buff *skb, u32 info_flags)
>>> @@ -4081,6 +4249,16 @@ static bool ieee80211_tx_pending_skb(struct
>>> ieee80211_local *local,
>>> }
>>> info->band = chanctx_conf->def.chan->band;
>>> result = ieee80211_tx(sdata, NULL, skb, true, 0);
>>> + } else if (info->control.hw_80211_encap) {
>>> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
>>> + dev_kfree_skb(skb);
>>> + return true;
>>> + }
>>> +
>>> + if (IS_ERR(sta) || (sta && !sta->uploaded))
>>> + sta = NULL;
>>> +
>>> + result = ieee80211_tx_8023(sdata, skb, skb->len, sta, true);
>>> } else {
>>> struct sk_buff_head skbs;
>
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: John Crispin @ 2019-04-02 14:39 UTC (permalink / raw)
To: Sebastian Gottschall, Johannes Berg, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <fff76783-1298-9315-6706-f8eaea393c6b@newmedia-net.de>
On 02/04/2019 11:31, Sebastian Gottschall wrote:
> the introduced control field hw_80211_encap in ieee80211_tx_info leads
> to a compile assert
> /include/linux/compiler.h:522:38: error: call to
> '__compiletime_assert_1307' declared with attribute error:
> BUILD_BUG_ON failed: sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)
>
> skb->cb is to small on x64 devices
> i suggest to implement hw_80211_encap in ieee80211_vif which is a
> member of control in ieee80211_tx_info
>
> Sebastian
Hi Sebastian,
stumbled across that aswell while testing on arm64 today. I'll fix it in
V4, Thanks
John
>
> Am 01.04.2019 um 15:14 schrieb John Crispin:
>> From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
>>
>> This patch adds a new transmit path for hardware that supports 802.11
>> encapsulation offloading. In those cases 802.3a frames get passed
>> directly to the driver allowing to hardware to handle the encapsulation.
>>
>> Certain features wont work and the patch masks these out.
>> * monitor interfaces are not supported if any of the vif is in encap
>> mode.
>> * amsdu/non-linear frames wont work in encap offloading mode.
>> * TKIP countermeasures cannot be triggered and hence those keys are not
>> accepted.
>>
>> The patch defines a secondary netdev_ops struct that the device is
>> assigned
>> to the device if 802.11 encap support is available and enabled. The
>> driver
>> needs to enable the support on a per vif basis if it finds that all
>> pre-reqs are meet.
>>
>> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
>> Signed-off-by: John Crispin <john@phrozen.org>
>> ---
>> include/net/mac80211.h | 25 ++++++
>> net/mac80211/cfg.c | 12 ++-
>> net/mac80211/debugfs.c | 1 +
>> net/mac80211/ieee80211_i.h | 10 +++
>> net/mac80211/iface.c | 54 +++++++++++++
>> net/mac80211/key.c | 3 +
>> net/mac80211/main.c | 10 ++-
>> net/mac80211/status.c | 79 +++++++++++++++++++
>> net/mac80211/tx.c | 188
>> +++++++++++++++++++++++++++++++++++++++++++--
>> 9 files changed, 373 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
>> index ac2ed8ec662b..3e8929770839 100644
>> --- a/include/net/mac80211.h
>> +++ b/include/net/mac80211.h
>> @@ -1021,6 +1021,7 @@ struct ieee80211_tx_info {
>> struct ieee80211_key_conf *hw_key;
>> u32 flags;
>> codel_time_t enqueue_time;
>> + u8 hw_80211_encap;
>> } control;
>> struct {
>> u64 cookie;
>> @@ -2243,6 +2244,9 @@ struct ieee80211_txq {
>> * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports
>> multi BSSID
>> * only for HE APs. Applies if
>> @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
>> *
>> + * @IEEE80211_HW_SUPPORTS_80211_ENCAP: Hardware/driver supports 802.11
>> + * encap for data frames.
>> + *
>> * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for
>> sizing arrays
>> */
>> enum ieee80211_hw_flags {
>> @@ -2294,6 +2298,7 @@ enum ieee80211_hw_flags {
>> IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
>> IEEE80211_HW_SUPPORTS_MULTI_BSSID,
>> IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
>> + IEEE80211_HW_SUPPORTS_80211_ENCAP,
>> /* keep last, obviously */
>> NUM_IEEE80211_HW_FLAGS
>> @@ -4587,6 +4592,25 @@ void ieee80211_tx_status_irqsafe(struct
>> ieee80211_hw *hw,
>> struct sk_buff *skb);
>> /**
>> + * ieee80211_tx_status_8023 - transmit status callback for 802.3
>> frame format
>> + *
>> + * Call this function for all transmitted data frames after their
>> transmit
>> + * completion. This callback should only be called for data frames
>> which
>> + * are are using driver's (or hardware's) offload capability of
>> encap/decap
>> + * 802.11 frames.
>> + *
>> + * This function may not be called in IRQ context. Calls to this
>> function
>> + * for a single hardware must be synchronized against each other.
>> + *
>> + * @hw: the hardware the frame was transmitted by
>> + * @vif: the interface for which the frame was transmitted
>> + * @skb: the frame that was transmitted, owned by mac80211 after
>> this call
>> + */
>> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
>> + struct ieee80211_vif *vif,
>> + struct sk_buff *skb);
>> +
>> +/**
>> * ieee80211_report_low_ack - report non-responding station
>> *
>> * When operating in AP-mode, call this function to report a
>> non-responding
>> @@ -6359,4 +6383,5 @@ void ieee80211_nan_func_match(struct
>> ieee80211_vif *vif,
>> struct cfg80211_nan_match_params *match,
>> gfp_t gfp);
>> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool
>> enable);
>> #endif /* MAC80211_H */
>> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
>> index 09dd1c2860fc..53b56f8fcdfc 100644
>> --- a/net/mac80211/cfg.c
>> +++ b/net/mac80211/cfg.c
>> @@ -367,8 +367,15 @@ static int ieee80211_add_key(struct wiphy
>> *wiphy, struct net_device *dev,
>> /* reject WEP and TKIP keys if WEP failed to initialize */
>> switch (params->cipher) {
>> - case WLAN_CIPHER_SUITE_WEP40:
>> case WLAN_CIPHER_SUITE_TKIP:
>> + /* countermeasures wont work on encap offload mode so reject
>> + * TKIP keys
>> + */
>> + if (ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
>> + return -EINVAL;
>> +
>> + /* drop through */
>> + case WLAN_CIPHER_SUITE_WEP40:
>> case WLAN_CIPHER_SUITE_WEP104:
>> if (IS_ERR(local->wep_tx_tfm))
>> return -EINVAL;
>> @@ -2379,6 +2386,9 @@ static int ieee80211_set_wiphy_params(struct
>> wiphy *wiphy, u32 changed)
>> if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
>> ieee80211_check_fast_xmit_all(local);
>> + if (ieee80211_is_hw_80211_encap(local))
>> + return -EINVAL;
>> +
>> err = drv_set_frag_threshold(local, wiphy->frag_threshold);
>> if (err) {
>> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
>> index 2d43bc127043..a4df6bca192f 100644
>> --- a/net/mac80211/debugfs.c
>> +++ b/net/mac80211/debugfs.c
>> @@ -221,6 +221,7 @@ static const char *hw_flag_names[] = {
>> FLAG(TX_STATUS_NO_AMPDU_LEN),
>> FLAG(SUPPORTS_MULTI_BSSID),
>> FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
>> + FLAG(SUPPORTS_80211_ENCAP),
>> #undef FLAG
>> };
>> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
>> index e170f986d226..d7569a455a06 100644
>> --- a/net/mac80211/ieee80211_i.h
>> +++ b/net/mac80211/ieee80211_i.h
>> @@ -987,6 +987,8 @@ struct ieee80211_sub_if_data {
>> } debugfs;
>> #endif
>> + bool hw_80211_encap;
>> +
>> /* must be last, dynamically sized area in this! */
>> struct ieee80211_vif vif;
>> };
>> @@ -1732,6 +1734,7 @@ int ieee80211_if_add(struct ieee80211_local
>> *local, const char *name,
>> struct vif_params *params);
>> int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
>> enum nl80211_iftype type);
>> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local);
>> void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
>> void ieee80211_remove_interfaces(struct ieee80211_local *local);
>> u32 ieee80211_idle_off(struct ieee80211_local *local);
>> @@ -1759,6 +1762,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct
>> sk_buff *skb,
>> struct net_device *dev);
>> netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
>> struct net_device *dev);
>> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
>> + struct net_device *dev);
>> void __ieee80211_subif_start_xmit(struct sk_buff *skb,
>> struct net_device *dev,
>> u32 info_flags);
>> @@ -1933,6 +1938,11 @@ void __ieee80211_tx_skb_tid_band(struct
>> ieee80211_sub_if_data *sdata,
>> struct sk_buff *skb, int tid,
>> enum nl80211_band band, u32 txdata_flags);
>> +/* sta_out needs to be checked for ERR_PTR() before using */
>> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
>> + struct sk_buff *skb,
>> + struct sta_info **sta_out);
>> +
>> static inline void
>> ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
>> struct sk_buff *skb, int tid,
>> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
>> index 4a6ff1482a9f..4090c2c5fde0 100644
>> --- a/net/mac80211/iface.c
>> +++ b/net/mac80211/iface.c
>> @@ -1177,6 +1177,59 @@ static const struct net_device_ops
>> ieee80211_dataif_ops = {
>> .ndo_get_stats64 = ieee80211_get_stats64,
>> };
>> +static const struct net_device_ops ieee80211_dataif_8023_ops = {
>> + .ndo_open = ieee80211_open,
>> + .ndo_stop = ieee80211_stop,
>> + .ndo_uninit = ieee80211_uninit,
>> + .ndo_start_xmit = ieee80211_subif_start_xmit_8023,
>> + .ndo_set_rx_mode = ieee80211_set_multicast_list,
>> + .ndo_set_mac_address = ieee80211_change_mac,
>> + .ndo_select_queue = ieee80211_netdev_select_queue,
>> + .ndo_get_stats64 = ieee80211_get_stats64,
>> +};
>> +
>> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool
>> enable)
>> +{
>> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
>> + struct ieee80211_local *local = sdata->local;
>> +
>> + if (!sdata->dev)
>> + return;
>> +
>> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
>> + enable = 0;
>> +
>> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
>> + (local->hw.wiphy->frag_threshold != (u32)-1))
>> + enable = 0;
>> +
>> + if (enable) {
>> + sdata->dev->netdev_ops = &ieee80211_dataif_8023_ops;
>> + sdata->hw_80211_encap = true;
>> + } else {
>> + sdata->dev->netdev_ops = &ieee80211_dataif_ops;
>> + sdata->hw_80211_encap = false;
>> + }
>> +}
>> +EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
>> +
>> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local)
>> +{
>> + struct ieee80211_sub_if_data *sdata;
>> + bool offloaded = false;
>> +
>> + mutex_lock(&local->iflist_mtx);
>> + list_for_each_entry(sdata, &local->interfaces, list) {
>> + if (sdata->hw_80211_encap) {
>> + offloaded = true;
>> + break;
>> + }
>> + }
>> + mutex_unlock(&local->iflist_mtx);
>> +
>> + return offloaded;
>> +}
>> +
>> static u16 ieee80211_monitor_select_queue(struct net_device *dev,
>> struct sk_buff *skb,
>> struct net_device *sb_dev,
>> @@ -1409,6 +1462,7 @@ static void ieee80211_setup_sdata(struct
>> ieee80211_sub_if_data *sdata,
>> sdata->vif.bss_conf.idle = true;
>> sdata->noack_map = 0;
>> + sdata->hw_80211_encap = false;
>> /* only monitor/p2p-device differ */
>> if (sdata->dev) {
>> diff --git a/net/mac80211/key.c b/net/mac80211/key.c
>> index 4700718e010f..861b67d43eb7 100644
>> --- a/net/mac80211/key.c
>> +++ b/net/mac80211/key.c
>> @@ -197,6 +197,9 @@ static int ieee80211_key_enable_hw_accel(struct
>> ieee80211_key *key)
>> key->conf.keyidx,
>> sta ? sta->sta.addr : bcast_addr, ret);
>> + if (sdata->hw_80211_encap)
>> + return -EINVAL;
>> +
>> out_unsupported:
>> switch (key->conf.cipher) {
>> case WLAN_CIPHER_SUITE_WEP40:
>> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
>> index 800e67615e2a..a49bcec3891e 100644
>> --- a/net/mac80211/main.c
>> +++ b/net/mac80211/main.c
>> @@ -1000,9 +1000,13 @@ int ieee80211_register_hw(struct ieee80211_hw
>> *hw)
>> hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
>> }
>> - /* mac80211 always supports monitor */
>> - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
>> - hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
>> + if (ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)) {
>> + /* mac80211 always supports monitor unless we do 802.11
>> + * encapsulation offloading.
>> + */
>> + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
>> + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
>> + }
>> /* mac80211 doesn't support more than one IBSS interface
>> right now */
>> for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
>> diff --git a/net/mac80211/status.c b/net/mac80211/status.c
>> index 5b9952b1caf3..8feafaab88a4 100644
>> --- a/net/mac80211/status.c
>> +++ b/net/mac80211/status.c
>> @@ -1019,6 +1019,85 @@ void ieee80211_tx_rate_update(struct
>> ieee80211_hw *hw,
>> }
>> EXPORT_SYMBOL(ieee80211_tx_rate_update);
>> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
>> + struct ieee80211_vif *vif,
>> + struct sk_buff *skb)
>> +{
>> + struct ieee80211_local *local = hw_to_local(hw);
>> + struct ieee80211_sub_if_data *sdata;
>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>> + struct sta_info *sta;
>> + int retry_count;
>> + int rates_idx;
>> + bool acked;
>> +
>> + if (WARN_ON(!ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)))
>> + goto skip_stats_update;
>> +
>> + sdata = vif_to_sdata(vif);
>> +
>> + acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
>> + rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
>> +
>> + rcu_read_lock();
>> +
>> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
>> + rcu_read_unlock();
>> + goto counters_update;
>> + }
>> +
>> + if (!sta || IS_ERR(sta)) {
>> + rcu_read_unlock();
>> + goto counters_update;
>> + }
>> +
>> + if (!acked)
>> + sta->status_stats.retry_failed++;
>> +
>> + if (rates_idx != -1)
>> + sta->tx_stats.last_rate = info->status.rates[rates_idx];
>> +
>> + sta->status_stats.retry_count += retry_count;
>> +
>> + if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
>> + if (acked && vif->type == NL80211_IFTYPE_STATION)
>> + ieee80211_sta_reset_conn_monitor(sdata);
>> +
>> + sta->status_stats.last_ack = jiffies;
>> + if (info->flags & IEEE80211_TX_STAT_ACK) {
>> + if (sta->status_stats.lost_packets)
>> + sta->status_stats.lost_packets = 0;
>> +
>> + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
>> + sta->status_stats.last_tdls_pkt_time = jiffies;
>> + } else {
>> + ieee80211_lost_packet(sta, info);
>> + }
>> + }
>> +
>> + rcu_read_unlock();
>> +
>> +counters_update:
>> + ieee80211_led_tx(local);
>> +
>> + if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
>> + !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
>> + goto skip_stats_update;
>> +
>> + I802_DEBUG_INC(local->dot11TransmittedFrameCount);
>> + if (is_multicast_ether_addr(skb->data))
>> + I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
>> + if (retry_count > 0)
>> + I802_DEBUG_INC(local->dot11RetryCount);
>> + if (retry_count > 1)
>> + I802_DEBUG_INC(local->dot11MultipleRetryCount);
>> +
>> +skip_stats_update:
>> + ieee80211_report_used_skb(local, skb, false);
>> + dev_kfree_skb(skb);
>> +}
>> +EXPORT_SYMBOL(ieee80211_tx_status_8023);
>> +
>> void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32
>> num_packets)
>> {
>> struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
>> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
>> index 8a49a74c0a37..85356c208c02 100644
>> --- a/net/mac80211/tx.c
>> +++ b/net/mac80211/tx.c
>> @@ -1253,7 +1253,8 @@ static struct txq_info
>> *ieee80211_get_txq(struct ieee80211_local *local,
>> (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
>> return NULL;
>> - if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
>> + if (!info->control.hw_80211_encap &&
>> + unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
>> if ((!ieee80211_is_mgmt(hdr->frame_control) ||
>> ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
>> vif->type == NL80211_IFTYPE_STATION) &&
>> @@ -1400,6 +1401,7 @@ static void ieee80211_txq_enqueue(struct
>> ieee80211_local *local,
>> struct fq *fq = &local->fq;
>> struct fq_tin *tin = &txqi->tin;
>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>> ieee80211_set_skb_enqueue_time(skb);
>> fq_tin_enqueue(fq, tin, skb,
>> fq_skb_free_func,
>> @@ -2357,9 +2359,9 @@ static inline bool
>> ieee80211_is_tdls_setup(struct sk_buff *skb)
>> skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
>> }
>> -static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data
>> *sdata,
>> - struct sk_buff *skb,
>> - struct sta_info **sta_out)
>> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
>> + struct sk_buff *skb,
>> + struct sta_info **sta_out)
>> {
>> struct sta_info *sta;
>> @@ -2855,7 +2857,9 @@ void ieee80211_check_fast_xmit(struct
>> sta_info *sta)
>> struct ieee80211_chanctx_conf *chanctx_conf;
>> __le16 fc;
>> - if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT))
>> + /* check for driver support and ieee80211 encap offload */
>> + if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT) ||
>> + sdata->hw_80211_encap)
>> return;
>> /* Locking here protects both the pointer itself, and against
>> concurrent
>> @@ -3554,6 +3558,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct
>> ieee80211_hw *hw,
>> hdr = (struct ieee80211_hdr *)skb->data;
>> info = IEEE80211_SKB_CB(skb);
>> + if (info->control.hw_80211_encap)
>> + goto out;
>> +
>> memset(&tx, 0, sizeof(tx));
>> __skb_queue_head_init(&tx.skbs);
>> tx.local = local;
>> @@ -4003,6 +4010,167 @@ netdev_tx_t ieee80211_subif_start_xmit(struct
>> sk_buff *skb,
>> return NETDEV_TX_OK;
>> }
>> +static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
>> + struct sk_buff *skb, int led_len,
>> + struct sta_info *sta,
>> + bool txpending)
>> +{
>> + struct ieee80211_local *local = sdata->local;
>> + struct ieee80211_tx_control control = {};
>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>> + struct ieee80211_sta *pubsta = NULL;
>> + unsigned long flags;
>> + int q = info->hw_queue;
>> +
>> + if (ieee80211_queue_skb(local, sdata, sta, skb))
>> + return true;
>> +
>> + spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
>> +
>> + if (local->queue_stop_reasons[q] ||
>> + (!txpending && !skb_queue_empty(&local->pending[q]))) {
>> + if (txpending)
>> + skb_queue_head(&local->pending[q], skb);
>> + else
>> + skb_queue_tail(&local->pending[q], skb);
>> +
>> + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
>> +
>> + return false;
>> + }
>> +
>> + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
>> +
>> + if (sta && sta->uploaded)
>> + pubsta = &sta->sta;
>> +
>> + control.sta = pubsta;
>> +
>> + drv_tx(local, &control, skb);
>> +
>> + return true;
>> +}
>> +
>> +static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
>> + struct net_device *dev, struct sta_info *sta,
>> + struct sk_buff *skb)
>> +{
>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>> + struct ethhdr *ehdr = (struct ethhdr *)skb->data;
>> + struct ieee80211_local *local = sdata->local;
>> + bool authorized = false;
>> + bool multicast;
>> + bool tdls_peer;
>> + unsigned char *ra = NULL;
>> +
>> + if (IS_ERR(sta) || (sta && !sta->uploaded))
>> + sta = NULL;
>> +
>> + if (sdata->vif.type == NL80211_IFTYPE_STATION) {
>> + tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER);
>> + if (tdls_peer)
>> + ra = skb->data;
>> + else
>> + ra = sdata->u.mgd.bssid;
>> + } else {
>> + ra = ehdr->h_dest;
>> + }
>> +
>> + if (!ra)
>> + goto out_free;
>> + multicast = is_multicast_ether_addr(ra);
>> +
>> + if (sta)
>> + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
>> +
>> + if (!multicast && !authorized &&
>> + ((ehdr->h_proto != sdata->control_port_protocol) ||
>> + !ether_addr_equal(sdata->vif.addr, ehdr->h_source)))
>> + goto out_free;
>> +
>> + if (multicast && sdata->vif.type == NL80211_IFTYPE_AP &&
>> + !atomic_read(&sdata->u.ap.num_mcast_sta))
>> + goto out_free;
>> +
>> + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
>> + test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
>> + goto out_free;
>> +
>> + /* TODO: Handle frames requiring wifi tx status to be notified */
>> +
>> + memset(info, 0, sizeof(*info));
>> +
>> + if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) {
>> + if (sdata->control_port_no_encrypt)
>> + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
>> + info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
>> + }
>> +
>> + if (multicast)
>> + info->flags |= IEEE80211_TX_CTL_NO_ACK;
>> +
>> + info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
>> +
>> + ieee80211_tx_stats(dev, skb->len);
>> +
>> + if (sta) {
>> + sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
>> + sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
>> + }
>> +
>> + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
>> + sdata = container_of(sdata->bss,
>> + struct ieee80211_sub_if_data, u.ap);
>> +
>> + info->control.hw_80211_encap = true;
>> + info->control.vif = &sdata->vif;
>> +
>> + ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
>> +
>> + return;
>> +
>> +out_free:
>> + kfree_skb(skb);
>> +}
>> +
>> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
>> + struct net_device *dev)
>> +{
>> + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
>> + struct sta_info *sta;
>> +
>> + if (WARN_ON(unlikely(!sdata->hw_80211_encap))) {
>> + kfree_skb(skb);
>> + return NETDEV_TX_OK;
>> + }
>> +
>> + if (unlikely(skb->len < ETH_HLEN)) {
>> + kfree_skb(skb);
>> + return NETDEV_TX_OK;
>> + }
>> +
>> + if (WARN_ON(dev->ieee80211_ptr->use_4addr)) {
>> + kfree_skb(skb);
>> + return NETDEV_TX_OK;
>> + }
>> +
>> + rcu_read_lock();
>> +
>> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
>> + goto out_free;
>> +
>> + ieee80211_8023_xmit(sdata, dev, sta, skb);
>> +
>> + goto out;
>> +
>> +out_free:
>> + kfree_skb(skb);
>> +out:
>> + rcu_read_unlock();
>> +
>> + return NETDEV_TX_OK;
>> +}
>> +
>> struct sk_buff *
>> ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
>> struct sk_buff *skb, u32 info_flags)
>> @@ -4081,6 +4249,16 @@ static bool ieee80211_tx_pending_skb(struct
>> ieee80211_local *local,
>> }
>> info->band = chanctx_conf->def.chan->band;
>> result = ieee80211_tx(sdata, NULL, skb, true, 0);
>> + } else if (info->control.hw_80211_encap) {
>> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
>> + dev_kfree_skb(skb);
>> + return true;
>> + }
>> +
>> + if (IS_ERR(sta) || (sta && !sta->uploaded))
>> + sta = NULL;
>> +
>> + result = ieee80211_tx_8023(sdata, skb, skb->len, sta, true);
>> } else {
>> struct sk_buff_head skbs;
^ permalink raw reply
* Re: [RFC V3 2/2] ath10k: add tx hw 802.11 encapusaltion offloading support
From: John Crispin @ 2019-04-02 14:38 UTC (permalink / raw)
To: Sebastian Gottschall, Johannes Berg, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <82b5d619-1214-7464-a873-901677b4445e@newmedia-net.de>
On 02/04/2019 11:27, Sebastian Gottschall wrote:
> Am 01.04.2019 um 16:02 schrieb John Crispin:
>
>>
>> On 01/04/2019 15:14, John Crispin wrote:
>>> @@ -5185,6 +5214,23 @@ static int ath10k_add_interface(struct
>>> ieee80211_hw *hw,
>>> break;
>>> }
>>> + switch (vif->type) {
>>> + case NL80211_IFTYPE_AP:
>>> + hw_encap = 1;
>>> + break;
>>> + case NL80211_IFTYPE_STATION:
>>> +// if (!sdata->u.mgd.use_4addr)
>>> + hw_encap = 1;
>>> + break;
>>> + case NL80211_IFTYPE_AP_VLAN:
>>> +// if (!sdata->wdev.use_4addr)
>>> + hw_encap = 1;
>>> + break;
>>> + default:
>>> + break;
>>> + }
>>> + ieee80211_set_hw_80211_encap(vif, ar->ethernetmode & hw_encap);
>>> +
>>> /* Using vdev_id as queue number will make it very easy to do
>>> per-vif
>>> * tx queue locking. This shouldn't wrap due to interface
>>> combinations
>>> * but do a modulo for correctness sake and prevent using
>>> offchannel tx
>>
>> Hi
>>
>> I am not sure what the best way to handle the 4addr mode is. sdata is
>> part of the subsystem and is not exposed to the drivers.Calling
>> ieee80211_set_hw_80211_encap() from within the driver looked best to
>> me at first glance and would avoid adding an extra op call to figure
>> out if the if encap is supported. Any pointers on what the preferred
>> solution would look like are welcome.
>>
>> John
>
> you may do the 4addr check within ieee80211_set_hw_80211_encap, there
> is no need for dealing with that in ath10k or do i miss something?
>
> Sebastian
>
Correct, I'll add that in V4
John
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: John Crispin @ 2019-04-02 14:37 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, Johannes Berg, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <878swspmdu.fsf@toke.dk>
On 02/04/2019 15:28, Toke Høiland-Jørgensen wrote:
> Johannes Berg <johannes@sipsolutions.net> writes:
>
>> On Tue, 2019-04-02 at 11:50 +0200, Toke Høiland-Jørgensen wrote:
>>
>> [snip, you really should try that sometimes ;-)]
>>
>>> ieee80211_queue_skb() calls ieee80211_get_txq() which treats skb-
>>> datalike it contains an 802.11 header. That is probably not the
>>> intention here, is it?
>> Indeed, that makes no sense.
>>
>>> I guess we could augment the TXQ stuctures to also handle 802.3 frames
>>> (and introduce ieee80211_queue_skb_8023())? Or would it be better to
>>> have a qdisc on 802.3-mode interfaces and push packets back to that? I
>>> guess we'd still benefit from per-station queueing of packets even if
>>> they are Ethernet frames, which would mean amending the TXQs would be
>>> better?
>> TXQs would be better, yes. We should do that.
> Cool. Glad that we agree ;)
>
> -Toke
Hi Toke,
will add that for V4, thanks
John
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: Toke Høiland-Jørgensen @ 2019-04-02 13:28 UTC (permalink / raw)
To: Johannes Berg, John Crispin, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <5647fa751aed450f09312c35f8d5becd47e26b66.camel@sipsolutions.net>
Johannes Berg <johannes@sipsolutions.net> writes:
> On Tue, 2019-04-02 at 11:50 +0200, Toke Høiland-Jørgensen wrote:
>
> [snip, you really should try that sometimes ;-)]
>
>> ieee80211_queue_skb() calls ieee80211_get_txq() which treats skb-
>> datalike it contains an 802.11 header. That is probably not the
>> intention here, is it?
>
> Indeed, that makes no sense.
>
>> I guess we could augment the TXQ stuctures to also handle 802.3 frames
>> (and introduce ieee80211_queue_skb_8023())? Or would it be better to
>> have a qdisc on 802.3-mode interfaces and push packets back to that? I
>> guess we'd still benefit from per-station queueing of packets even if
>> they are Ethernet frames, which would mean amending the TXQs would be
>> better?
>
> TXQs would be better, yes. We should do that.
Cool. Glad that we agree ;)
-Toke
^ permalink raw reply
* Re: [PATCH v4 1/3] cfg80211: Add support to set tx power for a station associated
From: Johannes Berg @ 2019-04-02 13:04 UTC (permalink / raw)
To: Bob Copeland, Balaji Pothunoori
Cc: ath10k, linux-wireless, Ashok Raj Nagarajan
In-Reply-To: <20190402125908.GD32168@localhost>
On Tue, 2019-04-02 at 08:59 -0400, Bob Copeland wrote:
> On Tue, Apr 02, 2019 at 12:00:29PM +0530, Balaji Pothunoori wrote:
> > > Should this really dBm? It's a bit asymmetric for WIPHY_TX_POWER_LEVEL
> > > to
> > > use mBm and this to use dBm, and I might want to adjust in half-dB steps
> > > if
> > > supported by hardware. Also allocating an s16 is a bit much for dBm.
> >
> > if user will send mBm value then driver has to convert to dBm because
> > firmware will expect the value in dBm.
> > Please refer johannes comments on following patch " [EXT] Re: [PATCH] iw:
> > Add support for controlling tx power for per station"
> > for the reason why we opted dBm.
>
> The quote was:
>
> > I would prefer if this was *dBm*, rather than mBm, and be allowed to
> > take float values, i.e. this would become "limit 20".
>
> I read that as "iw should convert fractional dBm to mBm" not "kernel should
> only support dBm".
Yeah, I was scratching my head here now wondering why I'd have said
that... But yes, I intended that we should present the nicer UI (float
dBm or so) and then send mBm :)
johannes
^ permalink raw reply
* Re: [PATCH v4 1/3] cfg80211: Add support to set tx power for a station associated
From: Bob Copeland @ 2019-04-02 12:59 UTC (permalink / raw)
To: Balaji Pothunoori; +Cc: johannes, ath10k, linux-wireless, Ashok Raj Nagarajan
In-Reply-To: <cd497042d164c322bc06c4cfbf26435a@codeaurora.org>
On Tue, Apr 02, 2019 at 12:00:29PM +0530, Balaji Pothunoori wrote:
> > Should this really dBm? It's a bit asymmetric for WIPHY_TX_POWER_LEVEL
> > to
> > use mBm and this to use dBm, and I might want to adjust in half-dB steps
> > if
> > supported by hardware. Also allocating an s16 is a bit much for dBm.
>
> if user will send mBm value then driver has to convert to dBm because
> firmware will expect the value in dBm.
> Please refer johannes comments on following patch " [EXT] Re: [PATCH] iw:
> Add support for controlling tx power for per station"
> for the reason why we opted dBm.
The quote was:
> I would prefer if this was *dBm*, rather than mBm, and be allowed to
> take float values, i.e. this would become "limit 20".
I read that as "iw should convert fractional dBm to mBm" not "kernel should
only support dBm".
ath10k might only support dBm, fine -- but even ath5k could support
per-packet transmit power in 0.5 dB steps, so this is already limiting
applicability to existing hardware.
--
Bob Copeland %% https://bobcopeland.com/
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: Johannes Berg @ 2019-04-02 12:44 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, John Crispin, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <87k1gcpwgy.fsf@toke.dk>
On Tue, 2019-04-02 at 11:50 +0200, Toke Høiland-Jørgensen wrote:
[snip, you really should try that sometimes ;-)]
> ieee80211_queue_skb() calls ieee80211_get_txq() which treats skb-
> datalike it contains an 802.11 header. That is probably not the
> intention here, is it?
Indeed, that makes no sense.
> I guess we could augment the TXQ stuctures to also handle 802.3 frames
> (and introduce ieee80211_queue_skb_8023())? Or would it be better to
> have a qdisc on 802.3-mode interfaces and push packets back to that? I
> guess we'd still benefit from per-station queueing of packets even if
> they are Ethernet frames, which would mean amending the TXQs would be
> better?
TXQs would be better, yes. We should do that.
johannes
^ permalink raw reply
* [PATCH] ath10k: Fix encoding for protected management frames
From: Rakesh Pillai @ 2019-04-02 12:42 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Rakesh Pillai
Currently the protected management frames are
not appended with the MIC_LEN which results in
the protected management frames being encoded
incorrectly.
Add the extra space at the end of the protected
management frames to fix this encoding error for
the protected management frames.
Tested HW: WCN3990
Tested FW: WLAN.HL.3.1-00784-QCAHLSWMTPLZ-1
Fixes: 1807da49733e "ath10k: wmi: add management tx by reference support over wmi"
Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
---
drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 582fb11..02709fc 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -2840,8 +2840,10 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
ieee80211_is_disassoc(hdr->frame_control)) &&
- ieee80211_has_protected(hdr->frame_control))
+ ieee80211_has_protected(hdr->frame_control)) {
+ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
buf_len += IEEE80211_CCMP_MIC_LEN;
+ }
buf_len = min_t(u32, buf_len, WMI_TLV_MGMT_TX_FRAME_MAX_LEN);
buf_len = round_up(buf_len, 4);
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] linux-firmware: add firmware for MT7615E
From: Josh Boyer @ 2019-04-02 12:02 UTC (permalink / raw)
To: Ryder Lee
Cc: Lorenzo Bianconi, Felix Fietkau, Roy Luo, Sean Wang,
Linux Wireless, Linux Firmware, linux-mediatek
In-Reply-To: <2c5c234766af299124ffb330198cf23b0a693cbf.1553591027.git.ryder.lee@mediatek.com>
On Tue, Mar 26, 2019 at 10:30 AM Ryder Lee <ryder.lee@mediatek.com> wrote:
>
> Add binary firmware for MT7615E based devices
>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> ---
> WHENCE | 13 +++++++++++++
> mediatek/mt7615_cr4.bin | Bin 0 -> 122644 bytes
> mediatek/mt7615_n9.bin | Bin 0 -> 459000 bytes
> mediatek/mt7615_rom_patch.bin | Bin 0 -> 11102 bytes
> 4 files changed, 13 insertions(+)
> create mode 100644 mediatek/mt7615_cr4.bin
> create mode 100644 mediatek/mt7615_n9.bin
> create mode 100644 mediatek/mt7615_rom_patch.bin
Applied and pushed out. Thanks.
josh
^ permalink raw reply
* Re: pull-request mwifiex-firmware 2019-03-15
From: Josh Boyer @ 2019-04-02 11:56 UTC (permalink / raw)
To: Ganapathi Bhat
Cc: linux-firmware@kernel.org, linux-wireless@vger.kernel.org,
Rakesh Parmar, Cathy Luo, James Cao, Zhiyuan Yang, Mayur Arakere
In-Reply-To: <CY4PR18MB1237CD0037B7ED3C3C11A5B5A0440@CY4PR18MB1237.namprd18.prod.outlook.com>
On Fri, Mar 15, 2019 at 1:44 PM Ganapathi Bhat <gbhat@marvell.com> wrote:
>
> The following changes since commit 78d2b16af093783d40f0b8990d5d9ede8c3281d3:
>
> linux-firmware: update Marvell 8787/8801/8887 firmware images (2019-02-28 23:35:32 +0530)
>
> are available in the git repository at:
>
> git://git.marvell.com/mwifiex-firmware.git
>
> for you to fetch changes up to d71dee4e5a86075c0ba6f81f00660ff999f171bc:
>
> linux-firmware: update Marvell 8797/8997 firmware images (2019-03-15 21:02:17 +0530)
>
> ----------------------------------------------------------------
> Ganapathi Bhat (1):
> linux-firmware: update Marvell 8797/8997 firmware images
>
> WHENCE | 6 +++---
> mrvl/pcieuart8997_combo_v4.bin | Bin 583628 -> 632240 bytes
> mrvl/sd8797_uapsta.bin | Bin 458108 -> 533976 bytes
> mrvl/usb8797_uapsta.bin | Bin 553456 -> 553940 bytes
> 4 files changed, 3 insertions(+), 3 deletions(-)
Pulled and pushed out. Thanks.
josh
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: Toke Høiland-Jørgensen @ 2019-04-02 9:50 UTC (permalink / raw)
To: John Crispin, Johannes Berg, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan,
John Crispin
In-Reply-To: <20190401131416.22646-2-john@phrozen.org>
John Crispin <john@phrozen.org> writes:
> From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
>
> This patch adds a new transmit path for hardware that supports 802.11
> encapsulation offloading. In those cases 802.3a frames get passed
> directly to the driver allowing to hardware to handle the encapsulation.
>
> Certain features wont work and the patch masks these out.
> * monitor interfaces are not supported if any of the vif is in encap mode.
> * amsdu/non-linear frames wont work in encap offloading mode.
> * TKIP countermeasures cannot be triggered and hence those keys are not
> accepted.
>
> The patch defines a secondary netdev_ops struct that the device is assigned
> to the device if 802.11 encap support is available and enabled. The driver
> needs to enable the support on a per vif basis if it finds that all
> pre-reqs are meet.
>
> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
> Signed-off-by: John Crispin <john@phrozen.org>
> ---
> include/net/mac80211.h | 25 ++++++
> net/mac80211/cfg.c | 12 ++-
> net/mac80211/debugfs.c | 1 +
> net/mac80211/ieee80211_i.h | 10 +++
> net/mac80211/iface.c | 54 +++++++++++++
> net/mac80211/key.c | 3 +
> net/mac80211/main.c | 10 ++-
> net/mac80211/status.c | 79 +++++++++++++++++++
> net/mac80211/tx.c | 188 +++++++++++++++++++++++++++++++++++++++++++--
> 9 files changed, 373 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index ac2ed8ec662b..3e8929770839 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -1021,6 +1021,7 @@ struct ieee80211_tx_info {
> struct ieee80211_key_conf *hw_key;
> u32 flags;
> codel_time_t enqueue_time;
> + u8 hw_80211_encap;
> } control;
> struct {
> u64 cookie;
> @@ -2243,6 +2244,9 @@ struct ieee80211_txq {
> * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
> * only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
> *
> + * @IEEE80211_HW_SUPPORTS_80211_ENCAP: Hardware/driver supports 802.11
> + * encap for data frames.
> + *
> * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
> */
> enum ieee80211_hw_flags {
> @@ -2294,6 +2298,7 @@ enum ieee80211_hw_flags {
> IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
> IEEE80211_HW_SUPPORTS_MULTI_BSSID,
> IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
> + IEEE80211_HW_SUPPORTS_80211_ENCAP,
>
> /* keep last, obviously */
> NUM_IEEE80211_HW_FLAGS
> @@ -4587,6 +4592,25 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
> struct sk_buff *skb);
>
> /**
> + * ieee80211_tx_status_8023 - transmit status callback for 802.3 frame format
> + *
> + * Call this function for all transmitted data frames after their transmit
> + * completion. This callback should only be called for data frames which
> + * are are using driver's (or hardware's) offload capability of encap/decap
> + * 802.11 frames.
> + *
> + * This function may not be called in IRQ context. Calls to this function
> + * for a single hardware must be synchronized against each other.
> + *
> + * @hw: the hardware the frame was transmitted by
> + * @vif: the interface for which the frame was transmitted
> + * @skb: the frame that was transmitted, owned by mac80211 after this call
> + */
> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + struct sk_buff *skb);
> +
> +/**
> * ieee80211_report_low_ack - report non-responding station
> *
> * When operating in AP-mode, call this function to report a non-responding
> @@ -6359,4 +6383,5 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
> struct cfg80211_nan_match_params *match,
> gfp_t gfp);
>
> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable);
> #endif /* MAC80211_H */
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index 09dd1c2860fc..53b56f8fcdfc 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -367,8 +367,15 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
>
> /* reject WEP and TKIP keys if WEP failed to initialize */
> switch (params->cipher) {
> - case WLAN_CIPHER_SUITE_WEP40:
> case WLAN_CIPHER_SUITE_TKIP:
> + /* countermeasures wont work on encap offload mode so reject
> + * TKIP keys
> + */
> + if (ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
> + return -EINVAL;
> +
> + /* drop through */
> + case WLAN_CIPHER_SUITE_WEP40:
> case WLAN_CIPHER_SUITE_WEP104:
> if (IS_ERR(local->wep_tx_tfm))
> return -EINVAL;
> @@ -2379,6 +2386,9 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
> if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
> ieee80211_check_fast_xmit_all(local);
>
> + if (ieee80211_is_hw_80211_encap(local))
> + return -EINVAL;
> +
> err = drv_set_frag_threshold(local, wiphy->frag_threshold);
>
> if (err) {
> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
> index 2d43bc127043..a4df6bca192f 100644
> --- a/net/mac80211/debugfs.c
> +++ b/net/mac80211/debugfs.c
> @@ -221,6 +221,7 @@ static const char *hw_flag_names[] = {
> FLAG(TX_STATUS_NO_AMPDU_LEN),
> FLAG(SUPPORTS_MULTI_BSSID),
> FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
> + FLAG(SUPPORTS_80211_ENCAP),
> #undef FLAG
> };
>
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index e170f986d226..d7569a455a06 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -987,6 +987,8 @@ struct ieee80211_sub_if_data {
> } debugfs;
> #endif
>
> + bool hw_80211_encap;
> +
> /* must be last, dynamically sized area in this! */
> struct ieee80211_vif vif;
> };
> @@ -1732,6 +1734,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
> struct vif_params *params);
> int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
> enum nl80211_iftype type);
> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local);
> void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
> void ieee80211_remove_interfaces(struct ieee80211_local *local);
> u32 ieee80211_idle_off(struct ieee80211_local *local);
> @@ -1759,6 +1762,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
> struct net_device *dev);
> netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
> struct net_device *dev);
> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
> + struct net_device *dev);
> void __ieee80211_subif_start_xmit(struct sk_buff *skb,
> struct net_device *dev,
> u32 info_flags);
> @@ -1933,6 +1938,11 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
> struct sk_buff *skb, int tid,
> enum nl80211_band band, u32 txdata_flags);
>
> +/* sta_out needs to be checked for ERR_PTR() before using */
> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
> + struct sk_buff *skb,
> + struct sta_info **sta_out);
> +
> static inline void
> ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
> struct sk_buff *skb, int tid,
> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
> index 4a6ff1482a9f..4090c2c5fde0 100644
> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -1177,6 +1177,59 @@ static const struct net_device_ops ieee80211_dataif_ops = {
> .ndo_get_stats64 = ieee80211_get_stats64,
> };
>
> +static const struct net_device_ops ieee80211_dataif_8023_ops = {
> + .ndo_open = ieee80211_open,
> + .ndo_stop = ieee80211_stop,
> + .ndo_uninit = ieee80211_uninit,
> + .ndo_start_xmit = ieee80211_subif_start_xmit_8023,
> + .ndo_set_rx_mode = ieee80211_set_multicast_list,
> + .ndo_set_mac_address = ieee80211_change_mac,
> + .ndo_select_queue = ieee80211_netdev_select_queue,
> + .ndo_get_stats64 = ieee80211_get_stats64,
> +};
> +
> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
> +{
> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> + struct ieee80211_local *local = sdata->local;
> +
> + if (!sdata->dev)
> + return;
> +
> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
> + enable = 0;
> +
> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
> + (local->hw.wiphy->frag_threshold != (u32)-1))
> + enable = 0;
> +
> + if (enable) {
> + sdata->dev->netdev_ops = &ieee80211_dataif_8023_ops;
> + sdata->hw_80211_encap = true;
> + } else {
> + sdata->dev->netdev_ops = &ieee80211_dataif_ops;
> + sdata->hw_80211_encap = false;
> + }
> +}
> +EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
> +
> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local)
> +{
> + struct ieee80211_sub_if_data *sdata;
> + bool offloaded = false;
> +
> + mutex_lock(&local->iflist_mtx);
> + list_for_each_entry(sdata, &local->interfaces, list) {
> + if (sdata->hw_80211_encap) {
> + offloaded = true;
> + break;
> + }
> + }
> + mutex_unlock(&local->iflist_mtx);
> +
> + return offloaded;
> +}
> +
> static u16 ieee80211_monitor_select_queue(struct net_device *dev,
> struct sk_buff *skb,
> struct net_device *sb_dev,
> @@ -1409,6 +1462,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
> sdata->vif.bss_conf.idle = true;
>
> sdata->noack_map = 0;
> + sdata->hw_80211_encap = false;
>
> /* only monitor/p2p-device differ */
> if (sdata->dev) {
> diff --git a/net/mac80211/key.c b/net/mac80211/key.c
> index 4700718e010f..861b67d43eb7 100644
> --- a/net/mac80211/key.c
> +++ b/net/mac80211/key.c
> @@ -197,6 +197,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
> key->conf.keyidx,
> sta ? sta->sta.addr : bcast_addr, ret);
>
> + if (sdata->hw_80211_encap)
> + return -EINVAL;
> +
> out_unsupported:
> switch (key->conf.cipher) {
> case WLAN_CIPHER_SUITE_WEP40:
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 800e67615e2a..a49bcec3891e 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -1000,9 +1000,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
> hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
> }
>
> - /* mac80211 always supports monitor */
> - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
> - hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
> + if (ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)) {
> + /* mac80211 always supports monitor unless we do 802.11
> + * encapsulation offloading.
> + */
> + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
> + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
> + }
>
> /* mac80211 doesn't support more than one IBSS interface right now */
> for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
> diff --git a/net/mac80211/status.c b/net/mac80211/status.c
> index 5b9952b1caf3..8feafaab88a4 100644
> --- a/net/mac80211/status.c
> +++ b/net/mac80211/status.c
> @@ -1019,6 +1019,85 @@ void ieee80211_tx_rate_update(struct ieee80211_hw *hw,
> }
> EXPORT_SYMBOL(ieee80211_tx_rate_update);
>
> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + struct sk_buff *skb)
> +{
> + struct ieee80211_local *local = hw_to_local(hw);
> + struct ieee80211_sub_if_data *sdata;
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> + struct sta_info *sta;
> + int retry_count;
> + int rates_idx;
> + bool acked;
> +
> + if (WARN_ON(!ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)))
> + goto skip_stats_update;
> +
> + sdata = vif_to_sdata(vif);
> +
> + acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
> + rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
> +
> + rcu_read_lock();
> +
> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
> + rcu_read_unlock();
> + goto counters_update;
> + }
> +
> + if (!sta || IS_ERR(sta)) {
> + rcu_read_unlock();
> + goto counters_update;
> + }
> +
> + if (!acked)
> + sta->status_stats.retry_failed++;
> +
> + if (rates_idx != -1)
> + sta->tx_stats.last_rate = info->status.rates[rates_idx];
> +
> + sta->status_stats.retry_count += retry_count;
> +
> + if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
> + if (acked && vif->type == NL80211_IFTYPE_STATION)
> + ieee80211_sta_reset_conn_monitor(sdata);
> +
> + sta->status_stats.last_ack = jiffies;
> + if (info->flags & IEEE80211_TX_STAT_ACK) {
> + if (sta->status_stats.lost_packets)
> + sta->status_stats.lost_packets = 0;
> +
> + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
> + sta->status_stats.last_tdls_pkt_time = jiffies;
> + } else {
> + ieee80211_lost_packet(sta, info);
> + }
> + }
> +
> + rcu_read_unlock();
> +
> +counters_update:
> + ieee80211_led_tx(local);
> +
> + if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
> + !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
> + goto skip_stats_update;
> +
> + I802_DEBUG_INC(local->dot11TransmittedFrameCount);
> + if (is_multicast_ether_addr(skb->data))
> + I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
> + if (retry_count > 0)
> + I802_DEBUG_INC(local->dot11RetryCount);
> + if (retry_count > 1)
> + I802_DEBUG_INC(local->dot11MultipleRetryCount);
> +
> +skip_stats_update:
> + ieee80211_report_used_skb(local, skb, false);
> + dev_kfree_skb(skb);
> +}
> +EXPORT_SYMBOL(ieee80211_tx_status_8023);
> +
> void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
> {
> struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 8a49a74c0a37..85356c208c02 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -1253,7 +1253,8 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
> (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
> return NULL;
>
> - if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
> + if (!info->control.hw_80211_encap &&
> + unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
> if ((!ieee80211_is_mgmt(hdr->frame_control) ||
> ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
> vif->type == NL80211_IFTYPE_STATION) &&
> @@ -1400,6 +1401,7 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
> struct fq *fq = &local->fq;
> struct fq_tin *tin = &txqi->tin;
>
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> ieee80211_set_skb_enqueue_time(skb);
> fq_tin_enqueue(fq, tin, skb,
> fq_skb_free_func,
> @@ -2357,9 +2359,9 @@ static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
> skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
> }
>
> -static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
> - struct sk_buff *skb,
> - struct sta_info **sta_out)
> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
> + struct sk_buff *skb,
> + struct sta_info **sta_out)
> {
> struct sta_info *sta;
>
> @@ -2855,7 +2857,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
> struct ieee80211_chanctx_conf *chanctx_conf;
> __le16 fc;
>
> - if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT))
> + /* check for driver support and ieee80211 encap offload */
> + if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT) ||
> + sdata->hw_80211_encap)
> return;
>
> /* Locking here protects both the pointer itself, and against concurrent
> @@ -3554,6 +3558,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
> hdr = (struct ieee80211_hdr *)skb->data;
> info = IEEE80211_SKB_CB(skb);
>
> + if (info->control.hw_80211_encap)
> + goto out;
> +
> memset(&tx, 0, sizeof(tx));
> __skb_queue_head_init(&tx.skbs);
> tx.local = local;
> @@ -4003,6 +4010,167 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
> return NETDEV_TX_OK;
> }
>
> +static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
> + struct sk_buff *skb, int led_len,
> + struct sta_info *sta,
> + bool txpending)
> +{
> + struct ieee80211_local *local = sdata->local;
> + struct ieee80211_tx_control control = {};
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> + struct ieee80211_sta *pubsta = NULL;
> + unsigned long flags;
> + int q = info->hw_queue;
> +
> + if (ieee80211_queue_skb(local, sdata, sta, skb))
> + return true;
ieee80211_queue_skb() calls ieee80211_get_txq() which treats skb->data
like it contains an 802.11 header. That is probably not the intention
here, is it?
I guess we could augment the TXQ stuctures to also handle 802.3 frames
(and introduce ieee80211_queue_skb_8023())? Or would it be better to
have a qdisc on 802.3-mode interfaces and push packets back to that? I
guess we'd still benefit from per-station queueing of packets even if
they are Ethernet frames, which would mean amending the TXQs would be
better?
-Toke
^ permalink raw reply
* [PATCH v2 4/4] mt76: dma: add skb check for dummy pointer
From: Lorenzo Bianconi @ 2019-04-02 9:47 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, lorenzo.bianconi, linux-wireless
In-Reply-To: <cover.1554194917.git.lorenzo@kernel.org>
Introduce skb check for dummy address in mt76_dma_tx_cleanup_idx.
This is a preliminary patch to add support for new chipsets (e.g. 7615)
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 9 +++++----
drivers/net/wireless/mediatek/mt76/dma.h | 2 ++
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 2bc5dd9a9e9f..4ed3ea53a16d 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -18,8 +18,6 @@
#include "mt76.h"
#include "dma.h"
-#define DMA_DUMMY_TXWI ((void *) ~0)
-
static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize,
@@ -67,7 +65,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
int i, idx = -1;
if (txwi)
- q->entry[q->head].txwi = DMA_DUMMY_TXWI;
+ q->entry[q->head].txwi = DMA_DUMMY_DATA;
for (i = 0; i < nbufs; i += 2, buf += 2) {
u32 buf0 = buf[0].addr, buf1 = 0;
@@ -126,9 +124,12 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
DMA_TO_DEVICE);
}
- if (e->txwi == DMA_DUMMY_TXWI)
+ if (e->txwi == DMA_DUMMY_DATA)
e->txwi = NULL;
+ if (e->skb == DMA_DUMMY_DATA)
+ e->skb = NULL;
+
*prev_e = *e;
memset(e, 0, sizeof(*e));
}
diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h
index e3292df5e9b2..03dd2bafa4e8 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.h
+++ b/drivers/net/wireless/mediatek/mt76/dma.h
@@ -16,6 +16,8 @@
#ifndef __MT76_DMA_H
#define __MT76_DMA_H
+#define DMA_DUMMY_DATA ((void *)~0)
+
#define MT_RING_SIZE 0x10
#define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0)
--
2.20.1
^ permalink raw reply related
* [PATCH v2 3/4] mt76: dma: introduce skb field in mt76_txwi_cache
From: Lorenzo Bianconi @ 2019-04-02 9:47 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, lorenzo.bianconi, linux-wireless
In-Reply-To: <cover.1554194917.git.lorenzo@kernel.org>
Introduce skb field in mt76_txwi_cache. Moreover add txwi_flags
to mt76_driver_ops since new chipsets will release mt76_txwi_cache/skbs
at tx completion instead of dma one.
This is a preliminary patch to add mt7615 support
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 3 ++-
drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++++
drivers/net/wireless/mediatek/mt76/tx.c | 1 +
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 54e6d985d384..2bc5dd9a9e9f 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -176,7 +176,8 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
}
if (entry.txwi) {
- mt76_put_txwi(dev, entry.txwi);
+ if (!(dev->drv->txwi_flags & MT_TXWI_NO_FREE))
+ mt76_put_txwi(dev, entry.txwi);
wake = !flush;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 91f9433bf979..665f843008d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -231,6 +231,8 @@ struct mt76_txq {
struct mt76_txwi_cache {
struct list_head list;
dma_addr_t dma_addr;
+
+ struct sk_buff *skb;
};
struct mt76_rx_tid {
@@ -284,8 +286,11 @@ struct mt76_hw_cap {
bool has_5ghz;
};
+#define MT_TXWI_NO_FREE BIT(0)
+
struct mt76_driver_ops {
bool tx_aligned4_skbs;
+ u32 txwi_flags;
u16 txwi_size;
void (*update_survey)(struct mt76_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 08587d262469..6a0c4b8a649d 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -74,6 +74,7 @@ mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
list_add(&t->list, &dev->txwi_cache);
spin_unlock_bh(&dev->lock);
}
+EXPORT_SYMBOL_GPL(mt76_put_txwi);
void mt76_tx_free(struct mt76_dev *dev)
{
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/4] mt76: add skb pointer to mt76_tx_info
From: Lorenzo Bianconi @ 2019-04-02 9:47 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, lorenzo.bianconi, linux-wireless
In-Reply-To: <cover.1554194917.git.lorenzo@kernel.org>
Pass skb pointer to tx_prepare_skb through mt76_tx_info data structure.
This is a preliminary patch to properly support dma error path for
new chipsets (e.g. 7615)
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 11 ++++++-----
drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++--
.../net/wireless/mediatek/mt76/mt7603/mac.c | 11 ++++++-----
.../net/wireless/mediatek/mt76/mt7603/mt7603.h | 4 ++--
drivers/net/wireless/mediatek/mt76/mt76x02.h | 4 ++--
.../net/wireless/mediatek/mt76/mt76x02_txrx.c | 12 ++++++------
.../net/wireless/mediatek/mt76/mt76x02_usb.h | 4 ++--
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 18 +++++++++---------
drivers/net/wireless/mediatek/mt76/usb.c | 14 ++++++++------
9 files changed, 43 insertions(+), 39 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index e0286fae8e79..54e6d985d384 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -284,7 +284,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
struct ieee80211_sta *sta)
{
struct mt76_queue *q = dev->q_tx[qid].q;
- struct mt76_tx_info tx_info = {};
+ struct mt76_tx_info tx_info = {
+ .skb = skb,
+ };
int len, n = 0, ret = -ENOMEM;
struct mt76_queue_entry e;
struct mt76_txwi_cache *t;
@@ -329,8 +331,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
dma_sync_single_for_cpu(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
- ret = dev->drv->tx_prepare_skb(dev, txwi, skb, qid, wcid, sta,
- &tx_info);
+ ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info);
dma_sync_single_for_device(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
if (ret < 0)
@@ -342,7 +343,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
}
return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf,
- tx_info.info, skb, t);
+ tx_info.info, tx_info.skb, t);
unmap:
for (n--; n > 0; n--)
@@ -350,7 +351,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
tx_info.buf[n].len, DMA_TO_DEVICE);
free:
- e.skb = skb;
+ e.skb = tx_info.skb;
e.txwi = t;
dev->drv->tx_complete_skb(dev, qid, &e);
mt76_put_txwi(dev, t);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 277f6b754693..91f9433bf979 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -85,6 +85,7 @@ struct mt76_queue_buf {
struct mt76_tx_info {
struct mt76_queue_buf buf[32];
+ struct sk_buff *skb;
int nbuf;
u32 info;
};
@@ -290,8 +291,7 @@ struct mt76_driver_ops {
void (*update_survey)(struct mt76_dev *dev);
int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index 5f800467c628..b38b89a89322 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -937,13 +937,13 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
}
int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
int pid;
@@ -959,7 +959,7 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
mt7603_wtbl_set_ps(dev, msta, false);
}
- pid = mt76_tx_status_skb_add(mdev, wcid, skb);
+ pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
spin_lock_bh(&dev->mt76.lock);
@@ -969,7 +969,8 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
spin_unlock_bh(&dev->mt76.lock);
}
- mt7603_mac_write_txwi(dev, txwi_ptr, skb, qid, wcid, sta, pid, key);
+ mt7603_mac_write_txwi(dev, txwi_ptr, tx_info->skb, qid, wcid,
+ sta, pid, key);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index 9cc8ca7a4d1c..72352559a212 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -223,8 +223,8 @@ void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
void mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort);
int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 0d817a142e76..fdf2f32b26dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -184,8 +184,8 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance);
void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb);
int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt76x02_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
index dd7d04b9b8db..cf7abd9b7d2e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
@@ -147,12 +147,12 @@ bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update)
EXPORT_SYMBOL_GPL(mt76x02_tx_status_data);
int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
struct mt76x02_txwi *txwi = txwi_ptr;
int hdrlen, len, pid, qsel = MT_QSEL_EDCA;
@@ -160,10 +160,10 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
mt76x02_mac_wcid_set_drop(dev, wcid->idx, false);
hdrlen = ieee80211_hdrlen(hdr->frame_control);
- len = skb->len - (hdrlen & 2);
- mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
+ len = tx_info->skb->len - (hdrlen & 2);
+ mt76x02_mac_write_txwi(dev, txwi, tx_info->skb, wcid, sta, len);
- pid = mt76_tx_status_skb_add(mdev, wcid, skb);
+ pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
txwi->pktid = pid;
if (pid >= MT_PACKET_ID_FIRST)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
index a012410c5ae7..7b53f9e57f29 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
@@ -26,8 +26,8 @@ int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data,
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags);
int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
struct mt76_queue_entry *e);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index c403218533da..818b96064dec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -72,23 +72,23 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
}
int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
- struct sk_buff *skb, enum mt76_txq_id qid,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
- int pid, len = skb->len, ep = q2ep(mdev->q_tx[qid].q->hw_idx);
+ int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid].q->hw_idx);
struct mt76x02_txwi *txwi;
enum mt76_qsel qsel;
u32 flags;
- mt76_insert_hdr_pad(skb);
+ mt76_insert_hdr_pad(tx_info->skb);
- txwi = (struct mt76x02_txwi *)(skb->data - sizeof(struct mt76x02_txwi));
- mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
- skb_push(skb, sizeof(struct mt76x02_txwi));
+ txwi = (struct mt76x02_txwi *)(tx_info->skb->data - sizeof(*txwi));
+ mt76x02_mac_write_txwi(dev, txwi, tx_info->skb, wcid, sta, len);
+ skb_push(tx_info->skb, sizeof(*txwi));
- pid = mt76_tx_status_skb_add(mdev, wcid, skb);
+ pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
txwi->pktid = pid;
if (pid >= MT_PACKET_ID_FIRST || ep == MT_EP_OUT_HCCA)
@@ -101,7 +101,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
flags |= MT_TXD_INFO_WIV;
- return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags);
+ return mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags);
}
EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb);
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 3b5d30eaa31f..070eef631c43 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -735,7 +735,9 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
struct ieee80211_sta *sta)
{
struct mt76_queue *q = dev->q_tx[qid].q;
- struct urb *urb;
+ struct mt76_tx_info tx_info = {
+ .skb = skb,
+ };
u16 idx = q->tail;
int err;
@@ -743,20 +745,20 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
return -ENOSPC;
skb->prev = skb->next = NULL;
- err = dev->drv->tx_prepare_skb(dev, NULL, skb, qid, wcid, sta, NULL);
+ err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
if (err < 0)
return err;
- urb = q->entry[idx].urb;
- err = mt76u_tx_setup_buffers(dev, skb, urb);
+ err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb);
if (err < 0)
return err;
mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q2ep(q->hw_idx),
- urb, mt76u_complete_tx, &q->entry[idx]);
+ q->entry[idx].urb, mt76u_complete_tx,
+ &q->entry[idx]);
q->tail = (q->tail + 1) % q->ndesc;
- q->entry[idx].skb = skb;
+ q->entry[idx].skb = tx_info.skb;
q->queued++;
return idx;
--
2.20.1
^ permalink raw reply related
* [PATCH v2 1/4] mt76: set txwi_size according to the driver value
From: Lorenzo Bianconi @ 2019-04-02 9:47 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, lorenzo.bianconi, linux-wireless
In-Reply-To: <cover.1554194917.git.lorenzo@kernel.org>
Dynamically allocate txwi since new chipsets will use longer txwi
descriptors
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 8 +++++---
drivers/net/wireless/mediatek/mt76/mt76.h | 10 +++++++---
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 +++-
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 -
drivers/net/wireless/mediatek/mt76/tx.c | 12 +++++++-----
5 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 7b8a998103d7..e0286fae8e79 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -290,12 +290,14 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
struct mt76_txwi_cache *t;
struct sk_buff *iter;
dma_addr_t addr;
+ u8 *txwi;
t = mt76_get_txwi(dev);
if (!t) {
ieee80211_free_txskb(dev->hw, skb);
return -ENOMEM;
}
+ txwi = mt76_get_txwi_ptr(dev, t);
skb->prev = skb->next = NULL;
if (dev->drv->tx_aligned4_skbs)
@@ -325,11 +327,11 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
}
tx_info.nbuf = n;
- dma_sync_single_for_cpu(dev->dev, t->dma_addr, sizeof(t->txwi),
+ dma_sync_single_for_cpu(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
- ret = dev->drv->tx_prepare_skb(dev, &t->txwi, skb, qid, wcid, sta,
+ ret = dev->drv->tx_prepare_skb(dev, txwi, skb, qid, wcid, sta,
&tx_info);
- dma_sync_single_for_device(dev->dev, t->dma_addr, sizeof(t->txwi),
+ dma_sync_single_for_device(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
if (ret < 0)
goto unmap;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index b432da3f55c7..277f6b754693 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -228,12 +228,10 @@ struct mt76_txq {
};
struct mt76_txwi_cache {
- u32 txwi[8];
- dma_addr_t dma_addr;
struct list_head list;
+ dma_addr_t dma_addr;
};
-
struct mt76_rx_tid {
struct rcu_head rcu_head;
@@ -613,6 +611,12 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_dev *dev);
+static inline u8 *
+mt76_get_txwi_ptr(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+{
+ return (u8 *)t - dev->drv->txwi_size;
+}
+
/* increment with wrap-around */
static inline int mt76_incr(int val, int size)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 1eb669ccd5a7..ffedb8e5d227 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -760,6 +760,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
struct mt76x02_txwi *txwi;
+ u8 *txwi_ptr;
if (!e->txwi) {
dev_kfree_skb_any(e->skb);
@@ -768,7 +769,8 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
mt76x02_mac_poll_tx_status(dev, false);
- txwi = (struct mt76x02_txwi *) &e->txwi->txwi;
+ txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi);
+ txwi = (struct mt76x02_txwi *)txwi_ptr;
trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid);
mt76_tx_complete_skb(mdev, e->skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index 3116aa935ee4..518dea4b9425 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -174,7 +174,6 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
struct mt76_queue *q;
void *status_fifo;
- BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi));
BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM);
fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status));
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 2c82db0b5834..08587d262469 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -21,15 +21,17 @@ mt76_alloc_txwi(struct mt76_dev *dev)
{
struct mt76_txwi_cache *t;
dma_addr_t addr;
+ u8 *txwi;
int size;
- size = (sizeof(*t) + L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES - 1);
- t = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
- if (!t)
+ size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
+ txwi = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
+ if (!txwi)
return NULL;
- addr = dma_map_single(dev->dev, &t->txwi, sizeof(t->txwi),
+ addr = dma_map_single(dev->dev, txwi, dev->drv->txwi_size,
DMA_TO_DEVICE);
+ t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
t->dma_addr = addr;
return t;
@@ -78,7 +80,7 @@ void mt76_tx_free(struct mt76_dev *dev)
struct mt76_txwi_cache *t;
while ((t = __mt76_get_txwi(dev)) != NULL)
- dma_unmap_single(dev->dev, t->dma_addr, sizeof(t->txwi),
+ dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
}
--
2.20.1
^ permalink raw reply related
* [PATCH v2 0/4] add missing bits for mt7615 support
From: Lorenzo Bianconi @ 2019-04-02 9:47 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, lorenzo.bianconi, linux-wireless
This is a preliminary series to add support for mt7615.
Dynamically allocate txwi descriptor.
Add missing bit in dma error data path.
This series is based on https://patchwork.kernel.org/patch/10856027/
Changes since v1:
- remove flags from mt76_txwi_cache
Lorenzo Bianconi (4):
mt76: set txwi_size according to the driver value
mt76: add skb pointer to mt76_tx_info
mt76: dma: introduce skb field in mt76_txwi_cache
mt76: dma: add skb check for dummy pointer
drivers/net/wireless/mediatek/mt76/dma.c | 29 +++++++++++--------
drivers/net/wireless/mediatek/mt76/dma.h | 2 ++
drivers/net/wireless/mediatek/mt76/mt76.h | 19 ++++++++----
.../net/wireless/mediatek/mt76/mt7603/mac.c | 11 +++----
.../wireless/mediatek/mt76/mt7603/mt7603.h | 4 +--
drivers/net/wireless/mediatek/mt76/mt76x02.h | 4 +--
.../net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++-
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 -
.../net/wireless/mediatek/mt76/mt76x02_txrx.c | 12 ++++----
.../net/wireless/mediatek/mt76/mt76x02_usb.h | 4 +--
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 18 ++++++------
drivers/net/wireless/mediatek/mt76/tx.c | 13 +++++----
drivers/net/wireless/mediatek/mt76/usb.c | 14 +++++----
13 files changed, 79 insertions(+), 56 deletions(-)
--
2.20.1
^ permalink raw reply
* Re: [RFC V3 1/2] mac80211: add hw 80211 encapsulation offloading support
From: Sebastian Gottschall @ 2019-04-02 9:31 UTC (permalink / raw)
To: John Crispin, Johannes Berg, Kalle Valo
Cc: linux-wireless, Shashidhar Lakkavalli, Vasanthakumar Thiagarajan
In-Reply-To: <20190401131416.22646-2-john@phrozen.org>
the introduced control field hw_80211_encap in ieee80211_tx_info leads
to a compile assert
/include/linux/compiler.h:522:38: error: call to
'__compiletime_assert_1307' declared with attribute error: BUILD_BUG_ON
failed: sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)
skb->cb is to small on x64 devices
i suggest to implement hw_80211_encap in ieee80211_vif which is a member
of control in ieee80211_tx_info
Sebastian
Am 01.04.2019 um 15:14 schrieb John Crispin:
> From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
>
> This patch adds a new transmit path for hardware that supports 802.11
> encapsulation offloading. In those cases 802.3a frames get passed
> directly to the driver allowing to hardware to handle the encapsulation.
>
> Certain features wont work and the patch masks these out.
> * monitor interfaces are not supported if any of the vif is in encap mode.
> * amsdu/non-linear frames wont work in encap offloading mode.
> * TKIP countermeasures cannot be triggered and hence those keys are not
> accepted.
>
> The patch defines a secondary netdev_ops struct that the device is assigned
> to the device if 802.11 encap support is available and enabled. The driver
> needs to enable the support on a per vif basis if it finds that all
> pre-reqs are meet.
>
> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
> Signed-off-by: John Crispin <john@phrozen.org>
> ---
> include/net/mac80211.h | 25 ++++++
> net/mac80211/cfg.c | 12 ++-
> net/mac80211/debugfs.c | 1 +
> net/mac80211/ieee80211_i.h | 10 +++
> net/mac80211/iface.c | 54 +++++++++++++
> net/mac80211/key.c | 3 +
> net/mac80211/main.c | 10 ++-
> net/mac80211/status.c | 79 +++++++++++++++++++
> net/mac80211/tx.c | 188 +++++++++++++++++++++++++++++++++++++++++++--
> 9 files changed, 373 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index ac2ed8ec662b..3e8929770839 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -1021,6 +1021,7 @@ struct ieee80211_tx_info {
> struct ieee80211_key_conf *hw_key;
> u32 flags;
> codel_time_t enqueue_time;
> + u8 hw_80211_encap;
> } control;
> struct {
> u64 cookie;
> @@ -2243,6 +2244,9 @@ struct ieee80211_txq {
> * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
> * only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
> *
> + * @IEEE80211_HW_SUPPORTS_80211_ENCAP: Hardware/driver supports 802.11
> + * encap for data frames.
> + *
> * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
> */
> enum ieee80211_hw_flags {
> @@ -2294,6 +2298,7 @@ enum ieee80211_hw_flags {
> IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
> IEEE80211_HW_SUPPORTS_MULTI_BSSID,
> IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
> + IEEE80211_HW_SUPPORTS_80211_ENCAP,
>
> /* keep last, obviously */
> NUM_IEEE80211_HW_FLAGS
> @@ -4587,6 +4592,25 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
> struct sk_buff *skb);
>
> /**
> + * ieee80211_tx_status_8023 - transmit status callback for 802.3 frame format
> + *
> + * Call this function for all transmitted data frames after their transmit
> + * completion. This callback should only be called for data frames which
> + * are are using driver's (or hardware's) offload capability of encap/decap
> + * 802.11 frames.
> + *
> + * This function may not be called in IRQ context. Calls to this function
> + * for a single hardware must be synchronized against each other.
> + *
> + * @hw: the hardware the frame was transmitted by
> + * @vif: the interface for which the frame was transmitted
> + * @skb: the frame that was transmitted, owned by mac80211 after this call
> + */
> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + struct sk_buff *skb);
> +
> +/**
> * ieee80211_report_low_ack - report non-responding station
> *
> * When operating in AP-mode, call this function to report a non-responding
> @@ -6359,4 +6383,5 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
> struct cfg80211_nan_match_params *match,
> gfp_t gfp);
>
> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable);
> #endif /* MAC80211_H */
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index 09dd1c2860fc..53b56f8fcdfc 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -367,8 +367,15 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
>
> /* reject WEP and TKIP keys if WEP failed to initialize */
> switch (params->cipher) {
> - case WLAN_CIPHER_SUITE_WEP40:
> case WLAN_CIPHER_SUITE_TKIP:
> + /* countermeasures wont work on encap offload mode so reject
> + * TKIP keys
> + */
> + if (ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
> + return -EINVAL;
> +
> + /* drop through */
> + case WLAN_CIPHER_SUITE_WEP40:
> case WLAN_CIPHER_SUITE_WEP104:
> if (IS_ERR(local->wep_tx_tfm))
> return -EINVAL;
> @@ -2379,6 +2386,9 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
> if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
> ieee80211_check_fast_xmit_all(local);
>
> + if (ieee80211_is_hw_80211_encap(local))
> + return -EINVAL;
> +
> err = drv_set_frag_threshold(local, wiphy->frag_threshold);
>
> if (err) {
> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
> index 2d43bc127043..a4df6bca192f 100644
> --- a/net/mac80211/debugfs.c
> +++ b/net/mac80211/debugfs.c
> @@ -221,6 +221,7 @@ static const char *hw_flag_names[] = {
> FLAG(TX_STATUS_NO_AMPDU_LEN),
> FLAG(SUPPORTS_MULTI_BSSID),
> FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
> + FLAG(SUPPORTS_80211_ENCAP),
> #undef FLAG
> };
>
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index e170f986d226..d7569a455a06 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -987,6 +987,8 @@ struct ieee80211_sub_if_data {
> } debugfs;
> #endif
>
> + bool hw_80211_encap;
> +
> /* must be last, dynamically sized area in this! */
> struct ieee80211_vif vif;
> };
> @@ -1732,6 +1734,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
> struct vif_params *params);
> int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
> enum nl80211_iftype type);
> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local);
> void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
> void ieee80211_remove_interfaces(struct ieee80211_local *local);
> u32 ieee80211_idle_off(struct ieee80211_local *local);
> @@ -1759,6 +1762,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
> struct net_device *dev);
> netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
> struct net_device *dev);
> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
> + struct net_device *dev);
> void __ieee80211_subif_start_xmit(struct sk_buff *skb,
> struct net_device *dev,
> u32 info_flags);
> @@ -1933,6 +1938,11 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
> struct sk_buff *skb, int tid,
> enum nl80211_band band, u32 txdata_flags);
>
> +/* sta_out needs to be checked for ERR_PTR() before using */
> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
> + struct sk_buff *skb,
> + struct sta_info **sta_out);
> +
> static inline void
> ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
> struct sk_buff *skb, int tid,
> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
> index 4a6ff1482a9f..4090c2c5fde0 100644
> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -1177,6 +1177,59 @@ static const struct net_device_ops ieee80211_dataif_ops = {
> .ndo_get_stats64 = ieee80211_get_stats64,
> };
>
> +static const struct net_device_ops ieee80211_dataif_8023_ops = {
> + .ndo_open = ieee80211_open,
> + .ndo_stop = ieee80211_stop,
> + .ndo_uninit = ieee80211_uninit,
> + .ndo_start_xmit = ieee80211_subif_start_xmit_8023,
> + .ndo_set_rx_mode = ieee80211_set_multicast_list,
> + .ndo_set_mac_address = ieee80211_change_mac,
> + .ndo_select_queue = ieee80211_netdev_select_queue,
> + .ndo_get_stats64 = ieee80211_get_stats64,
> +};
> +
> +void ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
> +{
> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> + struct ieee80211_local *local = sdata->local;
> +
> + if (!sdata->dev)
> + return;
> +
> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_80211_ENCAP))
> + enable = 0;
> +
> + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
> + (local->hw.wiphy->frag_threshold != (u32)-1))
> + enable = 0;
> +
> + if (enable) {
> + sdata->dev->netdev_ops = &ieee80211_dataif_8023_ops;
> + sdata->hw_80211_encap = true;
> + } else {
> + sdata->dev->netdev_ops = &ieee80211_dataif_ops;
> + sdata->hw_80211_encap = false;
> + }
> +}
> +EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
> +
> +bool ieee80211_is_hw_80211_encap(struct ieee80211_local *local)
> +{
> + struct ieee80211_sub_if_data *sdata;
> + bool offloaded = false;
> +
> + mutex_lock(&local->iflist_mtx);
> + list_for_each_entry(sdata, &local->interfaces, list) {
> + if (sdata->hw_80211_encap) {
> + offloaded = true;
> + break;
> + }
> + }
> + mutex_unlock(&local->iflist_mtx);
> +
> + return offloaded;
> +}
> +
> static u16 ieee80211_monitor_select_queue(struct net_device *dev,
> struct sk_buff *skb,
> struct net_device *sb_dev,
> @@ -1409,6 +1462,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
> sdata->vif.bss_conf.idle = true;
>
> sdata->noack_map = 0;
> + sdata->hw_80211_encap = false;
>
> /* only monitor/p2p-device differ */
> if (sdata->dev) {
> diff --git a/net/mac80211/key.c b/net/mac80211/key.c
> index 4700718e010f..861b67d43eb7 100644
> --- a/net/mac80211/key.c
> +++ b/net/mac80211/key.c
> @@ -197,6 +197,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
> key->conf.keyidx,
> sta ? sta->sta.addr : bcast_addr, ret);
>
> + if (sdata->hw_80211_encap)
> + return -EINVAL;
> +
> out_unsupported:
> switch (key->conf.cipher) {
> case WLAN_CIPHER_SUITE_WEP40:
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 800e67615e2a..a49bcec3891e 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -1000,9 +1000,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
> hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
> }
>
> - /* mac80211 always supports monitor */
> - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
> - hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
> + if (ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)) {
> + /* mac80211 always supports monitor unless we do 802.11
> + * encapsulation offloading.
> + */
> + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
> + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
> + }
>
> /* mac80211 doesn't support more than one IBSS interface right now */
> for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
> diff --git a/net/mac80211/status.c b/net/mac80211/status.c
> index 5b9952b1caf3..8feafaab88a4 100644
> --- a/net/mac80211/status.c
> +++ b/net/mac80211/status.c
> @@ -1019,6 +1019,85 @@ void ieee80211_tx_rate_update(struct ieee80211_hw *hw,
> }
> EXPORT_SYMBOL(ieee80211_tx_rate_update);
>
> +void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + struct sk_buff *skb)
> +{
> + struct ieee80211_local *local = hw_to_local(hw);
> + struct ieee80211_sub_if_data *sdata;
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> + struct sta_info *sta;
> + int retry_count;
> + int rates_idx;
> + bool acked;
> +
> + if (WARN_ON(!ieee80211_hw_check(hw, SUPPORTS_80211_ENCAP)))
> + goto skip_stats_update;
> +
> + sdata = vif_to_sdata(vif);
> +
> + acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
> + rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
> +
> + rcu_read_lock();
> +
> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
> + rcu_read_unlock();
> + goto counters_update;
> + }
> +
> + if (!sta || IS_ERR(sta)) {
> + rcu_read_unlock();
> + goto counters_update;
> + }
> +
> + if (!acked)
> + sta->status_stats.retry_failed++;
> +
> + if (rates_idx != -1)
> + sta->tx_stats.last_rate = info->status.rates[rates_idx];
> +
> + sta->status_stats.retry_count += retry_count;
> +
> + if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
> + if (acked && vif->type == NL80211_IFTYPE_STATION)
> + ieee80211_sta_reset_conn_monitor(sdata);
> +
> + sta->status_stats.last_ack = jiffies;
> + if (info->flags & IEEE80211_TX_STAT_ACK) {
> + if (sta->status_stats.lost_packets)
> + sta->status_stats.lost_packets = 0;
> +
> + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
> + sta->status_stats.last_tdls_pkt_time = jiffies;
> + } else {
> + ieee80211_lost_packet(sta, info);
> + }
> + }
> +
> + rcu_read_unlock();
> +
> +counters_update:
> + ieee80211_led_tx(local);
> +
> + if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
> + !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
> + goto skip_stats_update;
> +
> + I802_DEBUG_INC(local->dot11TransmittedFrameCount);
> + if (is_multicast_ether_addr(skb->data))
> + I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
> + if (retry_count > 0)
> + I802_DEBUG_INC(local->dot11RetryCount);
> + if (retry_count > 1)
> + I802_DEBUG_INC(local->dot11MultipleRetryCount);
> +
> +skip_stats_update:
> + ieee80211_report_used_skb(local, skb, false);
> + dev_kfree_skb(skb);
> +}
> +EXPORT_SYMBOL(ieee80211_tx_status_8023);
> +
> void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
> {
> struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 8a49a74c0a37..85356c208c02 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -1253,7 +1253,8 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
> (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
> return NULL;
>
> - if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
> + if (!info->control.hw_80211_encap &&
> + unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
> if ((!ieee80211_is_mgmt(hdr->frame_control) ||
> ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
> vif->type == NL80211_IFTYPE_STATION) &&
> @@ -1400,6 +1401,7 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
> struct fq *fq = &local->fq;
> struct fq_tin *tin = &txqi->tin;
>
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> ieee80211_set_skb_enqueue_time(skb);
> fq_tin_enqueue(fq, tin, skb,
> fq_skb_free_func,
> @@ -2357,9 +2359,9 @@ static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
> skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
> }
>
> -static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
> - struct sk_buff *skb,
> - struct sta_info **sta_out)
> +int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
> + struct sk_buff *skb,
> + struct sta_info **sta_out)
> {
> struct sta_info *sta;
>
> @@ -2855,7 +2857,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
> struct ieee80211_chanctx_conf *chanctx_conf;
> __le16 fc;
>
> - if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT))
> + /* check for driver support and ieee80211 encap offload */
> + if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT) ||
> + sdata->hw_80211_encap)
> return;
>
> /* Locking here protects both the pointer itself, and against concurrent
> @@ -3554,6 +3558,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
> hdr = (struct ieee80211_hdr *)skb->data;
> info = IEEE80211_SKB_CB(skb);
>
> + if (info->control.hw_80211_encap)
> + goto out;
> +
> memset(&tx, 0, sizeof(tx));
> __skb_queue_head_init(&tx.skbs);
> tx.local = local;
> @@ -4003,6 +4010,167 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
> return NETDEV_TX_OK;
> }
>
> +static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
> + struct sk_buff *skb, int led_len,
> + struct sta_info *sta,
> + bool txpending)
> +{
> + struct ieee80211_local *local = sdata->local;
> + struct ieee80211_tx_control control = {};
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> + struct ieee80211_sta *pubsta = NULL;
> + unsigned long flags;
> + int q = info->hw_queue;
> +
> + if (ieee80211_queue_skb(local, sdata, sta, skb))
> + return true;
> +
> + spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
> +
> + if (local->queue_stop_reasons[q] ||
> + (!txpending && !skb_queue_empty(&local->pending[q]))) {
> + if (txpending)
> + skb_queue_head(&local->pending[q], skb);
> + else
> + skb_queue_tail(&local->pending[q], skb);
> +
> + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
> +
> + return false;
> + }
> +
> + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
> +
> + if (sta && sta->uploaded)
> + pubsta = &sta->sta;
> +
> + control.sta = pubsta;
> +
> + drv_tx(local, &control, skb);
> +
> + return true;
> +}
> +
> +static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
> + struct net_device *dev, struct sta_info *sta,
> + struct sk_buff *skb)
> +{
> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> + struct ethhdr *ehdr = (struct ethhdr *)skb->data;
> + struct ieee80211_local *local = sdata->local;
> + bool authorized = false;
> + bool multicast;
> + bool tdls_peer;
> + unsigned char *ra = NULL;
> +
> + if (IS_ERR(sta) || (sta && !sta->uploaded))
> + sta = NULL;
> +
> + if (sdata->vif.type == NL80211_IFTYPE_STATION) {
> + tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER);
> + if (tdls_peer)
> + ra = skb->data;
> + else
> + ra = sdata->u.mgd.bssid;
> + } else {
> + ra = ehdr->h_dest;
> + }
> +
> + if (!ra)
> + goto out_free;
> + multicast = is_multicast_ether_addr(ra);
> +
> + if (sta)
> + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
> +
> + if (!multicast && !authorized &&
> + ((ehdr->h_proto != sdata->control_port_protocol) ||
> + !ether_addr_equal(sdata->vif.addr, ehdr->h_source)))
> + goto out_free;
> +
> + if (multicast && sdata->vif.type == NL80211_IFTYPE_AP &&
> + !atomic_read(&sdata->u.ap.num_mcast_sta))
> + goto out_free;
> +
> + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
> + test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
> + goto out_free;
> +
> + /* TODO: Handle frames requiring wifi tx status to be notified */
> +
> + memset(info, 0, sizeof(*info));
> +
> + if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) {
> + if (sdata->control_port_no_encrypt)
> + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
> + info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
> + }
> +
> + if (multicast)
> + info->flags |= IEEE80211_TX_CTL_NO_ACK;
> +
> + info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
> +
> + ieee80211_tx_stats(dev, skb->len);
> +
> + if (sta) {
> + sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
> + sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
> + }
> +
> + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
> + sdata = container_of(sdata->bss,
> + struct ieee80211_sub_if_data, u.ap);
> +
> + info->control.hw_80211_encap = true;
> + info->control.vif = &sdata->vif;
> +
> + ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
> +
> + return;
> +
> +out_free:
> + kfree_skb(skb);
> +}
> +
> +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
> + struct net_device *dev)
> +{
> + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> + struct sta_info *sta;
> +
> + if (WARN_ON(unlikely(!sdata->hw_80211_encap))) {
> + kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> +
> + if (unlikely(skb->len < ETH_HLEN)) {
> + kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> +
> + if (WARN_ON(dev->ieee80211_ptr->use_4addr)) {
> + kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> +
> + rcu_read_lock();
> +
> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
> + goto out_free;
> +
> + ieee80211_8023_xmit(sdata, dev, sta, skb);
> +
> + goto out;
> +
> +out_free:
> + kfree_skb(skb);
> +out:
> + rcu_read_unlock();
> +
> + return NETDEV_TX_OK;
> +}
> +
> struct sk_buff *
> ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
> struct sk_buff *skb, u32 info_flags)
> @@ -4081,6 +4249,16 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
> }
> info->band = chanctx_conf->def.chan->band;
> result = ieee80211_tx(sdata, NULL, skb, true, 0);
> + } else if (info->control.hw_80211_encap) {
> + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
> + dev_kfree_skb(skb);
> + return true;
> + }
> +
> + if (IS_ERR(sta) || (sta && !sta->uploaded))
> + sta = NULL;
> +
> + result = ieee80211_tx_8023(sdata, skb, skb->len, sta, true);
> } else {
> struct sk_buff_head skbs;
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox