mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
wil6210: implement broadcast/multicast data
Use dedicated vring for multicast frames; this vring allocated for AP and PBSS (both P2P GO and client) configurations For short frames, use MCS0; for long - MCS1 Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
62bfd30031
commit
41d6b093b7
5 changed files with 167 additions and 76 deletions
|
@ -783,8 +783,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
|
||||
channel->hw_value);
|
||||
if (rc)
|
||||
netif_carrier_off(ndev);
|
||||
goto err_pcp_start;
|
||||
|
||||
rc = wil_bcast_init(wil);
|
||||
if (rc)
|
||||
goto err_bcast;
|
||||
|
||||
goto out; /* success */
|
||||
err_bcast:
|
||||
wmi_pcp_stop(wil);
|
||||
err_pcp_start:
|
||||
netif_carrier_off(ndev);
|
||||
out:
|
||||
mutex_unlock(&wil->mutex);
|
||||
return rc;
|
||||
|
|
|
@ -121,12 +121,18 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
|
|||
|
||||
snprintf(name, sizeof(name), "tx_%2d", i);
|
||||
|
||||
seq_printf(s,
|
||||
"\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n",
|
||||
wil->sta[cid].addr, cid, tid,
|
||||
txdata->agg_wsize, txdata->agg_timeout,
|
||||
txdata->agg_amsdu ? "+" : "-",
|
||||
used, avail, sidle);
|
||||
if (cid < WIL6210_MAX_CID)
|
||||
seq_printf(s,
|
||||
"\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
|
||||
wil->sta[cid].addr, cid, tid,
|
||||
txdata->agg_wsize,
|
||||
txdata->agg_timeout,
|
||||
txdata->agg_amsdu ? "+" : "-",
|
||||
used, avail, sidle);
|
||||
else
|
||||
seq_printf(s,
|
||||
"\nBroadcast [%3d|%3d] idle %s\n",
|
||||
used, avail, sidle);
|
||||
|
||||
wil_print_vring(s, wil, name, vring, '_', 'H');
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value.");
|
|||
|
||||
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
|
||||
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
|
||||
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
|
||||
|
||||
static int ring_order_set(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
|
@ -216,6 +217,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
|||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
wil_bcast_fini(wil);
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
netif_carrier_off(ndev);
|
||||
|
||||
|
@ -360,6 +362,35 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
int wil_bcast_init(struct wil6210_priv *wil)
|
||||
{
|
||||
int ri = wil->bcast_vring, rc;
|
||||
|
||||
if ((ri >= 0) && wil->vring_tx[ri].va)
|
||||
return 0;
|
||||
|
||||
ri = wil_find_free_vring(wil);
|
||||
if (ri < 0)
|
||||
return ri;
|
||||
|
||||
rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
|
||||
if (rc == 0)
|
||||
wil->bcast_vring = ri;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_bcast_fini(struct wil6210_priv *wil)
|
||||
{
|
||||
int ri = wil->bcast_vring;
|
||||
|
||||
if (ri < 0)
|
||||
return;
|
||||
|
||||
wil->bcast_vring = -1;
|
||||
wil_vring_fini_tx(wil, ri);
|
||||
}
|
||||
|
||||
static void wil_connect_worker(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
|
@ -407,6 +438,7 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
init_completion(&wil->wmi_call);
|
||||
|
||||
wil->pending_connect_cid = -1;
|
||||
wil->bcast_vring = -1;
|
||||
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
|
||||
setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
|
||||
|
||||
|
@ -656,6 +688,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil_bcast_fini(wil);
|
||||
|
||||
/* prevent NAPI from being scheduled */
|
||||
bitmap_zero(wil->status, wil_status_last);
|
||||
|
|
|
@ -523,7 +523,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
unsigned int len = skb->len;
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int cid = wil_rxdesc_cid(d);
|
||||
int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
/* here looking for DA, not A1, thus Rxdesc's 'mcast' indication
|
||||
* is not suitable, need to look at data
|
||||
|
@ -749,6 +749,72 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||
{
|
||||
int rc;
|
||||
struct wmi_bcast_vring_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
|
||||
.vring_cfg = {
|
||||
.tx_sw_ring = {
|
||||
.max_mpdu_size =
|
||||
cpu_to_le16(wil_mtu2macbuf(mtu_max)),
|
||||
.ring_size = cpu_to_le16(size),
|
||||
},
|
||||
.ringid = id,
|
||||
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
|
||||
},
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_vring_cfg_done_event cmd;
|
||||
} __packed reply;
|
||||
struct vring *vring = &wil->vring_tx[id];
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[id];
|
||||
|
||||
wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
|
||||
cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
|
||||
|
||||
if (vring->va) {
|
||||
wil_err(wil, "Tx ring [%d] already allocated\n", id);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(txdata, 0, sizeof(*txdata));
|
||||
spin_lock_init(&txdata->lock);
|
||||
vring->size = size;
|
||||
rc = wil_vring_alloc(wil, vring);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
wil->vring2cid_tid[id][0] = WIL6210_MAX_CID; /* CID */
|
||||
wil->vring2cid_tid[id][1] = 0; /* TID */
|
||||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "Tx config failed, status 0x%02x\n",
|
||||
reply.cmd.status);
|
||||
rc = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
|
||||
|
||||
txdata->enabled = 1;
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
wil_vring_free(wil, vring, 1);
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
||||
{
|
||||
struct vring *vring = &wil->vring_tx[id];
|
||||
|
@ -772,7 +838,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
|||
memset(txdata, 0, sizeof(*txdata));
|
||||
}
|
||||
|
||||
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
|
||||
static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
|
@ -805,15 +871,6 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void wil_set_da_for_vring(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb, int vring_index)
|
||||
{
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
int cid = wil->vring2cid_tid[vring_index][0];
|
||||
|
||||
memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb);
|
||||
|
||||
|
@ -834,6 +891,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
|||
continue;
|
||||
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
||||
continue;
|
||||
|
||||
if (!wil->sta[cid].data_port_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
break;
|
||||
|
@ -848,57 +908,17 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find 1-st vring and return it; set dest address for this vring in skb
|
||||
* duplicate skb and send it to other active vrings
|
||||
*/
|
||||
static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v, *v2;
|
||||
struct sk_buff *skb2;
|
||||
int i;
|
||||
u8 cid;
|
||||
struct vring *v;
|
||||
int i = wil->bcast_vring;
|
||||
|
||||
/* find 1-st vring eligible for data */
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v = &wil->vring_tx[i];
|
||||
if (!v->va)
|
||||
continue;
|
||||
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
if (!wil->sta[cid].data_port_open)
|
||||
continue;
|
||||
|
||||
goto found;
|
||||
}
|
||||
|
||||
wil_dbg_txrx(wil, "Tx while no vrings active?\n");
|
||||
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
|
||||
wil_set_da_for_vring(wil, skb, i);
|
||||
|
||||
/* find other active vrings and duplicate skb for each */
|
||||
for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v2 = &wil->vring_tx[i];
|
||||
if (!v2->va)
|
||||
continue;
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
if (!wil->sta[cid].data_port_open)
|
||||
continue;
|
||||
|
||||
skb2 = skb_copy(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
|
||||
wil_set_da_for_vring(wil, skb2, i);
|
||||
wil_tx_vring(wil, v2, skb2);
|
||||
} else {
|
||||
wil_err(wil, "skb_copy failed\n");
|
||||
}
|
||||
}
|
||||
if (i < 0)
|
||||
return NULL;
|
||||
v = &wil->vring_tx[i];
|
||||
if (!v->va)
|
||||
return NULL;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
@ -995,6 +1015,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
uint i = swhead;
|
||||
dma_addr_t pa;
|
||||
int used;
|
||||
bool mcast = (vring_index == wil->bcast_vring);
|
||||
uint len = skb_headlen(skb);
|
||||
|
||||
wil_dbg_txrx(wil, "%s()\n", __func__);
|
||||
|
||||
|
@ -1020,7 +1042,17 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
return -EINVAL;
|
||||
vring->ctx[i].mapped_as = wil_mapped_as_single;
|
||||
/* 1-st segment */
|
||||
wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);
|
||||
wil_tx_desc_map(d, pa, len, vring_index);
|
||||
if (unlikely(mcast)) {
|
||||
d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */
|
||||
if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) {
|
||||
/* set MCS 1 */
|
||||
d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS);
|
||||
/* packet mode 2 */
|
||||
d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) |
|
||||
(2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS);
|
||||
}
|
||||
}
|
||||
/* Process TCP/UDP checksum offloading */
|
||||
if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) {
|
||||
wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n",
|
||||
|
@ -1126,6 +1158,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
bool bcast = is_multicast_ether_addr(eth->h_dest);
|
||||
struct vring *vring;
|
||||
static bool pr_once_fw;
|
||||
int rc;
|
||||
|
@ -1153,10 +1186,8 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
/* in STA mode (ESS), all to same VRING */
|
||||
vring = wil_find_tx_vring_sta(wil, skb);
|
||||
} else { /* direct communication, find matching VRING */
|
||||
if (is_unicast_ether_addr(eth->h_dest))
|
||||
vring = wil_find_tx_vring(wil, skb);
|
||||
else
|
||||
vring = wil_tx_bcast(wil, skb);
|
||||
vring = bcast ? wil_find_tx_bcast(wil, skb) :
|
||||
wil_find_tx_ucast(wil, skb);
|
||||
}
|
||||
if (unlikely(!vring)) {
|
||||
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
|
||||
|
@ -1219,7 +1250,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
|
||||
int done = 0;
|
||||
int cid = wil->vring2cid_tid[ringid][0];
|
||||
struct wil_net_stats *stats = &wil->sta[cid].stats;
|
||||
struct wil_net_stats *stats = NULL;
|
||||
volatile struct vring_tx_desc *_d;
|
||||
int used_before_complete;
|
||||
int used_new;
|
||||
|
@ -1238,6 +1269,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
|
||||
used_before_complete = wil_vring_used_tx(vring);
|
||||
|
||||
if (cid < WIL6210_MAX_CID)
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
while (!wil_vring_is_empty(vring)) {
|
||||
int new_swtail;
|
||||
struct wil_ctx *ctx = &vring->ctx[vring->swtail];
|
||||
|
@ -1279,12 +1313,15 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
if (skb) {
|
||||
if (likely(d->dma.error == 0)) {
|
||||
ndev->stats.tx_packets++;
|
||||
stats->tx_packets++;
|
||||
ndev->stats.tx_bytes += skb->len;
|
||||
stats->tx_bytes += skb->len;
|
||||
if (stats) {
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += skb->len;
|
||||
}
|
||||
} else {
|
||||
ndev->stats.tx_errors++;
|
||||
stats->tx_errors++;
|
||||
if (stats)
|
||||
stats->tx_errors++;
|
||||
}
|
||||
wil_consume_skb(skb, d->dma.error == 0);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
|
|||
#define WIL_TX_Q_LEN_DEFAULT (4000)
|
||||
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
|
||||
#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10)
|
||||
#define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7)
|
||||
#define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */
|
||||
/* limit ring size in range [32..32k] */
|
||||
#define WIL_RING_SIZE_ORDER_MIN (5)
|
||||
#define WIL_RING_SIZE_ORDER_MAX (15)
|
||||
|
@ -595,6 +597,7 @@ struct wil6210_priv {
|
|||
struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
|
||||
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
|
||||
struct wil_sta_info sta[WIL6210_MAX_CID];
|
||||
int bcast_vring;
|
||||
/* scan */
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
|
||||
|
@ -757,6 +760,9 @@ void wil_rx_fini(struct wil6210_priv *wil);
|
|||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
int cid, int tid);
|
||||
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
|
||||
int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
|
||||
int wil_bcast_init(struct wil6210_priv *wil);
|
||||
void wil_bcast_fini(struct wil6210_priv *wil);
|
||||
|
||||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
int wil_tx_complete(struct wil6210_priv *wil, int ringid);
|
||||
|
|
Loading…
Add table
Reference in a new issue