📄 pio.c
字号:
INIT_LIST_HEAD(&queue->txfree); INIT_LIST_HEAD(&queue->txqueue); INIT_LIST_HEAD(&queue->txrunning); tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue); value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); value &= ~B43legacy_SBF_XFER_REG_BYTESWAP; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value); qsize = b43legacy_read16(dev, queue->mmio_base + B43legacy_PIO_TXQBUFSIZE); if (qsize == 0) { b43legacyerr(dev->wl, "This card does not support PIO " "operation mode. Please use DMA mode " "(module parameter pio=0).\n"); goto err_freequeue; } if (qsize <= B43legacy_PIO_TXQADJUST) { b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n", qsize); goto err_freequeue; } qsize -= B43legacy_PIO_TXQADJUST; queue->tx_devq_size = qsize; setup_txqueues(queue);out: return queue;err_freequeue: kfree(queue); queue = NULL; goto out;}static void cancel_transfers(struct b43legacy_pioqueue *queue){ struct b43legacy_pio_txpacket *packet, *tmp_packet; tasklet_disable(&queue->txtask); list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) free_txpacket(packet, 0); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) free_txpacket(packet, 0);}static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue){ if (!queue) return; cancel_transfers(queue); kfree(queue);}void b43legacy_pio_free(struct b43legacy_wldev *dev){ struct b43legacy_pio *pio; if (!b43legacy_using_pio(dev)) return; pio = &dev->pio; b43legacy_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; b43legacy_destroy_pioqueue(pio->queue2); pio->queue2 = NULL; b43legacy_destroy_pioqueue(pio->queue1); pio->queue1 = NULL; b43legacy_destroy_pioqueue(pio->queue0); pio->queue0 = NULL;}int b43legacy_pio_init(struct b43legacy_wldev *dev){ struct b43legacy_pio *pio = &dev->pio; struct b43legacy_pioqueue *queue; int err = -ENOMEM; queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE); if (!queue) goto out; pio->queue0 = queue; queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE); if (!queue) goto err_destroy0; pio->queue1 = queue; queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE); if (!queue) goto err_destroy1; pio->queue2 = queue; queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE); if (!queue) goto err_destroy2; pio->queue3 = queue; if (dev->dev->id.revision < 3) dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND; b43legacydbg(dev->wl, "PIO initialized\n"); err = 0;out: return err;err_destroy2: b43legacy_destroy_pioqueue(pio->queue2); pio->queue2 = NULL;err_destroy1: b43legacy_destroy_pioqueue(pio->queue1); pio->queue1 = NULL;err_destroy0: b43legacy_destroy_pioqueue(pio->queue0); pio->queue0 = NULL; goto out;}int b43legacy_pio_tx(struct b43legacy_wldev *dev, struct sk_buff *skb, struct ieee80211_tx_control *ctl){ struct b43legacy_pioqueue *queue = dev->pio.queue1; struct b43legacy_pio_txpacket *packet; B43legacy_WARN_ON(queue->tx_suspended); B43legacy_WARN_ON(list_empty(&queue->txfree)); packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket, list); packet->skb = skb; memset(&packet->txstat, 0, sizeof(packet->txstat)); memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); list_move_tail(&packet->list, &queue->txqueue); queue->nr_txfree--; queue->nr_tx_packets++; B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS); tasklet_schedule(&queue->txtask); return 0;}void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status){ struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); if (!packet->skb) return; queue->tx_devq_packets--; queue->tx_devq_used -= (packet->skb->len + sizeof(struct b43legacy_txhdr_fw3)); if (status->acked) packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; packet->txstat.retry_count = status->frame_count - 1; ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, &(packet->txstat)); packet->skb = NULL; free_txpacket(packet, 1); /* If there are packets on the txqueue, poke the tasklet * to transmit them. */ if (!list_empty(&queue->txqueue)) tasklet_schedule(&queue->txtask);}void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, struct ieee80211_tx_queue_stats *stats){ struct b43legacy_pio *pio = &dev->pio; struct b43legacy_pioqueue *queue; struct ieee80211_tx_queue_stats_data *data; queue = pio->queue1; data = &(stats->data[0]); data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; data->limit = B43legacy_PIO_MAXTXPACKETS; data->count = queue->nr_tx_packets;}static void pio_rx_error(struct b43legacy_pioqueue *queue, int clear_buffers, const char *error){ int i; b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error); b43legacy_pio_write(queue, B43legacy_PIO_RXCTL, B43legacy_PIO_RXCTL_READY); if (clear_buffers) { B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE); for (i = 0; i < 15; i++) { /* Dummy read. */ b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); } }}void b43legacy_pio_rx(struct b43legacy_pioqueue *queue){ __le16 preamble[21] = { 0 }; struct b43legacy_rxhdr_fw3 *rxhdr; u16 tmp; u16 len; u16 macstat; int i; int preamble_readwords; struct sk_buff *skb; tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL); if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE)) return; b43legacy_pio_write(queue, B43legacy_PIO_RXCTL, B43legacy_PIO_RXCTL_DATAAVAILABLE); for (i = 0; i < 10; i++) { tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL); if (tmp & B43legacy_PIO_RXCTL_READY) goto data_ready; udelay(10); } b43legacydbg(queue->dev->wl, "PIO RX timed out\n"); return;data_ready: len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); if (unlikely(len > 0x700)) { pio_rx_error(queue, 0, "len > 0x700"); return; } if (unlikely(len == 0 && queue->mmio_base != B43legacy_MMIO_PIO4_BASE)) { pio_rx_error(queue, 0, "len == 0"); return; } preamble[0] = cpu_to_le16(len); if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) preamble_readwords = 14 / sizeof(u16); else preamble_readwords = 18 / sizeof(u16); for (i = 0; i < preamble_readwords; i++) { tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); preamble[i + 1] = cpu_to_le16(tmp); } rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble; macstat = le16_to_cpu(rxhdr->mac_status); if (macstat & B43legacy_RX_MAC_FCSERR) { pio_rx_error(queue, (queue->mmio_base == B43legacy_MMIO_PIO1_BASE), "Frame FCS error"); return; } if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) { /* We received an xmit status. */ struct b43legacy_hwtxstatus *hw; hw = (struct b43legacy_hwtxstatus *)(preamble + 1); b43legacy_handle_hwtxstatus(queue->dev, hw); return; } skb = dev_alloc_skb(len); if (unlikely(!skb)) { pio_rx_error(queue, 1, "OOM"); return; } skb_put(skb, len); for (i = 0; i < len - 1; i += 2) { tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); } if (len % 2) { tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); skb->data[len - 1] = (tmp & 0x00FF); } b43legacy_rx(queue->dev, skb, rxhdr);}void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue){ b43legacy_power_saving_ctl_bits(queue->dev, -1, 1); b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, b43legacy_pio_read(queue, B43legacy_PIO_TXCTL) | B43legacy_PIO_TXCTL_SUSPEND);}void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue){ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, b43legacy_pio_read(queue, B43legacy_PIO_TXCTL) & ~B43legacy_PIO_TXCTL_SUSPEND); b43legacy_power_saving_ctl_bits(queue->dev, -1, -1); tasklet_schedule(&queue->txtask);}void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev){ struct b43legacy_pio *pio; B43legacy_WARN_ON(!b43legacy_using_pio(dev)); pio = &dev->pio; pio->queue0->tx_frozen = 1; pio->queue1->tx_frozen = 1; pio->queue2->tx_frozen = 1; pio->queue3->tx_frozen = 1;}void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev){ struct b43legacy_pio *pio; B43legacy_WARN_ON(!b43legacy_using_pio(dev)); pio = &dev->pio; pio->queue0->tx_frozen = 0; pio->queue1->tx_frozen = 0; pio->queue2->tx_frozen = 0; pio->queue3->tx_frozen = 0; if (!list_empty(&pio->queue0->txqueue)) tasklet_schedule(&pio->queue0->txtask); if (!list_empty(&pio->queue1->txqueue)) tasklet_schedule(&pio->queue1->txtask); if (!list_empty(&pio->queue2->txqueue)) tasklet_schedule(&pio->queue2->txtask); if (!list_empty(&pio->queue3->txqueue)) tasklet_schedule(&pio->queue3->txtask);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -