> -----Original Message----- > From: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > Sent: Wednesday, March 26, 2025 8:19 PM > To: Brian Norris <briannorris@xxxxxxxxxxxx>; Francesco Dolcini > <francesco@xxxxxxxxxx>; Ulf Hansson <ulf.hansson@xxxxxxxxxx> > Cc: linux-wireless@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; > linux-mmc@xxxxxxxxxxxxxxx; Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > Subject: [EXT] [PATCH do not merge 2/4] wifi: mwifiex: handle VDLL > > Caution: This is an external email. Please take care when clicking links or > opening attachments. When in doubt, report the message using the 'Report > this email' button > > > Some adapters send events to the Kernel requesting VDLL images. When we > receive such an event we have to upload parts of the firmware image to the > device. > > When the firmware requests a VDLL image then we have to bypass the > pending command queue and have to send it immediately. Failing to do so will > cause every other command sent from the queue to timeout. > > There is this check currently in mwifiex_download_vdll_block(): > > if (adapter->cmd_sent) { > mwifiex_dbg(adapter, MSG, "%s: adapter is busy\n", > __func__); > return -EBUSY; > } > > The downstream driver has this check as well. However, the downstream > driver tries to defer sending the VDLL command when this happens. It sets a > variable in the private driver struct where the main process picks it up later. I > am not sure if this can work, because when > adapter->cmd_sent is true then it's already too late, we already missed > to send the VDLL image before the next command. In my tests I never saw the > above trigger, but this surely a place to have a closer look at. > > Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > --- > drivers/net/wireless/marvell/mwifiex/cmdevt.c | 86 > ++++++++++++++++++++++++ > drivers/net/wireless/marvell/mwifiex/fw.h | 16 +++++ > drivers/net/wireless/marvell/mwifiex/main.h | 4 ++ > drivers/net/wireless/marvell/mwifiex/sta_event.c | 4 ++ > drivers/net/wireless/marvell/mwifiex/uap_event.c | 4 ++ > 5 files changed, 114 insertions(+) > > diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c > b/drivers/net/wireless/marvell/mwifiex/cmdevt.c > index b30ed321c6251..916d0b804bec3 100644 > --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c > +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c > @@ -1716,3 +1716,89 @@ int mwifiex_ret_wakeup_reason(struct > mwifiex_private *priv, > > return 0; > } > + > +static int mwifiex_download_vdll_block(struct mwifiex_adapter *adapter, > u32 offset, > + u16 block_len) { > + int ret; > + struct host_cmd_ds_gen *cmd_hdr = NULL; > + u16 msg_len = block_len + sizeof(*cmd_hdr); > + struct sk_buff *skb; > + u32 fw_offset; > + > + block_len = min(block_len, adapter->vdll_len - offset); > + > + if (offset > adapter->vdll_len) > + return -EINVAL; > + > + if (adapter->cmd_sent) { > + mwifiex_dbg(adapter, MSG, "%s: adapter is busy\n", > __func__); > + return -EBUSY; > + } Shared the handling of VDLL events in the nxpwifi driver: - When “cmd_sent” is true: The VDLL block download is deferred, with its offset and length stored for later processing. - When no command is active (“cmd_sent” is false): The VDLL block is downloaded immediately in the nxpwifi_main_process. int nxpwifi_process_vdll_event(struct nxpwifi_private *priv, struct sk_buff *skb) { : if (!adapter->cmd_sent) { ret = nxpwifi_download_vdll_block(adapter, ctrl->vdll_mem + offset, block_len); if (ret) nxpwifi_dbg(adapter, ERROR, "Download VDLL failed\n"); } else { nxpwifi_dbg(adapter, EVENT, "Delay download VDLL block\n"); ctrl->pending_block_len = block_len; ctrl->pending_block = ctrl->vdll_mem + offset; } : } int nxpwifi_main_process(struct nxpwifi_adapter *adapter) { : if (!adapter->cmd_sent && adapter->vdll_ctrl.pending_block) { struct vdll_dnld_ctrl *ctrl = &adapter->vdll_ctrl; nxpwifi_download_vdll_block(adapter, ctrl->pending_block, ctrl->pending_block_len); ctrl->pending_block = NULL; } : } > + > + skb = dev_alloc_skb(msg_len + MWIFIEX_TYPE_LEN); > + if (!skb) { > + mwifiex_dbg(adapter, ERROR, > + "SLEEP_CFM: dev_alloc_skb failed\n"); > + return -ENOMEM; > + } > + > + skb_put(skb, msg_len); > + > + cmd_hdr = (void *)skb->data; > + cmd_hdr->command = cpu_to_le16(HostCmd_CMD_VDLL); > + cmd_hdr->seq_num = cpu_to_le16(0xFF00); > + cmd_hdr->size = cpu_to_le16(msg_len); > + > + fw_offset = adapter->firmware->size - adapter->vdll_len + offset; > + memcpy(skb->data + sizeof(*cmd_hdr), adapter->firmware->data + > + fw_offset, block_len); > + > + skb_push(skb, adapter->intf_hdr_len); > + > + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_VDLL, > skb, NULL); > + if (ret < 0) > + mwifiex_dbg(adapter, MSG, "DNLD_VDLL: Host to Card > + Failed\n"); > + > + dev_kfree_skb_any(skb); > + > + return ret; > + > +} > + > +int mwifiex_process_vdll_event(struct mwifiex_private *priv, struct > +sk_buff *event_skb) { > + int status = 0; > + struct mwifiex_vdll_ind *ind; > + struct mwifiex_adapter *adapter = priv->adapter; > + > + ind = (struct mwifiex_vdll_ind *)(event_skb->data + > + sizeof(u32)); > + > + switch (le16_to_cpu(ind->type)) { > + case VDLL_IND_TYPE_REQ: > + mwifiex_download_vdll_block(adapter, > le32_to_cpu(ind->offset), > + > le16_to_cpu(ind->block_len)); > + break; > + case VDLL_IND_TYPE_OFFSET: > + adapter->vdll_len = le32_to_cpu(ind->offset); > + mwifiex_dbg(adapter, MSG, "VDLL_IND (OFFSET): > offset=0x%x\n", > + adapter->vdll_len); > + break; > + case VDLL_IND_TYPE_ERR_SIG: > + mwifiex_dbg(adapter, MSG, "VDLL_IND (SIG ERR).\n"); > + break; > + case VDLL_IND_TYPE_ERR_ID: > + mwifiex_dbg(adapter, MSG, "VDLL_IND (ID ERR).\n"); > + break; > + case VDLL_IND_TYPE_SEC_ERR_ID: > + mwifiex_dbg(adapter, MSG, "VDLL_IND (SECURE ERR).\n"); > + break; > + case VDLL_IND_TYPE_INTF_RESET: > + mwifiex_dbg(adapter, MSG, "VDLL_IND (INTF_RESET)\n"); > + break; > + default: > + mwifiex_dbg(adapter, MSG, "unknown vdll ind > type=%d\n", ind->type); > + break; > + } > + > + return status; > +} > diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h > b/drivers/net/wireless/marvell/mwifiex/fw.h > index 4a96281792cc1..92541bc6d0122 100644 > --- a/drivers/net/wireless/marvell/mwifiex/fw.h > +++ b/drivers/net/wireless/marvell/mwifiex/fw.h > @@ -406,6 +406,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { > #define HostCmd_CMD_FW_DUMP_EVENT 0x0125 > #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 > #define HostCmd_CMD_STA_CONFIGURE 0x023f > +#define HostCmd_CMD_VDLL 0x0240 > #define HostCmd_CMD_CHAN_REGION_CFG 0x0242 > #define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251 > #define HostCmd_CMD_ADD_NEW_STATION 0x025f > @@ -584,6 +585,7 @@ enum mwifiex_channel_flags { > #define EVENT_FW_DUMP_INFO 0x00000073 > #define EVENT_TX_STATUS_REPORT 0x00000074 > #define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076 > +#define EVENT_VDLL_IND 0x00000081 > > #define EVENT_ID_MASK 0xffff > #define BSS_NUM_MASK 0xf > @@ -2449,4 +2451,18 @@ struct hw_spec_max_conn { > u8 max_sta_conn; > } __packed; > > +#define VDLL_IND_TYPE_REQ 0 /* req host side download > vdll block */ > +#define VDLL_IND_TYPE_OFFSET 1 /* notify vdll start offset in > firmware image */ > +#define VDLL_IND_TYPE_ERR_SIG 2 /* notify vdll download error: > signature error */ > +#define VDLL_IND_TYPE_ERR_ID 3 /* notify vdll download error: > ID error */ > +#define VDLL_IND_TYPE_SEC_ERR_ID 4 /* notify vdll download error: > Secure error */ > +#define VDLL_IND_TYPE_INTF_RESET 5 /* req host side interface > reset */ > + > +struct mwifiex_vdll_ind { > + __le16 type; > + __le16 vdllId; > + __le32 offset; > + __le16 block_len; > +} __packed; > + > #endif /* !_MWIFIEX_FW_H_ */ > diff --git a/drivers/net/wireless/marvell/mwifiex/main.h > b/drivers/net/wireless/marvell/mwifiex/main.h > index 0674dcf7a5374..5adbf66957e14 100644 > --- a/drivers/net/wireless/marvell/mwifiex/main.h > +++ b/drivers/net/wireless/marvell/mwifiex/main.h > @@ -131,6 +131,7 @@ enum { > #define MWIFIEX_TYPE_DATA 0 > #define MWIFIEX_TYPE_AGGR_DATA 10 > #define MWIFIEX_TYPE_EVENT 3 > +#define MWIFIEX_TYPE_VDLL 4 > > #define MAX_BITMAP_RATES_SIZE 18 > > @@ -1041,6 +1042,8 @@ struct mwifiex_adapter { > struct delayed_work devdump_work; > > bool ignore_btcoex_events; > + > + u32 vdll_len; > }; > > void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); @@ > -1252,6 +1255,7 @@ int mwifiex_cmd_802_11_bg_scan_config(struct > mwifiex_private *priv, > struct host_cmd_ds_command > *cmd, > void *data_buf); int > mwifiex_stop_bg_scan(struct mwifiex_private *priv); > +int mwifiex_process_vdll_event(struct mwifiex_private *priv, struct > +sk_buff *event_skb); > > /* > * This function checks if the queuing is RA based or not. > diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c > b/drivers/net/wireless/marvell/mwifiex/sta_event.c > index 400348abeee54..e516f44f1804d 100644 > --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c > +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c > @@ -1084,6 +1084,10 @@ int mwifiex_process_sta_event(struct > mwifiex_private *priv) > mwifiex_dbg(adapter, EVENT, "event: firmware debug > info\n"); > mwifiex_fw_dump_info_event(priv, adapter->event_skb); > break; > + case EVENT_VDLL_IND: > + mwifiex_dbg(adapter, EVENT, "event: VDLL event\n"); > + mwifiex_process_vdll_event(priv, adapter->event_skb); > + break; > /* Debugging event; not used, but let's not print an ERROR for it. */ > case EVENT_UNKNOWN_DEBUG: > mwifiex_dbg(adapter, EVENT, "event: debug\n"); diff --git > a/drivers/net/wireless/marvell/mwifiex/uap_event.c > b/drivers/net/wireless/marvell/mwifiex/uap_event.c > index 58ef5020a46a7..80a9c433db64a 100644 > --- a/drivers/net/wireless/marvell/mwifiex/uap_event.c > +++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c > @@ -317,6 +317,10 @@ int mwifiex_process_uap_event(struct > mwifiex_private *priv) > memset(&priv->roc_cfg, 0x00, sizeof(struct > mwifiex_roc_cfg)); > break; > > + case EVENT_VDLL_IND: > + mwifiex_dbg(adapter, EVENT, "event: handle VDLL > event...\n"); > + mwifiex_process_vdll_event(priv, adapter->event_skb); > + break; > default: > mwifiex_dbg(adapter, EVENT, > "event: unknown event id: %#x\n", > eventcause); > > -- > 2.39.5 >