diff options
| author | Gabor Juhos <juhosg@openwrt.org> | 2013-10-17 03:42:21 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2013-10-18 14:06:59 -0400 |
| commit | 8d03e77218ff4bc59e4645438acbd3c5c7e0f654 (patch) | |
| tree | 78610b13d390385c4b486078d1118297bb8a9517 | |
| parent | b5cfde3fd9ff44c4ba831815a441d2b5a5af0b2f (diff) | |
rt2x00: rt2800pci: move interrupt functions to the rt2800mmio module
Move the functions into a separate module, in order
to make those usable from other modules.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2800mmio.c | 396 | ||||
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2800mmio.h | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2800pci.c | 388 |
3 files changed, 405 insertions, 388 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800mmio.c b/drivers/net/wireless/rt2x00/rt2800mmio.c index 32b8e5058867..bfae4f03a522 100644 --- a/drivers/net/wireless/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/rt2x00/rt2800mmio.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | 34 | ||
| 35 | #include "rt2x00.h" | 35 | #include "rt2x00.h" |
| 36 | #include "rt2x00mmio.h" | 36 | #include "rt2x00mmio.h" |
| 37 | #include "rt2800.h" | ||
| 37 | #include "rt2800lib.h" | 38 | #include "rt2800lib.h" |
| 38 | #include "rt2800mmio.h" | 39 | #include "rt2800mmio.h" |
| 39 | 40 | ||
| @@ -156,6 +157,401 @@ void rt2800mmio_fill_rxdone(struct queue_entry *entry, | |||
| 156 | } | 157 | } |
| 157 | EXPORT_SYMBOL_GPL(rt2800mmio_fill_rxdone); | 158 | EXPORT_SYMBOL_GPL(rt2800mmio_fill_rxdone); |
| 158 | 159 | ||
| 160 | /* | ||
| 161 | * Interrupt functions. | ||
| 162 | */ | ||
| 163 | static void rt2800mmio_wakeup(struct rt2x00_dev *rt2x00dev) | ||
| 164 | { | ||
| 165 | struct ieee80211_conf conf = { .flags = 0 }; | ||
| 166 | struct rt2x00lib_conf libconf = { .conf = &conf }; | ||
| 167 | |||
| 168 | rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); | ||
| 169 | } | ||
| 170 | |||
| 171 | static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status) | ||
| 172 | { | ||
| 173 | __le32 *txwi; | ||
| 174 | u32 word; | ||
| 175 | int wcid, tx_wcid; | ||
| 176 | |||
| 177 | wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID); | ||
| 178 | |||
| 179 | txwi = rt2800_drv_get_txwi(entry); | ||
| 180 | rt2x00_desc_read(txwi, 1, &word); | ||
| 181 | tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); | ||
| 182 | |||
| 183 | return (tx_wcid == wcid); | ||
| 184 | } | ||
| 185 | |||
| 186 | static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data) | ||
| 187 | { | ||
| 188 | u32 status = *(u32 *)data; | ||
| 189 | |||
| 190 | /* | ||
| 191 | * rt2800pci hardware might reorder frames when exchanging traffic | ||
| 192 | * with multiple BA enabled STAs. | ||
| 193 | * | ||
| 194 | * For example, a tx queue | ||
| 195 | * [ STA1 | STA2 | STA1 | STA2 ] | ||
| 196 | * can result in tx status reports | ||
| 197 | * [ STA1 | STA1 | STA2 | STA2 ] | ||
| 198 | * when the hw decides to aggregate the frames for STA1 into one AMPDU. | ||
| 199 | * | ||
| 200 | * To mitigate this effect, associate the tx status to the first frame | ||
| 201 | * in the tx queue with a matching wcid. | ||
| 202 | */ | ||
| 203 | if (rt2800mmio_txdone_entry_check(entry, status) && | ||
| 204 | !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { | ||
| 205 | /* | ||
| 206 | * Got a matching frame, associate the tx status with | ||
| 207 | * the frame | ||
| 208 | */ | ||
| 209 | entry->status = status; | ||
| 210 | set_bit(ENTRY_DATA_STATUS_SET, &entry->flags); | ||
| 211 | return true; | ||
| 212 | } | ||
| 213 | |||
| 214 | /* Check the next frame */ | ||
| 215 | return false; | ||
| 216 | } | ||
| 217 | |||
| 218 | static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data) | ||
| 219 | { | ||
| 220 | u32 status = *(u32 *)data; | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Find the first frame without tx status and assign this status to it | ||
| 224 | * regardless if it matches or not. | ||
| 225 | */ | ||
| 226 | if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { | ||
| 227 | /* | ||
| 228 | * Got a matching frame, associate the tx status with | ||
| 229 | * the frame | ||
| 230 | */ | ||
| 231 | entry->status = status; | ||
| 232 | set_bit(ENTRY_DATA_STATUS_SET, &entry->flags); | ||
| 233 | return true; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* Check the next frame */ | ||
| 237 | return false; | ||
| 238 | } | ||
| 239 | static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry, | ||
| 240 | void *data) | ||
| 241 | { | ||
| 242 | if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { | ||
| 243 | rt2800_txdone_entry(entry, entry->status, | ||
| 244 | rt2800mmio_get_txwi(entry)); | ||
| 245 | return false; | ||
| 246 | } | ||
| 247 | |||
| 248 | /* No more frames to release */ | ||
| 249 | return true; | ||
| 250 | } | ||
| 251 | |||
| 252 | static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev) | ||
| 253 | { | ||
| 254 | struct data_queue *queue; | ||
| 255 | u32 status; | ||
| 256 | u8 qid; | ||
| 257 | int max_tx_done = 16; | ||
| 258 | |||
| 259 | while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { | ||
| 260 | qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); | ||
| 261 | if (unlikely(qid >= QID_RX)) { | ||
| 262 | /* | ||
| 263 | * Unknown queue, this shouldn't happen. Just drop | ||
| 264 | * this tx status. | ||
| 265 | */ | ||
| 266 | rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n", | ||
| 267 | qid); | ||
| 268 | break; | ||
| 269 | } | ||
| 270 | |||
| 271 | queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); | ||
| 272 | if (unlikely(queue == NULL)) { | ||
| 273 | /* | ||
| 274 | * The queue is NULL, this shouldn't happen. Stop | ||
| 275 | * processing here and drop the tx status | ||
| 276 | */ | ||
| 277 | rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n", | ||
| 278 | qid); | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (unlikely(rt2x00queue_empty(queue))) { | ||
| 283 | /* | ||
| 284 | * The queue is empty. Stop processing here | ||
| 285 | * and drop the tx status. | ||
| 286 | */ | ||
| 287 | rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", | ||
| 288 | qid); | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | |||
| 292 | /* | ||
| 293 | * Let's associate this tx status with the first | ||
| 294 | * matching frame. | ||
| 295 | */ | ||
| 296 | if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, | ||
| 297 | Q_INDEX, &status, | ||
| 298 | rt2800mmio_txdone_find_entry)) { | ||
| 299 | /* | ||
| 300 | * We cannot match the tx status to any frame, so just | ||
| 301 | * use the first one. | ||
| 302 | */ | ||
| 303 | if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, | ||
| 304 | Q_INDEX, &status, | ||
| 305 | rt2800mmio_txdone_match_first)) { | ||
| 306 | rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n", | ||
| 307 | qid); | ||
| 308 | break; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Release all frames with a valid tx status. | ||
| 314 | */ | ||
| 315 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, | ||
| 316 | Q_INDEX, NULL, | ||
| 317 | rt2800mmio_txdone_release_entries); | ||
| 318 | |||
| 319 | if (--max_tx_done == 0) | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | |||
| 323 | return !max_tx_done; | ||
| 324 | } | ||
| 325 | |||
| 326 | static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev, | ||
