wil6210: multiple connect - initial support
Enable multiple (up to 8 - HW/FW limitation) simultaneous connections. Each connection has its own CID (connection ID) that describes chip's beam-forming entity. Tx Vring should refer to correct CID for frame to reach its destination. Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
59f7c0a957
commit
3df2cd3618
|
@ -110,15 +110,19 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy,
|
|||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
|
||||
int cid = wil_find_cid(wil, mac);
|
||||
struct wmi_notify_req_cmd cmd = {
|
||||
.cid = 0,
|
||||
.cid = cid,
|
||||
.interval_usec = 0,
|
||||
};
|
||||
|
||||
if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
|
||||
wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
|
||||
if (cid < 0)
|
||||
return -ENOENT;
|
||||
|
||||
/* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
|
||||
/* TODO: keep stats per CID */
|
||||
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
|
||||
if (rc)
|
||||
|
|
|
@ -71,8 +71,13 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
|
|||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
struct vring *vring = &(wil->vring_tx[i]);
|
||||
if (vring->va) {
|
||||
int cid = wil->vring2cid_tid[i][0];
|
||||
int tid = wil->vring2cid_tid[i][1];
|
||||
char name[10];
|
||||
snprintf(name, sizeof(name), "tx_%2d", i);
|
||||
|
||||
seq_printf(s, "\n%pM CID %d TID %d\n",
|
||||
wil->sta[cid].addr, cid, tid);
|
||||
wil_print_vring(s, wil, name, vring, '_', 'H');
|
||||
}
|
||||
}
|
||||
|
@ -592,6 +597,45 @@ static const struct file_operations fops_temp = {
|
|||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------Station matrix------------*/
|
||||
|
||||
static int wil_sta_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
struct wil_sta_info *p = &wil->sta[i];
|
||||
char *status = "unknown";
|
||||
switch (p->status) {
|
||||
case wil_sta_unused:
|
||||
status = "unused ";
|
||||
break;
|
||||
case wil_sta_conn_pending:
|
||||
status = "pending ";
|
||||
break;
|
||||
case wil_sta_connected:
|
||||
status = "connected";
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_sta_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_sta_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_sta = {
|
||||
.open = wil_sta_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*----------------*/
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil)
|
||||
{
|
||||
|
@ -603,6 +647,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
|
|||
|
||||
debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
|
||||
debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
|
||||
debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
|
||||
debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
|
||||
debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
|
||||
&dbg_txdesc_index);
|
||||
|
|
|
@ -113,14 +113,20 @@ static void wil_connect_worker(struct work_struct *work)
|
|||
|
||||
rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
|
||||
wil->pending_connect_cid = -1;
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
wil->sta[cid].status = wil_sta_connected;
|
||||
wil_link_on(wil);
|
||||
} else {
|
||||
wil->sta[cid].status = wil_sta_unused;
|
||||
}
|
||||
}
|
||||
|
||||
int wil_priv_init(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
memset(wil->sta, 0, sizeof(wil->sta));
|
||||
|
||||
mutex_init(&wil->mutex);
|
||||
mutex_init(&wil->wmi_mutex);
|
||||
|
||||
|
@ -370,3 +376,19 @@ int wil_down(struct wil6210_priv *wil)
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
|
||||
{
|
||||
int i;
|
||||
int rc = -ENOENT;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if ((wil->sta[i].status != wil_sta_unused) &&
|
||||
(0 == memcmp(wil->sta[i].addr, mac, ETH_ALEN))) {
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -613,6 +613,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
|||
}
|
||||
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
|
||||
|
||||
wil->vring2cid_tid[id][0] = cid;
|
||||
wil->vring2cid_tid[id][1] = tid;
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
wil_vring_free(wil, vring, 1);
|
||||
|
@ -634,10 +637,27 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
|||
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v = &wil->vring_tx[0];
|
||||
int i;
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
int cid = wil_find_cid(wil, eth->h_dest);
|
||||
|
||||
if (v->va)
|
||||
return v;
|
||||
if (cid < 0)
|
||||
return NULL;
|
||||
|
||||
/* TODO: fix for multiple TID */
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
|
||||
if (wil->vring2cid_tid[i][0] == cid) {
|
||||
struct vring *v = &wil->vring_tx[i];
|
||||
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
|
||||
__func__, eth->h_dest, i);
|
||||
if (v->va) {
|
||||
return v;
|
||||
} else {
|
||||
wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -740,9 +760,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
}
|
||||
_d = &(vring->va[i].tx);
|
||||
|
||||
/* FIXME FW can accept only unicast frames for the peer */
|
||||
memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
|
||||
|
||||
pa = dma_map_single(dev, skb->data,
|
||||
skb_headlen(skb), DMA_TO_DEVICE);
|
||||
|
||||
|
@ -836,6 +853,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
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;
|
||||
struct vring *vring;
|
||||
int rc;
|
||||
|
||||
|
@ -854,9 +872,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
|
||||
/* find vring */
|
||||
vring = wil_find_tx_vring(wil, skb);
|
||||
if (is_unicast_ether_addr(eth->h_dest)) {
|
||||
vring = wil_find_tx_vring(wil, skb);
|
||||
} else {
|
||||
int i = 0;
|
||||
/* TODO: duplicate for all CID's */
|
||||
vring = &wil->vring_tx[i];
|
||||
if (vring->va) {
|
||||
int cid = wil->vring2cid_tid[i][0];
|
||||
/* FIXME FW can accept only unicast frames */
|
||||
memcpy(skb->data, wil->sta[cid].addr, ETH_ALEN);
|
||||
} else {
|
||||
vring = NULL;
|
||||
}
|
||||
}
|
||||
if (!vring) {
|
||||
wil_err(wil, "No Tx VRING available\n");
|
||||
wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);
|
||||
goto drop;
|
||||
}
|
||||
/* set up vring entry */
|
||||
|
|
|
@ -226,6 +226,24 @@ struct wil6210_stats {
|
|||
u16 peer_tx_sector;
|
||||
};
|
||||
|
||||
enum wil_sta_status {
|
||||
wil_sta_unused = 0,
|
||||
wil_sta_conn_pending = 1,
|
||||
wil_sta_connected = 2,
|
||||
};
|
||||
/**
|
||||
* struct wil_sta_info - data for peer
|
||||
*
|
||||
* Peer identified by its CID (connection ID)
|
||||
* NIC performs beam forming for each peer;
|
||||
* if no beam forming done, frame exchange is not
|
||||
* possible.
|
||||
*/
|
||||
struct wil_sta_info {
|
||||
u8 addr[ETH_ALEN];
|
||||
enum wil_sta_status status;
|
||||
};
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
int n_msi;
|
||||
|
@ -267,7 +285,8 @@ struct wil6210_priv {
|
|||
/* DMA related */
|
||||
struct vring vring_rx;
|
||||
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
|
||||
u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
|
||||
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
|
||||
struct wil_sta_info sta[WIL6210_MAX_CID];
|
||||
/* scan */
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
|
||||
|
@ -334,6 +353,7 @@ void wil_link_off(struct wil6210_priv *wil);
|
|||
int wil_up(struct wil6210_priv *wil);
|
||||
int wil_down(struct wil6210_priv *wil);
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
||||
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
|
||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||
|
|
|
@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
evt->assoc_req_len, evt->assoc_resp_len);
|
||||
return;
|
||||
}
|
||||
if (evt->cid >= WIL6210_MAX_CID) {
|
||||
wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
|
||||
return;
|
||||
}
|
||||
|
||||
ch = evt->channel + 1;
|
||||
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
|
||||
evt->bssid, ch, evt->cid);
|
||||
|
@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
|
||||
/* FIXME FW can transmit only ucast frames to peer */
|
||||
/* FIXME real ring_id instead of hard coded 0 */
|
||||
memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
|
||||
memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN);
|
||||
wil->sta[evt->cid].status = wil_sta_conn_pending;
|
||||
|
||||
wil->pending_connect_cid = evt->cid;
|
||||
queue_work(wil->wmi_wq_conn, &wil->connect_worker);
|
||||
|
@ -449,14 +455,19 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
|
|||
void *d, int len)
|
||||
{
|
||||
struct wmi_disconnect_event *evt = d;
|
||||
int cid = wil_find_cid(wil, evt->bssid);
|
||||
|
||||
wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n",
|
||||
evt->bssid,
|
||||
wil_dbg_wmi(wil, "Disconnect %pM CID %d reason %d proto %d wmi\n",
|
||||
evt->bssid, cid,
|
||||
evt->protocol_reason_status, evt->disconnect_reason);
|
||||
|
||||
wil->sinfo_gen++;
|
||||
|
||||
/* TODO: fix for multiple connections */
|
||||
|
||||
wil6210_disconnect(wil, evt->bssid);
|
||||
if (cid >= 0)
|
||||
wil->sta[cid].status = wil_sta_unused;
|
||||
}
|
||||
|
||||
static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
|
|
Loading…
Reference in New Issue