aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/mwl8k.c180
1 files changed, 119 insertions, 61 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 49ae31b8b621..c9a4c1e1987f 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -80,10 +80,18 @@
80#define MWL8K_RX_QUEUES 1 80#define MWL8K_RX_QUEUES 1
81#define MWL8K_TX_QUEUES 4 81#define MWL8K_TX_QUEUES 4
82 82
83struct rxd_ops {
84 int rxd_size;
85 void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
86 void (*rxd_refill)(void *rxd, dma_addr_t addr, int len);
87 int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status);
88};
89
83struct mwl8k_device_info { 90struct mwl8k_device_info {
84 char *part_name; 91 char *part_name;
85 char *helper_image; 92 char *helper_image;
86 char *fw_image; 93 char *fw_image;
94 struct rxd_ops *rxd_ops;
87}; 95};
88 96
89struct mwl8k_rx_queue { 97struct mwl8k_rx_queue {
@@ -95,7 +103,7 @@ struct mwl8k_rx_queue {
95 /* refill descs here */ 103 /* refill descs here */
96 int tail; 104 int tail;
97 105
98 struct mwl8k_rx_desc *rxd; 106 void *rxd;
99 dma_addr_t rxd_dma; 107 dma_addr_t rxd_dma;
100 struct { 108 struct {
101 struct sk_buff *skb; 109 struct sk_buff *skb;
@@ -134,6 +142,7 @@ struct mwl8k_priv {
134 142
135 struct mwl8k_device_info *device_info; 143 struct mwl8k_device_info *device_info;
136 bool ap_fw; 144 bool ap_fw;
145 struct rxd_ops *rxd_ops;
137 146
138 /* firmware files and meta data */ 147 /* firmware files and meta data */
139 struct mwl8k_firmware fw; 148 struct mwl8k_firmware fw;
@@ -744,9 +753,7 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
744/* 753/*
745 * Packet reception. 754 * Packet reception.
746 */ 755 */
747#define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02 756struct mwl8k_rxd_8687 {
748
749struct mwl8k_rx_desc {
750 __le16 pkt_len; 757 __le16 pkt_len;
751 __u8 link_quality; 758 __u8 link_quality;
752 __u8 noise_level; 759 __u8 noise_level;
@@ -763,16 +770,79 @@ struct mwl8k_rx_desc {
763 __u8 pad2[2]; 770 __u8 pad2[2];
764} __attribute__((packed)); 771} __attribute__((packed));
765 772
773#define MWL8K_8687_RATE_INFO_SHORTPRE 0x8000
774#define MWL8K_8687_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3)
775#define MWL8K_8687_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f)
776#define MWL8K_8687_RATE_INFO_40MHZ 0x0004
777#define MWL8K_8687_RATE_INFO_SHORTGI 0x0002
778#define MWL8K_8687_RATE_INFO_MCS_FORMAT 0x0001
779
780#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST 0x02
781
782static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr)
783{
784 struct mwl8k_rxd_8687 *rxd = _rxd;
785
786 rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
787 rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST;
788}
789
790static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
791{
792 struct mwl8k_rxd_8687 *rxd = _rxd;
793
794 rxd->pkt_len = cpu_to_le16(len);
795 rxd->pkt_phys_addr = cpu_to_le32(addr);
796 wmb();
797 rxd->rx_ctrl = 0;
798}
799
800static int
801mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status)
802{
803 struct mwl8k_rxd_8687 *rxd = _rxd;
804 u16 rate_info;
805
806 if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST))
807 return -1;
808 rmb();
809
810 rate_info = le16_to_cpu(rxd->rate_info);
811
812 memset(status, 0, sizeof(*status));
813
814 status->signal = -rxd->rssi;
815 status->noise = -rxd->noise_level;
816 status->qual = rxd->link_quality;
817 status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info);
818 status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info);
819
820 if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE)
821 status->flag |= RX_FLAG_SHORTPRE;
822 if (rate_info & MWL8K_8687_RATE_INFO_40MHZ)
823 status->flag |= RX_FLAG_40MHZ;
824 if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI)
825 status->flag |= RX_FLAG_SHORT_GI;
826 if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT)
827 status->flag |= RX_FLAG_HT;
828
829 status->band = IEEE80211_BAND_2GHZ;
830 status->freq = ieee80211_channel_to_frequency(rxd->channel);
831
832 return le16_to_cpu(rxd->pkt_len);
833}
834
835static struct rxd_ops rxd_8687_ops = {
836 .rxd_size = sizeof(struct mwl8k_rxd_8687),
837 .rxd_init = mwl8k_rxd_8687_init,
838 .rxd_refill = mwl8k_rxd_8687_refill,
839 .rxd_process = mwl8k_rxd_8687_process,
840};
841
842
766#define MWL8K_RX_DESCS 256 843#define MWL8K_RX_DESCS 256
767#define MWL8K_RX_MAXSZ 3800 844#define MWL8K_RX_MAXSZ 3800
768 845
769#define RATE_INFO_SHORTPRE 0x8000
770#define RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3)
771#define RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f)
772#define RATE_INFO_40MHZ 0x0004
773#define RATE_INFO_SHORTGI 0x0002
774#define RATE_INFO_MCS_FORMAT 0x0001
775
776static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) 846static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
777{ 847{
778 struct mwl8k_priv *priv = hw->priv; 848 struct mwl8k_priv *priv = hw->priv;
@@ -784,7 +854,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
784 rxq->head = 0; 854 rxq->head = 0;
785 rxq->tail = 0; 855 rxq->tail = 0;
786 856
787 size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc); 857 size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size;
788 858
789 rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); 859 rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma);
790 if (rxq->rxd == NULL) { 860 if (rxq->rxd == NULL) {
@@ -804,15 +874,20 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
804 memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf)); 874 memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf));
805 875
806 for (i = 0; i < MWL8K_RX_DESCS; i++) { 876 for (i = 0; i < MWL8K_RX_DESCS; i++) {
807 struct mwl8k_rx_desc *rx_desc; 877 int desc_size;
878 void *rxd;
808 int nexti; 879 int nexti;
880 dma_addr_t next_dma_addr;
881
882 desc_size = priv->rxd_ops->rxd_size;
883 rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size);
809 884
810 rx_desc = rxq->rxd + i; 885 nexti = i + 1;
811 nexti = (i + 1) % MWL8K_RX_DESCS; 886 if (nexti == MWL8K_RX_DESCS)
887 nexti = 0;
888 next_dma_addr = rxq->rxd_dma + (nexti * desc_size);
812 889
813 rx_desc->next_rxd_phys_addr = 890 priv->rxd_ops->rxd_init(rxd, next_dma_addr);
814 cpu_to_le32(rxq->rxd_dma + nexti * sizeof(*rx_desc));
815 rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST;
816 } 891 }
817 892
818 return 0; 893 return 0;
@@ -829,25 +904,24 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
829 struct sk_buff *skb; 904 struct sk_buff *skb;
830 dma_addr_t addr; 905 dma_addr_t addr;
831 int rx; 906 int rx;
907 void *rxd;
832 908
833 skb = dev_alloc_skb(MWL8K_RX_MAXSZ); 909 skb = dev_alloc_skb(MWL8K_RX_MAXSZ);
834 if (skb == NULL) 910 if (skb == NULL)
835 break; 911 break;
836 912
837 rxq->rxd_count++;
838
839 rx = rxq->tail;
840 rxq->tail = (rx + 1) % MWL8K_RX_DESCS;
841
842 addr = pci_map_single(priv->pdev, skb->data, 913 addr = pci_map_single(priv->pdev, skb->data,
843 MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); 914 MWL8K_RX_MAXSZ, DMA_FROM_DEVICE);
844 915
845 rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ); 916 rxq->rxd_count++;
846 rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(addr); 917 rx = rxq->tail++;
918 if (rxq->tail == MWL8K_RX_DESCS)
919 rxq->tail = 0;
847 rxq->buf[rx].skb = skb; 920 rxq->buf[rx].skb = skb;
848 pci_unmap_addr_set(&rxq->buf[rx], dma, addr); 921 pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
849 wmb(); 922
850 rxq->rxd[rx].rx_ctrl = 0; 923 rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size);
924 priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ);
851 925
852 refilled++; 926 refilled++;
853 } 927 }
@@ -878,7 +952,7 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
878 rxq->buf = NULL; 952 rxq->buf = NULL;
879 953
880 pci_free_consistent(priv->pdev, 954 pci_free_consistent(priv->pdev,
881 MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc), 955 MWL8K_RX_DESCS * priv->rxd_ops->rxd_size,
882 rxq->rxd, rxq->rxd_dma); 956 rxq->rxd, rxq->rxd_dma);
883 rxq->rxd = NULL; 957 rxq->rxd = NULL;
884} 958}
@@ -922,20 +996,21 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
922 996
923 processed = 0; 997 processed = 0;
924 while (rxq->rxd_count && limit--) { 998 while (rxq->rxd_count && limit--) {
925 struct mwl8k_rx_desc *rx_desc;
926 struct sk_buff *skb; 999 struct sk_buff *skb;
1000 void *rxd;
1001 int pkt_len;
927 struct ieee80211_rx_status status; 1002 struct ieee80211_rx_status status;
928 struct ieee80211_hdr *wh;
929 u16 rate_info;
930
931 rx_desc = rxq->rxd + rxq->head;
932 if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST))
933 break;
934 rmb();
935 1003
936 skb = rxq->buf[rxq->head].skb; 1004 skb = rxq->buf[rxq->head].skb;
937 if (skb == NULL) 1005 if (skb == NULL)
938 break; 1006 break;
1007
1008 rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size);
1009
1010 pkt_len = priv->rxd_ops->rxd_process(rxd, &status);
1011 if (pkt_len < 0)
1012 break;
1013
939 rxq->buf[rxq->head].skb = NULL; 1014 rxq->buf[rxq->head].skb = NULL;
940 1015
941 pci_unmap_single(priv->pdev, 1016 pci_unmap_single(priv->pdev,
@@ -943,42 +1018,23 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
943 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 1018 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
944 pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); 1019 pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
945 1020
946 rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS; 1021 rxq->head++;
1022 if (rxq->head == MWL8K_RX_DESCS)
1023 rxq->head = 0;
1024
947 rxq->rxd_count--; 1025 rxq->rxd_count--;
948 1026
949 skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); 1027 skb_put(skb, pkt_len);
950 mwl8k_remove_dma_header(skb); 1028 mwl8k_remove_dma_header(skb);
951 1029
952 wh = (struct ieee80211_hdr *)skb->data;
953
954 /* 1030 /*
955 * Check for a pending join operation. Save a 1031 * Check for a pending join operation. Save a
956 * copy of the beacon and schedule a tasklet to 1032 * copy of the beacon and schedule a tasklet to
957 * send a FINALIZE_JOIN command to the firmware. 1033 * send a FINALIZE_JOIN command to the firmware.
958 */ 1034 */
959 if (mwl8k_capture_bssid(priv, wh)) 1035 if (mwl8k_capture_bssid(priv, (void *)skb->data))
960 mwl8k_save_beacon(hw, skb); 1036 mwl8k_save_beacon(hw, skb);
961 1037
962 rate_info = le16_to_cpu(rx_desc->rate_info);
963
964 memset(&status, 0, sizeof(status));
965 status.mactime = 0;
966 status.signal = -rx_desc->rssi;
967 status.noise = -rx_desc->noise_level;
968 status.qual = rx_desc->link_quality;
969 status.antenna = RATE_INFO_ANTSELECT(rate_info);
970 status.rate_idx = RATE_INFO_RATEID(rate_info);
971 status.flag = 0;
972 if (rate_info & RATE_INFO_SHORTPRE)
973 status.flag |= RX_FLAG_SHORTPRE;
974 if (rate_info & RATE_INFO_40MHZ)
975 status.flag |= RX_FLAG_40MHZ;
976 if (rate_info & RATE_INFO_SHORTGI)
977 status.flag |= RX_FLAG_SHORT_GI;
978 if (rate_info & RATE_INFO_MCS_FORMAT)
979 status.flag |= RX_FLAG_HT;
980 status.band = IEEE80211_BAND_2GHZ;
981 status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
982 memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); 1038 memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
983 ieee80211_rx_irqsafe(hw, skb); 1039 ieee80211_rx_irqsafe(hw, skb);
984 1040
@@ -2959,6 +3015,7 @@ static struct mwl8k_device_info di_8687 = {
2959 .part_name = "88w8687", 3015 .part_name = "88w8687",
2960 .helper_image = "mwl8k/helper_8687.fw", 3016 .helper_image = "mwl8k/helper_8687.fw",
2961 .fw_image = "mwl8k/fmimage_8687.fw", 3017 .fw_image = "mwl8k/fmimage_8687.fw",
3018 .rxd_ops = &rxd_8687_ops,
2962}; 3019};
2963 3020
2964static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { 3021static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
@@ -3014,6 +3071,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
3014 priv->hw = hw; 3071 priv->hw = hw;
3015 priv->pdev = pdev; 3072 priv->pdev = pdev;
3016 priv->device_info = (void *)id->driver_data; 3073 priv->device_info = (void *)id->driver_data;
3074 priv->rxd_ops = priv->device_info->rxd_ops;
3017 priv->sniffer_enabled = false; 3075 priv->sniffer_enabled = false;
3018 priv->wmm_enabled = false; 3076 priv->wmm_enabled = false;
3019 priv->pending_tx_pkts = 0; 3077 priv->pending_tx_pkts = 0;