pio.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. Broadcom B43legacy wireless driver
  3. PIO Transmission
  4. Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; see the file COPYING. If not, write to
  15. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  16. Boston, MA 02110-1301, USA.
  17. */
  18. #include "b43legacy.h"
  19. #include "pio.h"
  20. #include "main.h"
  21. #include "xmit.h"
  22. #include <linux/delay.h>
  23. static void tx_start(struct b43legacy_pioqueue *queue)
  24. {
  25. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  26. B43legacy_PIO_TXCTL_INIT);
  27. }
  28. static void tx_octet(struct b43legacy_pioqueue *queue,
  29. u8 octet)
  30. {
  31. if (queue->need_workarounds) {
  32. b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
  33. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  34. B43legacy_PIO_TXCTL_WRITELO);
  35. } else {
  36. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  37. B43legacy_PIO_TXCTL_WRITELO);
  38. b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
  39. }
  40. }
  41. static u16 tx_get_next_word(const u8 *txhdr,
  42. const u8 *packet,
  43. size_t txhdr_size,
  44. unsigned int *pos)
  45. {
  46. const u8 *source;
  47. unsigned int i = *pos;
  48. u16 ret;
  49. if (i < txhdr_size)
  50. source = txhdr;
  51. else {
  52. source = packet;
  53. i -= txhdr_size;
  54. }
  55. ret = le16_to_cpu(*((__le16 *)(source + i)));
  56. *pos += 2;
  57. return ret;
  58. }
  59. static void tx_data(struct b43legacy_pioqueue *queue,
  60. u8 *txhdr,
  61. const u8 *packet,
  62. unsigned int octets)
  63. {
  64. u16 data;
  65. unsigned int i = 0;
  66. if (queue->need_workarounds) {
  67. data = tx_get_next_word(txhdr, packet,
  68. sizeof(struct b43legacy_txhdr_fw3), &i);
  69. b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
  70. }
  71. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  72. B43legacy_PIO_TXCTL_WRITELO |
  73. B43legacy_PIO_TXCTL_WRITEHI);
  74. while (i < octets - 1) {
  75. data = tx_get_next_word(txhdr, packet,
  76. sizeof(struct b43legacy_txhdr_fw3), &i);
  77. b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
  78. }
  79. if (octets % 2)
  80. tx_octet(queue, packet[octets -
  81. sizeof(struct b43legacy_txhdr_fw3) - 1]);
  82. }
  83. static void tx_complete(struct b43legacy_pioqueue *queue,
  84. struct sk_buff *skb)
  85. {
  86. if (queue->need_workarounds) {
  87. b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
  88. skb->data[skb->len - 1]);
  89. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  90. B43legacy_PIO_TXCTL_WRITELO |
  91. B43legacy_PIO_TXCTL_COMPLETE);
  92. } else
  93. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  94. B43legacy_PIO_TXCTL_COMPLETE);
  95. }
  96. static u16 generate_cookie(struct b43legacy_pioqueue *queue,
  97. struct b43legacy_pio_txpacket *packet)
  98. {
  99. u16 cookie = 0x0000;
  100. int packetindex;
  101. /* We use the upper 4 bits for the PIO
  102. * controller ID and the lower 12 bits
  103. * for the packet index (in the cache).
  104. */
  105. switch (queue->mmio_base) {
  106. case B43legacy_MMIO_PIO1_BASE:
  107. break;
  108. case B43legacy_MMIO_PIO2_BASE:
  109. cookie = 0x1000;
  110. break;
  111. case B43legacy_MMIO_PIO3_BASE:
  112. cookie = 0x2000;
  113. break;
  114. case B43legacy_MMIO_PIO4_BASE:
  115. cookie = 0x3000;
  116. break;
  117. default:
  118. B43legacy_WARN_ON(1);
  119. }
  120. packetindex = pio_txpacket_getindex(packet);
  121. B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
  122. cookie |= (u16)packetindex;
  123. return cookie;
  124. }
  125. static
  126. struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
  127. u16 cookie,
  128. struct b43legacy_pio_txpacket **packet)
  129. {
  130. struct b43legacy_pio *pio = &dev->pio;
  131. struct b43legacy_pioqueue *queue = NULL;
  132. int packetindex;
  133. switch (cookie & 0xF000) {
  134. case 0x0000:
  135. queue = pio->queue0;
  136. break;
  137. case 0x1000:
  138. queue = pio->queue1;
  139. break;
  140. case 0x2000:
  141. queue = pio->queue2;
  142. break;
  143. case 0x3000:
  144. queue = pio->queue3;
  145. break;
  146. default:
  147. B43legacy_WARN_ON(1);
  148. }
  149. packetindex = (cookie & 0x0FFF);
  150. B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
  151. < B43legacy_PIO_MAXTXPACKETS));
  152. *packet = &(queue->tx_packets_cache[packetindex]);
  153. return queue;
  154. }
  155. union txhdr_union {
  156. struct b43legacy_txhdr_fw3 txhdr_fw3;
  157. };
  158. static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
  159. struct sk_buff *skb,
  160. struct b43legacy_pio_txpacket *packet,
  161. size_t txhdr_size)
  162. {
  163. union txhdr_union txhdr_data;
  164. u8 *txhdr = NULL;
  165. unsigned int octets;
  166. txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
  167. B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
  168. b43legacy_generate_txhdr(queue->dev,
  169. txhdr, skb->data, skb->len,
  170. &packet->txstat.control,
  171. generate_cookie(queue, packet));
  172. tx_start(queue);
  173. octets = skb->len + txhdr_size;
  174. if (queue->need_workarounds)
  175. octets--;
  176. tx_data(queue, txhdr, (u8 *)skb->data, octets);
  177. tx_complete(queue, skb);
  178. }
  179. static void free_txpacket(struct b43legacy_pio_txpacket *packet,
  180. int irq_context)
  181. {
  182. struct b43legacy_pioqueue *queue = packet->queue;
  183. if (packet->skb) {
  184. if (irq_context)
  185. dev_kfree_skb_irq(packet->skb);
  186. else
  187. dev_kfree_skb(packet->skb);
  188. }
  189. list_move(&packet->list, &queue->txfree);
  190. queue->nr_txfree++;
  191. }
  192. static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
  193. {
  194. struct b43legacy_pioqueue *queue = packet->queue;
  195. struct sk_buff *skb = packet->skb;
  196. u16 octets;
  197. octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
  198. if (queue->tx_devq_size < octets) {
  199. b43legacywarn(queue->dev->wl, "PIO queue too small. "
  200. "Dropping packet.\n");
  201. /* Drop it silently (return success) */
  202. free_txpacket(packet, 1);
  203. return 0;
  204. }
  205. B43legacy_WARN_ON(queue->tx_devq_packets >
  206. B43legacy_PIO_MAXTXDEVQPACKETS);
  207. B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
  208. /* Check if there is sufficient free space on the device
  209. * TX queue. If not, return and let the TX tasklet
  210. * retry later.
  211. */
  212. if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
  213. return -EBUSY;
  214. if (queue->tx_devq_used + octets > queue->tx_devq_size)
  215. return -EBUSY;
  216. /* Now poke the device. */
  217. pio_tx_write_fragment(queue, skb, packet,
  218. sizeof(struct b43legacy_txhdr_fw3));
  219. /* Account for the packet size.
  220. * (We must not overflow the device TX queue)
  221. */
  222. queue->tx_devq_packets++;
  223. queue->tx_devq_used += octets;
  224. /* Transmission started, everything ok, move the
  225. * packet to the txrunning list.
  226. */
  227. list_move_tail(&packet->list, &queue->txrunning);
  228. return 0;
  229. }
  230. static void tx_tasklet(unsigned long d)
  231. {
  232. struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
  233. struct b43legacy_wldev *dev = queue->dev;
  234. unsigned long flags;
  235. struct b43legacy_pio_txpacket *packet, *tmp_packet;
  236. int err;
  237. u16 txctl;
  238. spin_lock_irqsave(&dev->wl->irq_lock, flags);
  239. if (queue->tx_frozen)
  240. goto out_unlock;
  241. txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
  242. if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
  243. goto out_unlock;
  244. list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
  245. /* Try to transmit the packet. This can fail, if
  246. * the device queue is full. In case of failure, the
  247. * packet is left in the txqueue.
  248. * If transmission succeed, the packet is moved to txrunning.
  249. * If it is impossible to transmit the packet, it
  250. * is dropped.
  251. */
  252. err = pio_tx_packet(packet);
  253. if (err)
  254. break;
  255. }
  256. out_unlock:
  257. spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
  258. }
  259. static void setup_txqueues(struct b43legacy_pioqueue *queue)
  260. {
  261. struct b43legacy_pio_txpacket *packet;
  262. int i;
  263. queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
  264. for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
  265. packet = &(queue->tx_packets_cache[i]);
  266. packet->queue = queue;
  267. INIT_LIST_HEAD(&packet->list);
  268. list_add(&packet->list, &queue->txfree);
  269. }
  270. }
  271. static
  272. struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
  273. u16 pio_mmio_base)
  274. {
  275. struct b43legacy_pioqueue *queue;
  276. u32 value;
  277. u16 qsize;
  278. queue = kzalloc(sizeof(*queue), GFP_KERNEL);
  279. if (!queue)
  280. goto out;
  281. queue->dev = dev;
  282. queue->mmio_base = pio_mmio_base;
  283. queue->need_workarounds = (dev->dev->id.revision < 3);
  284. INIT_LIST_HEAD(&queue->txfree);
  285. INIT_LIST_HEAD(&queue->txqueue);
  286. INIT_LIST_HEAD(&queue->txrunning);
  287. tasklet_init(&queue->txtask, tx_tasklet,
  288. (unsigned long)queue);
  289. value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
  290. value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
  291. b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
  292. qsize = b43legacy_read16(dev, queue->mmio_base
  293. + B43legacy_PIO_TXQBUFSIZE);
  294. if (qsize == 0) {
  295. b43legacyerr(dev->wl, "This card does not support PIO "
  296. "operation mode. Please use DMA mode "
  297. "(module parameter pio=0).\n");
  298. goto err_freequeue;
  299. }
  300. if (qsize <= B43legacy_PIO_TXQADJUST) {
  301. b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
  302. qsize);
  303. goto err_freequeue;
  304. }
  305. qsize -= B43legacy_PIO_TXQADJUST;
  306. queue->tx_devq_size = qsize;
  307. setup_txqueues(queue);
  308. out:
  309. return queue;
  310. err_freequeue:
  311. kfree(queue);
  312. queue = NULL;
  313. goto out;
  314. }
  315. static void cancel_transfers(struct b43legacy_pioqueue *queue)
  316. {
  317. struct b43legacy_pio_txpacket *packet, *tmp_packet;
  318. tasklet_disable(&queue->txtask);
  319. list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
  320. free_txpacket(packet, 0);
  321. list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
  322. free_txpacket(packet, 0);
  323. }
  324. static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
  325. {
  326. if (!queue)
  327. return;
  328. cancel_transfers(queue);
  329. kfree(queue);
  330. }
  331. void b43legacy_pio_free(struct b43legacy_wldev *dev)
  332. {
  333. struct b43legacy_pio *pio;
  334. if (!b43legacy_using_pio(dev))
  335. return;
  336. pio = &dev->pio;
  337. b43legacy_destroy_pioqueue(pio->queue3);
  338. pio->queue3 = NULL;
  339. b43legacy_destroy_pioqueue(pio->queue2);
  340. pio->queue2 = NULL;
  341. b43legacy_destroy_pioqueue(pio->queue1);
  342. pio->queue1 = NULL;
  343. b43legacy_destroy_pioqueue(pio->queue0);
  344. pio->queue0 = NULL;
  345. }
  346. int b43legacy_pio_init(struct b43legacy_wldev *dev)
  347. {
  348. struct b43legacy_pio *pio = &dev->pio;
  349. struct b43legacy_pioqueue *queue;
  350. int err = -ENOMEM;
  351. queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
  352. if (!queue)
  353. goto out;
  354. pio->queue0 = queue;
  355. queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
  356. if (!queue)
  357. goto err_destroy0;
  358. pio->queue1 = queue;
  359. queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
  360. if (!queue)
  361. goto err_destroy1;
  362. pio->queue2 = queue;
  363. queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
  364. if (!queue)
  365. goto err_destroy2;
  366. pio->queue3 = queue;
  367. if (dev->dev->id.revision < 3)
  368. dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
  369. b43legacydbg(dev->wl, "PIO initialized\n");
  370. err = 0;
  371. out:
  372. return err;
  373. err_destroy2:
  374. b43legacy_destroy_pioqueue(pio->queue2);
  375. pio->queue2 = NULL;
  376. err_destroy1:
  377. b43legacy_destroy_pioqueue(pio->queue1);
  378. pio->queue1 = NULL;
  379. err_destroy0:
  380. b43legacy_destroy_pioqueue(pio->queue0);
  381. pio->queue0 = NULL;
  382. goto out;
  383. }
  384. int b43legacy_pio_tx(struct b43legacy_wldev *dev,
  385. struct sk_buff *skb,
  386. struct ieee80211_tx_control *ctl)
  387. {
  388. struct b43legacy_pioqueue *queue = dev->pio.queue1;
  389. struct b43legacy_pio_txpacket *packet;
  390. B43legacy_WARN_ON(queue->tx_suspended);
  391. B43legacy_WARN_ON(list_empty(&queue->txfree));
  392. packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
  393. list);
  394. packet->skb = skb;
  395. memset(&packet->txstat, 0, sizeof(packet->txstat));
  396. memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
  397. list_move_tail(&packet->list, &queue->txqueue);
  398. queue->nr_txfree--;
  399. queue->nr_tx_packets++;
  400. B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
  401. tasklet_schedule(&queue->txtask);
  402. return 0;
  403. }
  404. void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
  405. const struct b43legacy_txstatus *status)
  406. {
  407. struct b43legacy_pioqueue *queue;
  408. struct b43legacy_pio_txpacket *packet;
  409. queue = parse_cookie(dev, status->cookie, &packet);
  410. B43legacy_WARN_ON(!queue);
  411. queue->tx_devq_packets--;
  412. queue->tx_devq_used -= (packet->skb->len +
  413. sizeof(struct b43legacy_txhdr_fw3));
  414. if (status->acked)
  415. packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
  416. packet->txstat.retry_count = status->frame_count - 1;
  417. ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
  418. &(packet->txstat));
  419. packet->skb = NULL;
  420. free_txpacket(packet, 1);
  421. /* If there are packets on the txqueue, poke the tasklet
  422. * to transmit them.
  423. */
  424. if (!list_empty(&queue->txqueue))
  425. tasklet_schedule(&queue->txtask);
  426. }
  427. void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
  428. struct ieee80211_tx_queue_stats *stats)
  429. {
  430. struct b43legacy_pio *pio = &dev->pio;
  431. struct b43legacy_pioqueue *queue;
  432. struct ieee80211_tx_queue_stats_data *data;
  433. queue = pio->queue1;
  434. data = &(stats->data[0]);
  435. data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
  436. data->limit = B43legacy_PIO_MAXTXPACKETS;
  437. data->count = queue->nr_tx_packets;
  438. }
  439. static void pio_rx_error(struct b43legacy_pioqueue *queue,
  440. int clear_buffers,
  441. const char *error)
  442. {
  443. int i;
  444. b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
  445. b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
  446. B43legacy_PIO_RXCTL_READY);
  447. if (clear_buffers) {
  448. B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
  449. for (i = 0; i < 15; i++) {
  450. /* Dummy read. */
  451. b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
  452. }
  453. }
  454. }
  455. void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
  456. {
  457. __le16 preamble[21] = { 0 };
  458. struct b43legacy_rxhdr_fw3 *rxhdr;
  459. u16 tmp;
  460. u16 len;
  461. u16 macstat;
  462. int i;
  463. int preamble_readwords;
  464. struct sk_buff *skb;
  465. tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
  466. if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
  467. return;
  468. b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
  469. B43legacy_PIO_RXCTL_DATAAVAILABLE);
  470. for (i = 0; i < 10; i++) {
  471. tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
  472. if (tmp & B43legacy_PIO_RXCTL_READY)
  473. goto data_ready;
  474. udelay(10);
  475. }
  476. b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
  477. return;
  478. data_ready:
  479. len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
  480. if (unlikely(len > 0x700)) {
  481. pio_rx_error(queue, 0, "len > 0x700");
  482. return;
  483. }
  484. if (unlikely(len == 0 && queue->mmio_base !=
  485. B43legacy_MMIO_PIO4_BASE)) {
  486. pio_rx_error(queue, 0, "len == 0");
  487. return;
  488. }
  489. preamble[0] = cpu_to_le16(len);
  490. if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
  491. preamble_readwords = 14 / sizeof(u16);
  492. else
  493. preamble_readwords = 18 / sizeof(u16);
  494. for (i = 0; i < preamble_readwords; i++) {
  495. tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
  496. preamble[i + 1] = cpu_to_le16(tmp);
  497. }
  498. rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
  499. macstat = le16_to_cpu(rxhdr->mac_status);
  500. if (macstat & B43legacy_RX_MAC_FCSERR) {
  501. pio_rx_error(queue,
  502. (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
  503. "Frame FCS error");
  504. return;
  505. }
  506. if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
  507. /* We received an xmit status. */
  508. struct b43legacy_hwtxstatus *hw;
  509. hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
  510. b43legacy_handle_hwtxstatus(queue->dev, hw);
  511. return;
  512. }
  513. skb = dev_alloc_skb(len);
  514. if (unlikely(!skb)) {
  515. pio_rx_error(queue, 1, "OOM");
  516. return;
  517. }
  518. skb_put(skb, len);
  519. for (i = 0; i < len - 1; i += 2) {
  520. tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
  521. *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
  522. }
  523. if (len % 2) {
  524. tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
  525. skb->data[len - 1] = (tmp & 0x00FF);
  526. }
  527. b43legacy_rx(queue->dev, skb, rxhdr);
  528. }
  529. void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
  530. {
  531. b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
  532. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  533. b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
  534. | B43legacy_PIO_TXCTL_SUSPEND);
  535. }
  536. void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
  537. {
  538. b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
  539. b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
  540. & ~B43legacy_PIO_TXCTL_SUSPEND);
  541. b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
  542. tasklet_schedule(&queue->txtask);
  543. }
  544. void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
  545. {
  546. struct b43legacy_pio *pio;
  547. B43legacy_WARN_ON(!b43legacy_using_pio(dev));
  548. pio = &dev->pio;
  549. pio->queue0->tx_frozen = 1;
  550. pio->queue1->tx_frozen = 1;
  551. pio->queue2->tx_frozen = 1;
  552. pio->queue3->tx_frozen = 1;
  553. }
  554. void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
  555. {
  556. struct b43legacy_pio *pio;
  557. B43legacy_WARN_ON(!b43legacy_using_pio(dev));
  558. pio = &dev->pio;
  559. pio->queue0->tx_frozen = 0;
  560. pio->queue1->tx_frozen = 0;
  561. pio->queue2->tx_frozen = 0;
  562. pio->queue3->tx_frozen = 0;
  563. if (!list_empty(&pio->queue0->txqueue))
  564. tasklet_schedule(&pio->queue0->txtask);
  565. if (!list_empty(&pio->queue1->txqueue))
  566. tasklet_schedule(&pio->queue1->txtask);
  567. if (!list_empty(&pio->queue2->txqueue))
  568. tasklet_schedule(&pio->queue2->txtask);
  569. if (!list_empty(&pio->queue3->txqueue))
  570. tasklet_schedule(&pio->queue3->txtask);
  571. }