diff options
author | Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | 2014-02-27 09:20:43 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-28 14:33:29 -0500 |
commit | 3df2cd361871eb4636c8ce9cf97e6899c90c588c (patch) | |
tree | 0e59b5981660734cc63ef930faadaa7d245e2d6f | |
parent | 59f7c0a9577a965e279a0c15858480100f28f03d (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.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/debugfs.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/txrx.c | 47 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 22 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 17 |
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 | |||
602 | static 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 | |||
627 | static 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 | |||
632 | static 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 | /*----------------*/ |
596 | int wil6210_debugfs_init(struct wil6210_priv *wil) | 640 | int 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 | ||
120 | int wil_priv_init(struct wil6210_priv *wil) | 124 | int 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 | |||
380 | int 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) | |||
634 | static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | 637 | static 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, | |||
836 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 853 | netdev_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 | ||
229 | enum 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 | */ | ||
242 | struct wil_sta_info { | ||
243 | u8 addr[ETH_ALEN]; | ||
244 | enum wil_sta_status status; | ||
245 | }; | ||
246 | |||
229 | struct wil6210_priv { | 247 | struct 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); | |||
334 | int wil_up(struct wil6210_priv *wil); | 353 | int wil_up(struct wil6210_priv *wil); |
335 | int wil_down(struct wil6210_priv *wil); | 354 | int wil_down(struct wil6210_priv *wil); |
336 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); | 355 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); |
356 | int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); | ||
337 | 357 | ||
338 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); | 358 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); |
339 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); | 359 | void __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 | ||
462 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | 473 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) |