📄 pio.c
字号:
} qsize -= B43_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 b43_pioqueue *queue){ struct b43_pio_txpacket *packet, *tmp_packet; tasklet_disable(&queue->txtask); list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) free_txpacket(packet); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) free_txpacket(packet);}static void b43_destroy_pioqueue(struct b43_pioqueue *queue){ if (!queue) return; cancel_transfers(queue); kfree(queue);}void b43_pio_free(struct b43_wldev *dev){ struct b43_pio *pio; if (!b43_using_pio(dev)) return; pio = &dev->pio; b43_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; b43_destroy_pioqueue(pio->queue2); pio->queue2 = NULL; b43_destroy_pioqueue(pio->queue1); pio->queue1 = NULL; b43_destroy_pioqueue(pio->queue0); pio->queue0 = NULL;}int b43_pio_init(struct b43_wldev *dev){ struct b43_pio *pio = &dev->pio; struct b43_pioqueue *queue; int err = -ENOMEM; queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE); if (!queue) goto out; pio->queue0 = queue; queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE); if (!queue) goto err_destroy0; pio->queue1 = queue; queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE); if (!queue) goto err_destroy1; pio->queue2 = queue; queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE); if (!queue) goto err_destroy2; pio->queue3 = queue; if (dev->dev->id.revision < 3) dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND; b43dbg(dev->wl, "PIO initialized\n"); err = 0; out: return err; err_destroy2: b43_destroy_pioqueue(pio->queue2); pio->queue2 = NULL; err_destroy1: b43_destroy_pioqueue(pio->queue1); pio->queue1 = NULL; err_destroy0: b43_destroy_pioqueue(pio->queue0); pio->queue0 = NULL; goto out;}int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb, struct ieee80211_tx_control *ctl){ struct b43_pioqueue *queue = dev->pio.queue1; struct b43_pio_txpacket *packet; B43_WARN_ON(queue->tx_suspended); B43_WARN_ON(list_empty(&queue->txfree)); packet = list_entry(queue->txfree.next, struct b43_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++; B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS); tasklet_schedule(&queue->txtask); return 0;}void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status){ struct b43_pioqueue *queue; struct b43_pio_txpacket *packet; queue = parse_cookie(dev, status->cookie, &packet); if (B43_WARN_ON(!queue)) return; queue->tx_devq_packets--; queue->tx_devq_used -= (packet->skb->len + sizeof(struct b43_txhdr_fw4)); if (status->acked) { packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; } else { if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK)) packet->txstat.excessive_retries = 1; } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ packet->txstat.retry_count = 0; } else 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); /* If there are packets on the txqueue, poke the tasklet * to transmit them. */ if (!list_empty(&queue->txqueue)) tasklet_schedule(&queue->txtask);}void b43_pio_get_tx_stats(struct b43_wldev *dev, struct ieee80211_tx_queue_stats *stats){ struct b43_pio *pio = &dev->pio; struct b43_pioqueue *queue; struct ieee80211_tx_queue_stats_data *data; queue = pio->queue1; data = &(stats->data[0]); data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree; data->limit = B43_PIO_MAXTXPACKETS; data->count = queue->nr_tx_packets;}static void pio_rx_error(struct b43_pioqueue *queue, int clear_buffers, const char *error){ int i; b43err(queue->dev->wl, "PIO RX error: %s\n", error); b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY); if (clear_buffers) { B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE); for (i = 0; i < 15; i++) { /* Dummy read. */ b43_pio_read(queue, B43_PIO_RXDATA); } }}void b43_pio_rx(struct b43_pioqueue *queue){ __le16 preamble[21] = { 0 }; struct b43_rxhdr_fw4 *rxhdr; u16 tmp, len; u32 macstat; int i, preamble_readwords; struct sk_buff *skb; tmp = b43_pio_read(queue, B43_PIO_RXCTL); if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE)) return; b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE); for (i = 0; i < 10; i++) { tmp = b43_pio_read(queue, B43_PIO_RXCTL); if (tmp & B43_PIO_RXCTL_READY) goto data_ready; udelay(10); } b43dbg(queue->dev->wl, "PIO RX timed out\n"); return;data_ready: len = b43_pio_read(queue, B43_PIO_RXDATA); if (unlikely(len > 0x700)) { pio_rx_error(queue, 0, "len > 0x700"); return; } if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) { pio_rx_error(queue, 0, "len == 0"); return; } preamble[0] = cpu_to_le16(len); if (queue->mmio_base == B43_MMIO_PIO4_BASE) preamble_readwords = 14 / sizeof(u16); else preamble_readwords = 18 / sizeof(u16); for (i = 0; i < preamble_readwords; i++) { tmp = b43_pio_read(queue, B43_PIO_RXDATA); preamble[i + 1] = cpu_to_le16(tmp); } rxhdr = (struct b43_rxhdr_fw4 *)preamble; macstat = le32_to_cpu(rxhdr->mac_status); if (macstat & B43_RX_MAC_FCSERR) { pio_rx_error(queue, (queue->mmio_base == B43_MMIO_PIO1_BASE), "Frame FCS error"); return; } if (queue->mmio_base == B43_MMIO_PIO4_BASE) { /* We received an xmit status. */ struct b43_hwtxstatus *hw; hw = (struct b43_hwtxstatus *)(preamble + 1); b43_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 = b43_pio_read(queue, B43_PIO_RXDATA); *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); } if (len % 2) { tmp = b43_pio_read(queue, B43_PIO_RXDATA); skb->data[len - 1] = (tmp & 0x00FF);/* The specs say the following is required, but * it is wrong and corrupts the PLCP. If we don't do * this, the PLCP seems to be correct. So ifdef it out for now. */#if 0 if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME) skb->data[2] = (tmp & 0xFF00) >> 8; else skb->data[0] = (tmp & 0xFF00) >> 8;#endif } b43_rx(queue->dev, skb, rxhdr);}void b43_pio_tx_suspend(struct b43_pioqueue *queue){ b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE); b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) | B43_PIO_TXCTL_SUSPEND);}void b43_pio_tx_resume(struct b43_pioqueue *queue){ b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) & ~B43_PIO_TXCTL_SUSPEND); b43_power_saving_ctl_bits(queue->dev, 0); tasklet_schedule(&queue->txtask);}void b43_pio_freeze_txqueues(struct b43_wldev *dev){ struct b43_pio *pio; B43_WARN_ON(!b43_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 b43_pio_thaw_txqueues(struct b43_wldev *dev){ struct b43_pio *pio; B43_WARN_ON(!b43_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 + -