diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 180 |
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 | ||
83 | struct 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 | |||
83 | struct mwl8k_device_info { | 90 | struct 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 | ||
89 | struct mwl8k_rx_queue { | 97 | struct 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 | 756 | struct mwl8k_rxd_8687 { |
748 | |||
749 | struct 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 | |||
782 | static 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 | |||
790 | static 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 | |||
800 | static int | ||
801 | mwl8k_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 | |||
835 | static 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 | |||
776 | static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) | 846 | static 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 | ||
2964 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | 3021 | static 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; |