📄 bcm43xx_pio.c
字号:
INIT_LIST_HEAD(&queue->txqueue); INIT_LIST_HEAD(&queue->txrunning); tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue); value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); value &= ~BCM43xx_SBF_XFER_REG_BYTESWAP; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); if (qsize == 0) { printk(KERN_ERR PFX "ERROR: This card does not support PIO " "operation mode. Please use DMA mode " "(module parameter pio=0).\n"); goto err_freequeue; } if (qsize <= BCM43xx_PIO_TXQADJUST) { printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize); goto err_freequeue; } qsize -= BCM43xx_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 bcm43xx_pioqueue *queue){ struct bcm43xx_pio_txpacket *packet, *tmp_packet; netif_tx_disable(queue->bcm->net_dev); 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 bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue){ if (!queue) return; cancel_transfers(queue); kfree(queue);}void bcm43xx_pio_free(struct bcm43xx_private *bcm){ struct bcm43xx_pio *pio; if (!bcm43xx_using_pio(bcm)) return; pio = bcm43xx_current_pio(bcm); bcm43xx_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; bcm43xx_destroy_pioqueue(pio->queue2); pio->queue2 = NULL; bcm43xx_destroy_pioqueue(pio->queue1); pio->queue1 = NULL; bcm43xx_destroy_pioqueue(pio->queue0); pio->queue0 = NULL;}int bcm43xx_pio_init(struct bcm43xx_private *bcm){ struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); struct bcm43xx_pioqueue *queue; int err = -ENOMEM; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); if (!queue) goto out; pio->queue0 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); if (!queue) goto err_destroy0; pio->queue1 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); if (!queue) goto err_destroy1; pio->queue2 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); if (!queue) goto err_destroy2; pio->queue3 = queue; if (bcm->current_core->rev < 3) bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; dprintk(KERN_INFO PFX "PIO initialized\n"); err = 0;out: return err;err_destroy2: bcm43xx_destroy_pioqueue(pio->queue2); pio->queue2 = NULL;err_destroy1: bcm43xx_destroy_pioqueue(pio->queue1); pio->queue1 = NULL;err_destroy0: bcm43xx_destroy_pioqueue(pio->queue0); pio->queue0 = NULL; goto out;}int bcm43xx_pio_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb){ struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1; struct bcm43xx_pio_txpacket *packet; assert(!queue->tx_suspended); assert(!list_empty(&queue->txfree)); packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); packet->txb = txb; packet->xmitted_frags = 0; packet->xmitted_octets = 0; list_move_tail(&packet->list, &queue->txqueue); queue->nr_txfree--; assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); /* Suspend TX, if we are out of packets in the "free" queue. */ if (list_empty(&queue->txfree)) { netif_stop_queue(queue->bcm->net_dev); queue->tx_suspended = 1; } tasklet_schedule(&queue->txtask); return 0;}void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status){ struct bcm43xx_pioqueue *queue; struct bcm43xx_pio_txpacket *packet; queue = parse_cookie(bcm, status->cookie, &packet); assert(queue); free_txpacket(packet, 1); if (queue->tx_suspended) { queue->tx_suspended = 0; netif_wake_queue(queue->bcm->net_dev); } /* If there are packets on the txqueue, poke the tasklet * to transmit them. */ if (!list_empty(&queue->txqueue)) tasklet_schedule(&queue->txtask);}static void pio_rx_error(struct bcm43xx_pioqueue *queue, int clear_buffers, const char *error){ int i; printkl("PIO RX error: %s\n", error); bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY); if (clear_buffers) { assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); for (i = 0; i < 15; i++) { /* Dummy read. */ bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); } }}void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue){ u16 preamble[21] = { 0 }; struct bcm43xx_rxhdr *rxhdr; u16 tmp, len, rxflags2; int i, preamble_readwords; struct sk_buff *skb; tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) return; bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE); for (i = 0; i < 10; i++) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); if (tmp & BCM43xx_PIO_RXCTL_READY) goto data_ready; udelay(10); } dprintkl(KERN_ERR PFX "PIO RX timed out\n"); return;data_ready: len = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); if (unlikely(len > 0x700)) { pio_rx_error(queue, 0, "len > 0x700"); return; } if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { pio_rx_error(queue, 0, "len == 0"); return; } preamble[0] = cpu_to_le16(len); if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) preamble_readwords = 14 / sizeof(u16); else preamble_readwords = 18 / sizeof(u16); for (i = 0; i < preamble_readwords; i++) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); preamble[i + 1] = cpu_to_le16(tmp); } rxhdr = (struct bcm43xx_rxhdr *)preamble; rxflags2 = le16_to_cpu(rxhdr->flags2); if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { pio_rx_error(queue, (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), "invalid frame"); return; } if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { /* We received an xmit status. */ struct bcm43xx_hwxmitstatus *hw; struct bcm43xx_xmitstatus stat; hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); stat.cookie = le16_to_cpu(hw->cookie); stat.flags = hw->flags; stat.cnt1 = hw->cnt1; stat.cnt2 = hw->cnt2; stat.seq = le16_to_cpu(hw->seq); stat.unknown = le16_to_cpu(hw->unknown); bcm43xx_debugfs_log_txstat(queue->bcm, &stat); bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); 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 = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); *((u16 *)(skb->data + i)) = cpu_to_le16(tmp); } if (len % 2) { tmp = bcm43xx_pio_read(queue, BCM43xx_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 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) skb->data[2] = (tmp & 0xFF00) >> 8; else skb->data[0] = (tmp & 0xFF00) >> 8;#endif } skb_trim(skb, len - IEEE80211_FCS_LEN); bcm43xx_rx(queue->bcm, skb, rxhdr);}void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue){ bcm43xx_power_saving_ctl_bits(queue->bcm, -1, 1); bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) | BCM43xx_PIO_TXCTL_SUSPEND);}void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue){ bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) & ~BCM43xx_PIO_TXCTL_SUSPEND); bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1); if (!list_empty(&queue->txqueue)) tasklet_schedule(&queue->txtask);}void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm){ struct bcm43xx_pio *pio; assert(bcm43xx_using_pio(bcm)); pio = bcm43xx_current_pio(bcm); pio->queue0->tx_frozen = 1; pio->queue1->tx_frozen = 1; pio->queue2->tx_frozen = 1; pio->queue3->tx_frozen = 1;}void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm){ struct bcm43xx_pio *pio; assert(bcm43xx_using_pio(bcm)); pio = bcm43xx_current_pio(bcm); 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 + -