diff options
Diffstat (limited to 'drivers/net/wireless/ralink/rt2x00/rt2800lib.c')
| -rw-r--r-- | drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 174 |
1 files changed, 167 insertions, 7 deletions
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 429d07b651dd..9e7b8933d30c 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c | |||
| @@ -957,6 +957,47 @@ static void rt2800_rate_from_status(struct skb_frame_desc *skbdesc, | |||
| 957 | skbdesc->tx_rate_flags = flags; | 957 | skbdesc->tx_rate_flags = flags; |
| 958 | } | 958 | } |
| 959 | 959 | ||
| 960 | static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) | ||
| 961 | { | ||
| 962 | __le32 *txwi; | ||
| 963 | u32 word; | ||
| 964 | int wcid, ack, pid; | ||
| 965 | int tx_wcid, tx_ack, tx_pid, is_agg; | ||
| 966 | |||
| 967 | /* | ||
| 968 | * This frames has returned with an IO error, | ||
| 969 | * so the status report is not intended for this | ||
| 970 | * frame. | ||
| 971 | */ | ||
| 972 | if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) | ||
| 973 | return false; | ||
| 974 | |||
| 975 | wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); | ||
| 976 | ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); | ||
| 977 | pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); | ||
| 978 | is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE); | ||
| 979 | |||
| 980 | /* | ||
| 981 | * Validate if this TX status report is intended for | ||
| 982 | * this entry by comparing the WCID/ACK/PID fields. | ||
| 983 | */ | ||
| 984 | txwi = rt2800_drv_get_txwi(entry); | ||
| 985 | |||
| 986 | word = rt2x00_desc_read(txwi, 1); | ||
| 987 | tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); | ||
| 988 | tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); | ||
| 989 | tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); | ||
| 990 | |||
| 991 | if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { | ||
| 992 | rt2x00_dbg(entry->queue->rt2x00dev, | ||
| 993 | "TX status report missed for queue %d entry %d\n", | ||
| 994 | entry->queue->qid, entry->entry_idx); | ||
| 995 | return false; | ||
| 996 | } | ||
| 997 | |||
| 998 | return true; | ||
| 999 | } | ||
| 1000 | |||
| 960 | void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, | 1001 | void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, |
| 961 | bool match) | 1002 | bool match) |
| 962 | { | 1003 | { |
| @@ -1059,6 +1100,119 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, | |||
| 1059 | } | 1100 | } |
| 1060 | EXPORT_SYMBOL_GPL(rt2800_txdone_entry); | 1101 | EXPORT_SYMBOL_GPL(rt2800_txdone_entry); |
| 1061 | 1102 | ||
| 1103 | void rt2800_txdone(struct rt2x00_dev *rt2x00dev) | ||
| 1104 | { | ||
| 1105 | struct data_queue *queue; | ||
| 1106 | struct queue_entry *entry; | ||
| 1107 | u32 reg; | ||
| 1108 | u8 qid; | ||
| 1109 | bool match; | ||
| 1110 | |||
| 1111 | while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { | ||
| 1112 | /* | ||
| 1113 | * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is | ||
| 1114 | * guaranteed to be one of the TX QIDs . | ||
| 1115 | */ | ||
| 1116 | qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); | ||
| 1117 | queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); | ||
| 1118 | |||
| 1119 | if (unlikely(rt2x00queue_empty(queue))) { | ||
| 1120 | rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", | ||
| 1121 | qid); | ||
| 1122 | break; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | ||
| 1126 | |||
| 1127 | if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || | ||
| 1128 | !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) { | ||
| 1129 | rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n", | ||
| 1130 | entry->entry_idx, qid); | ||
| 1131 | break; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | match = rt2800_txdone_entry_check(entry, reg); | ||
| 1135 | rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match); | ||
| 1136 | } | ||
| 1137 | } | ||
| 1138 | EXPORT_SYMBOL_GPL(rt2800_txdone); | ||
| 1139 | |||
| 1140 | static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev, | ||
| 1141 | struct queue_entry *entry) | ||
| 1142 | { | ||
| 1143 | bool ret; | ||
| 1144 | unsigned long tout; | ||
| 1145 | |||
| 1146 | if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) | ||
| 1147 | return false; | ||
| 1148 | |||
| 1149 | if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) | ||
| 1150 | tout = msecs_to_jiffies(50); | ||
| 1151 | else | ||
| 1152 | tout = msecs_to_jiffies(2000); | ||
| 1153 | |||
| 1154 | ret = time_after(jiffies, entry->last_action + tout); | ||
| 1155 | if (unlikely(ret)) | ||
| 1156 | rt2x00_dbg(entry->queue->rt2x00dev, | ||
| 1157 | "TX status timeout for entry %d in queue %d\n", | ||
| 1158 | entry->entry_idx, entry->queue->qid); | ||
| 1159 | return ret; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev) | ||
| 1163 | { | ||
| 1164 | struct data_queue *queue; | ||
| 1165 | struct queue_entry *entry; | ||
| 1166 | |||
| 1167 | if (!test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) { | ||
| 1168 | unsigned long tout = msecs_to_jiffies(1000); | ||
| 1169 | |||
| 1170 | if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout)) | ||
| 1171 | return false; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | rt2x00dev->last_nostatus_check = jiffies; | ||
| 1175 | |||
| 1176 | tx_queue_for_each(rt2x00dev, queue) { | ||
| 1177 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | ||
| 1178 | if (rt2800_entry_txstatus_timeout(rt2x00dev, entry)) | ||
| 1179 | return true; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | return false; | ||
| 1183 | } | ||
| 1184 | EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout); | ||
| 1185 | |||
| 1186 | void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev) | ||
| 1187 | { | ||
| 1188 | struct data_queue *queue; | ||
| 1189 | struct queue_entry *entry; | ||
| 1190 | |||
| 1191 | /* | ||
| 1192 | * Process any trailing TX status reports for IO failures, | ||
| 1193 | * we loop until we find the first non-IO error entry. This | ||
| 1194 | * can either be a frame which is free, is being uploaded, | ||
| 1195 | * or has completed the upload but didn't have an entry | ||
| 1196 | * in the TX_STAT_FIFO register yet. | ||
| 1197 | */ | ||
| 1198 | tx_queue_for_each(rt2x00dev, queue) { | ||
| 1199 | while (!rt2x00queue_empty(queue)) { | ||
| 1200 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | ||
| 1201 | |||
| 1202 | if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || | ||
| 1203 | !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) | ||
| 1204 | break; | ||
| 1205 | |||
| 1206 | if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) || | ||
| 1207 | rt2800_entry_txstatus_timeout(rt2x00dev, entry)) | ||
| 1208 | rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); | ||
| 1209 | else | ||
| 1210 | break; | ||
| 1211 | } | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus); | ||
| 1215 | |||
| 1062 | static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, | 1216 | static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, |
| 1063 | unsigned int index) | 1217 | unsigned int index) |
| 1064 | { | 1218 | { |
| @@ -1557,12 +1711,13 @@ static void rt2800_set_max_psdu_len(struct rt2x00_dev *rt2x00dev) | |||
| 1557 | rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); | 1711 | rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); |
| 1558 | } | 1712 | } |
| 1559 | 1713 | ||
| 1560 | int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, | 1714 | int rt2800_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1561 | struct ieee80211_sta *sta) | 1715 | struct ieee80211_sta *sta) |
| 1562 | { | 1716 | { |
| 1563 | int wcid; | 1717 | struct rt2x00_dev *rt2x00dev = hw->priv; |
| 1564 | struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); | ||
| 1565 | struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; | 1718 | struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| 1719 | struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); | ||
| 1720 | int wcid; | ||
| 1566 | 1721 | ||
| 1567 | /* | 1722 | /* |
| 1568 | * Limit global maximum TX AMPDU length to smallest value of all | 1723 | * Limit global maximum TX AMPDU length to smallest value of all |
| @@ -1608,8 +1763,10 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, | |||
| 1608 | } | 1763 | } |
| 1609 | EXPORT_SYMBOL_GPL(rt2800_sta_add); | 1764 | EXPORT_SYMBOL_GPL(rt2800_sta_add); |
| 1610 | 1765 | ||
| 1611 | int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, struct ieee80211_sta *sta) | 1766 | int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1767 | struct ieee80211_sta *sta) | ||
| 1612 | { | 1768 | { |
| 1769 | struct rt2x00_dev *rt2x00dev = hw->priv; | ||
| 1613 | struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; | 1770 | struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| 1614 | struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); | 1771 | struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); |
| 1615 | int wcid = sta_priv->wcid; | 1772 | int wcid = sta_priv->wcid; |
| @@ -6220,8 +6377,9 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) | |||
| 6220 | rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); | 6377 | rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); |
| 6221 | } | 6378 | } |
| 6222 | 6379 | ||
| 6223 | /* This chip has hardware antenna diversity*/ | 6380 | /* These chips have hardware RX antenna diversity */ |
| 6224 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { | 6381 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R) || |
| 6382 | rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5370G)) { | ||
| 6225 | rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */ | 6383 | rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */ |
| 6226 | rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */ | 6384 | rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */ |
| 6227 | rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ | 6385 | rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ |
| @@ -8748,7 +8906,9 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
| 8748 | rt2x00dev->default_ant.rx = ANTENNA_A; | 8906 | rt2x00dev->default_ant.rx = ANTENNA_A; |
| 8749 | } | 8907 | } |
| 8750 | 8908 | ||
| 8751 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { | 8909 | /* These chips have hardware RX antenna diversity */ |
| 8910 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R) || | ||
| 8911 | rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5370G)) { | ||
| 8752 | rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; /* Unused */ | 8912 | rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; /* Unused */ |
| 8753 | rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; /* Unused */ | 8913 | rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; /* Unused */ |
| 8754 | } | 8914 | } |
