aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>2014-02-27 09:20:43 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-02-28 14:33:29 -0500
commit3df2cd361871eb4636c8ce9cf97e6899c90c588c (patch)
tree0e59b5981660734cc63ef930faadaa7d245e2d6f
parent59f7c0a9577a965e279a0c15858480100f28f03d (diff)
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>
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c45
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c24
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c47
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h22
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c17
6 files changed, 148 insertions, 15 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 204c7c82b1b5..fa713ef8dc95 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -110,15 +110,19 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy,
110{ 110{
111 struct wil6210_priv *wil = wiphy_to_wil(wiphy); 111 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
112 int rc; 112 int rc;
113
114 int cid = wil_find_cid(wil, mac);
113 struct wmi_notify_req_cmd cmd = { 115 struct wmi_notify_req_cmd cmd = {
114 .cid = 0, 116 .cid = cid,
115 .interval_usec = 0, 117 .interval_usec = 0,
116 }; 118 };
117 119
118 if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) 120 wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
121 if (cid < 0)
119 return -ENOENT; 122 return -ENOENT;
120 123
121 /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ 124 /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
125 /* TODO: keep stats per CID */
122 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), 126 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
123 WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); 127 WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
124 if (rc) 128 if (rc)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 6fdab1a73e9e..f12aa0b1e1df 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -71,8 +71,13 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
71 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { 71 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
72 struct vring *vring = &(wil->vring_tx[i]); 72 struct vring *vring = &(wil->vring_tx[i]);
73 if (vring->va) { 73 if (vring->va) {
74 int cid = wil->vring2cid_tid[i][0];
75 int tid = wil->vring2cid_tid[i][1];
74 char name[10]; 76 char name[10];
75 snprintf(name, sizeof(name), "tx_%2d", i); 77 snprintf(name, sizeof(name), "tx_%2d", i);
78
79 seq_printf(s, "\n%pM CID %d TID %d\n",
80 wil->sta[cid].addr, cid, tid);
76 wil_print_vring(s, wil, name, vring, '_', 'H'); 81 wil_print_vring(s, wil, name, vring, '_', 'H');
77 } 82 }
78 } 83 }
@@ -592,6 +597,45 @@ static const struct file_operations fops_temp = {
592 .llseek = seq_lseek, 597 .llseek = seq_lseek,
593}; 598};
594 599
600/*---------Station matrix------------*/
601
602static int wil_sta_debugfs_show(struct seq_file *s, void *data)
603{
604 struct wil6210_priv *wil = s->private;
605 int i;
606
607 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
608 struct wil_sta_info *p = &wil->sta[i];
609 char *status = "unknown";
610 switch (p->status) {
611 case wil_sta_unused:
612 status = "unused ";
613 break;
614 case wil_sta_conn_pending:
615 status = "pending ";
616 break;
617 case wil_sta_connected:
618 status = "connected";
619 break;
620 }
621 seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
622 }
623
624 return 0;
625}
626
627static int wil_sta_seq_open(struct inode *inode, struct file *file)
628{
629 return single_open(file, wil_sta_debugfs_show, inode->i_private);
630}
631
632static const struct file_operations fops_sta = {
633 .open = wil_sta_seq_open,
634 .release = single_release,
635 .read = seq_read,
636 .llseek = seq_lseek,
637};
638
595/*----------------*/ 639/*----------------*/
596int wil6210_debugfs_init(struct wil6210_priv *wil) 640int wil6210_debugfs_init(struct wil6210_priv *wil)
597{ 641{
@@ -603,6 +647,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
603 647
604 debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); 648 debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
605 debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); 649 debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
650 debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
606 debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); 651 debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
607 debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, 652 debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
608 &dbg_txdesc_index); 653 &dbg_txdesc_index);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index fd30cddd5882..f68481de0ad7 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -113,14 +113,20 @@ static void wil_connect_worker(struct work_struct *work)
113 113
114 rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); 114 rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
115 wil->pending_connect_cid = -1; 115 wil->pending_connect_cid = -1;
116 if (rc == 0) 116 if (rc == 0) {
117 wil->sta[cid].status = wil_sta_connected;
117 wil_link_on(wil); 118 wil_link_on(wil);
119 } else {
120 wil->sta[cid].status = wil_sta_unused;
121 }
118} 122}
119 123
120int wil_priv_init(struct wil6210_priv *wil) 124int wil_priv_init(struct wil6210_priv *wil)
121{ 125{
122 wil_dbg_misc(wil, "%s()\n", __func__); 126 wil_dbg_misc(wil, "%s()\n", __func__);
123 127
128 memset(wil->sta, 0, sizeof(wil->sta));
129
124 mutex_init(&wil->mutex); 130 mutex_init(&wil->mutex);
125 mutex_init(&wil->wmi_mutex); 131 mutex_init(&wil->wmi_mutex);
126 132
@@ -370,3 +376,19 @@ int wil_down(struct wil6210_priv *wil)
370 376
371 return rc; 377 return rc;
372} 378}
379
380int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
381{
382 int i;
383 int rc = -ENOENT;
384
385 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
386 if ((wil->sta[i].status != wil_sta_unused) &&
387 (0 == memcmp(wil->sta[i].addr, mac, ETH_ALEN))) {
388 rc = i;
389 break;
390 }
391 }
392
393 return rc;
394}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 0b0975d88b43..eb60023fa217 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -613,6 +613,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
613 } 613 }
614 vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); 614 vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
615 615
616 wil->vring2cid_tid[id][0] = cid;
617 wil->vring2cid_tid[id][1] = tid;
618
616 return 0; 619 return 0;
617 out_free: 620 out_free:
618 wil_vring_free(wil, vring, 1); 621 wil_vring_free(wil, vring, 1);
@@ -634,10 +637,27 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
634static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, 637static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
635 struct sk_buff *skb) 638 struct sk_buff *skb)
636{ 639{
637 struct vring *v = &wil->vring_tx[0]; 640 int i;
641 struct ethhdr *eth = (void *)skb->data;
642 int cid = wil_find_cid(wil, eth->h_dest);
643
644 if (cid < 0)
645 return NULL;
638 646
639 if (v->va) 647 /* TODO: fix for multiple TID */
640 return v; 648 for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
649 if (wil->vring2cid_tid[i][0] == cid) {
650 struct vring *v = &wil->vring_tx[i];
651 wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
652 __func__, eth->h_dest, i);
653 if (v->va) {
654 return v;
655 } else {
656 wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
657 return NULL;
658 }
659 }
660 }
641 661
642 return NULL; 662 return NULL;
643} 663}
@@ -740,9 +760,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
740 } 760 }
741 _d = &(vring->va[i].tx); 761 _d = &(vring->va[i].tx);
742 762
743 /* FIXME FW can accept only unicast frames for the peer */
744 memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
745
746 pa = dma_map_single(dev, skb->data, 763 pa = dma_map_single(dev, skb->data,
747 skb_headlen(skb), DMA_TO_DEVICE); 764 skb_headlen(skb), DMA_TO_DEVICE);
748 765
@@ -836,6 +853,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
836netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) 853netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
837{ 854{
838 struct wil6210_priv *wil = ndev_to_wil(ndev); 855 struct wil6210_priv *wil = ndev_to_wil(ndev);
856 struct ethhdr *eth = (void *)skb->data;
839 struct vring *vring; 857 struct vring *vring;
840 int rc; 858 int rc;
841 859
@@ -854,9 +872,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
854 } 872 }
855 873
856 /* find vring */ 874 /* find vring */
857 vring = wil_find_tx_vring(wil, skb); 875 if (is_unicast_ether_addr(eth->h_dest)) {
876 vring = wil_find_tx_vring(wil, skb);
877 } else {
878 int i = 0;
879 /* TODO: duplicate for all CID's */
880 vring = &wil->vring_tx[i];
881 if (vring->va) {
882 int cid = wil->vring2cid_tid[i][0];
883 /* FIXME FW can accept only unicast frames */
884 memcpy(skb->data, wil->sta[cid].addr, ETH_ALEN);
885 } else {
886 vring = NULL;
887 }
888 }
858 if (!vring) { 889 if (!vring) {
859 wil_err(wil, "No Tx VRING available\n"); 890 wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);
860 goto drop; 891 goto drop;
861 } 892 }
862 /* set up vring entry */ 893 /* set up vring entry */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 0d7fba4f09e2..38df203f723d 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -226,6 +226,24 @@ struct wil6210_stats {
226 u16 peer_tx_sector; 226 u16 peer_tx_sector;
227}; 227};
228 228
229enum wil_sta_status {
230 wil_sta_unused = 0,
231 wil_sta_conn_pending = 1,
232 wil_sta_connected = 2,
233};
234/**
235 * struct wil_sta_info - data for peer
236 *
237 * Peer identified by its CID (connection ID)
238 * NIC performs beam forming for each peer;
239 * if no beam forming done, frame exchange is not
240 * possible.
241 */
242struct wil_sta_info {
243 u8 addr[ETH_ALEN];
244 enum wil_sta_status status;
245};
246
229struct wil6210_priv { 247struct wil6210_priv {
230 struct pci_dev *pdev; 248 struct pci_dev *pdev;
231 int n_msi; 249 int n_msi;
@@ -267,7 +285,8 @@ struct wil6210_priv {
267 /* DMA related */ 285 /* DMA related */
268 struct vring vring_rx; 286 struct vring vring_rx;
269 struct vring vring_tx[WIL6210_MAX_TX_RINGS]; 287 struct vring vring_tx[WIL6210_MAX_TX_RINGS];
270 u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; 288 u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
289 struct wil_sta_info sta[WIL6210_MAX_CID];
271 /* scan */ 290 /* scan */
272 struct cfg80211_scan_request *scan_request; 291 struct cfg80211_scan_request *scan_request;
273 292
@@ -334,6 +353,7 @@ void wil_link_off(struct wil6210_priv *wil);
334int wil_up(struct wil6210_priv *wil); 353int wil_up(struct wil6210_priv *wil);
335int wil_down(struct wil6210_priv *wil); 354int wil_down(struct wil6210_priv *wil);
336void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); 355void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
356int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
337 357
338void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); 358void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
339void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); 359void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index d65da5590c5f..2d602901675d 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
384 evt->assoc_req_len, evt->assoc_resp_len); 384 evt->assoc_req_len, evt->assoc_resp_len);
385 return; 385 return;
386 } 386 }
387 if (evt->cid >= WIL6210_MAX_CID) {
388 wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
389 return;
390 }
391
387 ch = evt->channel + 1; 392 ch = evt->channel + 1;
388 wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", 393 wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
389 evt->bssid, ch, evt->cid); 394 evt->bssid, ch, evt->cid);
@@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
439 444
440 /* FIXME FW can transmit only ucast frames to peer */ 445 /* FIXME FW can transmit only ucast frames to peer */
441 /* FIXME real ring_id instead of hard coded 0 */ 446 /* FIXME real ring_id instead of hard coded 0 */
442 memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); 447 memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN);
448 wil->sta[evt->cid].status = wil_sta_conn_pending;
443 449
444 wil->pending_connect_cid = evt->cid; 450 wil->pending_connect_cid = evt->cid;
445 queue_work(wil->wmi_wq_conn, &wil->connect_worker); 451 queue_work(wil->wmi_wq_conn, &wil->connect_worker);
@@ -449,14 +455,19 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
449 void *d, int len) 455 void *d, int len)
450{ 456{
451 struct wmi_disconnect_event *evt = d; 457 struct wmi_disconnect_event *evt = d;
458 int cid = wil_find_cid(wil, evt->bssid);
452 459
453 wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", 460 wil_dbg_wmi(wil, "Disconnect %pM CID %d reason %d proto %d wmi\n",
454 evt->bssid, 461 evt->bssid, cid,
455 evt->protocol_reason_status, evt->disconnect_reason); 462 evt->protocol_reason_status, evt->disconnect_reason);
456 463
457 wil->sinfo_gen++; 464 wil->sinfo_gen++;
458 465
466 /* TODO: fix for multiple connections */
467
459 wil6210_disconnect(wil, evt->bssid); 468 wil6210_disconnect(wil, evt->bssid);
469 if (cid >= 0)
470 wil->sta[cid].status = wil_sta_unused;
460} 471}
461 472
462static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) 473static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)