Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20a779ed authored by Pontus Fuchs's avatar Pontus Fuchs Committed by Kalle Valo
Browse files

wcn36xx: Implement multicast filtering



Pass the multicast list to FW.

This patch also adds a way to build the smd command in place. This is
needed because the MC list command is too big for the stack.

Signed-off-by: default avatarPontus Fuchs <pontus.fuchs@gmail.com>
[bjorn: dropped FIF_PROMISC_IN_BSS usage]
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 043ce546
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -4267,9 +4267,9 @@ struct wcn36xx_hal_rcv_flt_mc_addr_list_type {
	u8 data_offset;

	u32 mc_addr_count;
	u8 mc_addr[ETH_ALEN][WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS];
	u8 mc_addr[WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS][ETH_ALEN];
	u8 bss_index;
};
} __packed;

struct wcn36xx_hal_set_pkt_filter_rsp_msg {
	struct wcn36xx_hal_msg_header header;
@@ -4323,7 +4323,7 @@ struct wcn36xx_hal_rcv_flt_pkt_clear_rsp_msg {
struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg {
	struct wcn36xx_hal_msg_header header;
	struct wcn36xx_hal_rcv_flt_mc_addr_list_type mc_addr_list;
};
} __packed;

struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_rsp_msg {
	struct wcn36xx_hal_msg_header header;
+47 −3
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
	}

	wcn36xx_detect_chip_version(wcn);
	wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);

	/* DMA channel initialization */
	ret = wcn36xx_dxe_init(wcn);
@@ -354,15 +355,57 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
	return 0;
}

#define WCN36XX_SUPPORTED_FILTERS (0)

static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
				     unsigned int changed,
				     unsigned int *total, u64 multicast)
{
	struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
	struct wcn36xx *wcn = hw->priv;
	struct wcn36xx_vif *tmp;
	struct ieee80211_vif *vif = NULL;

	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");

	*total &= WCN36XX_SUPPORTED_FILTERS;
	*total &= FIF_ALLMULTI;

	fp = (void *)(unsigned long)multicast;
	list_for_each_entry(tmp, &wcn->vif_list, list) {
		vif = wcn36xx_priv_to_vif(tmp);

		/* FW handles MC filtering only when connected as STA */
		if (*total & FIF_ALLMULTI)
			wcn36xx_smd_set_mc_list(wcn, vif, NULL);
		else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc)
			wcn36xx_smd_set_mc_list(wcn, vif, fp);
	}
	kfree(fp);
}

static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw,
				     struct netdev_hw_addr_list *mc_list)
{
	struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
	struct netdev_hw_addr *ha;

	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n");
	fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
	if (!fp) {
		wcn36xx_err("Out of memory setting filters.\n");
		return 0;
	}

	fp->mc_addr_count = 0;
	/* update multicast filtering parameters */
	if (netdev_hw_addr_list_count(mc_list) <=
	    WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) {
		netdev_hw_addr_list_for_each(ha, mc_list) {
			memcpy(fp->mc_addr[fp->mc_addr_count],
					ha->addr, ETH_ALEN);
			fp->mc_addr_count++;
		}
	}

	return (u64)(unsigned long)fp;
}

static void wcn36xx_tx(struct ieee80211_hw *hw,
@@ -920,6 +963,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
	.resume			= wcn36xx_resume,
#endif
	.config			= wcn36xx_config,
	.prepare_multicast	= wcn36xx_prepare_multicast,
	.configure_filter       = wcn36xx_configure_filter,
	.tx			= wcn36xx_tx,
	.set_key		= wcn36xx_set_key,
+51 −0
Original line number Diff line number Diff line
@@ -271,6 +271,16 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
	return ret;
}

static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr,
			 enum wcn36xx_hal_host_msg_type msg_type,
			 size_t msg_size)
{
	memset(hdr, 0, msg_size + sizeof(*hdr));
	hdr->msg_type = msg_type;
	hdr->msg_version = WCN36XX_HAL_MSG_VERSION0;
	hdr->len = msg_size + sizeof(*hdr);
}

#define INIT_HAL_MSG(msg_body, type) \
	do {								\
		memset(&msg_body, 0, sizeof(msg_body));			\
@@ -2144,6 +2154,46 @@ int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value)
	mutex_unlock(&wcn->hal_mutex);
	return ret;
}

int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
			    struct ieee80211_vif *vif,
			    struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp)
{
	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
	struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *msg_body = NULL;
	int ret = 0;

	mutex_lock(&wcn->hal_mutex);

	msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *)
		   wcn->hal_buf;
	init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ,
		     sizeof(msg_body->mc_addr_list));

	/* An empty list means all mc traffic will be received */
	if (fp)
		memcpy(&msg_body->mc_addr_list, fp,
		       sizeof(msg_body->mc_addr_list));
	else
		msg_body->mc_addr_list.mc_addr_count = 0;

	msg_body->mc_addr_list.bss_index = vif_priv->bss_index;

	ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);
	if (ret) {
		wcn36xx_err("Sending HAL_8023_MULTICAST_LIST failed\n");
		goto out;
	}
	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
	if (ret) {
		wcn36xx_err("HAL_8023_MULTICAST_LIST rsp failed err=%d\n", ret);
		goto out;
	}
out:
	mutex_unlock(&wcn->hal_mutex);
	return ret;
}

static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
{
	struct wcn36xx_hal_msg_header *msg_header = buf;
@@ -2185,6 +2235,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
	case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP:
	case WCN36XX_HAL_CH_SWITCH_RSP:
	case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
	case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
		memcpy(wcn->hal_buf, buf, len);
		wcn->hal_rsp_len = len;
		complete(&wcn->hal_rsp_compl);
+3 −0
Original line number Diff line number Diff line
@@ -136,4 +136,7 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);

int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
			    struct ieee80211_vif *vif,
			    struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
#endif	/* _SMD_H_ */