diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2009-10-22 14:20:59 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-06 16:54:37 -0500 |
commit | 54bc3a0d7a0c9a13da31183609c42cf7786138e1 (patch) | |
tree | 1e6e62d890d05d2dde478fa6b241d83de3ba63d8 /drivers | |
parent | 788838ebe8a4caca93a91982c7bbf393edf24c08 (diff) |
mwl8k: allow for different receive descriptor formats
As the receive descriptor format is determined by the firmware running
on the hardware and not by the hardware itself, and as these
descriptor formats vary a bit between different firmware releases,
abstract out the receive descriptor init/refill/process methods, and
allow choosing between different formats at run time depending on the
chip and firmware we're running on.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-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; |