📄 bcm43xx_pio.c
字号:
INIT_LIST_HEAD(&packet->list); list_add(&packet->list, &queue->txfree); }}staticstruct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, u16 pio_mmio_base){ struct bcm43xx_pioqueue *queue; u32 value; u16 qsize; queue = kzalloc(sizeof(*queue), GFP_KERNEL); if (!queue) goto out; queue->bcm = bcm; queue->mmio_base = pio_mmio_base; queue->need_workarounds = (bcm->current_core->rev < 3); 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 = 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 <= 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); assert(queue->bcm->shutting_down); 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 = bcm->current_core->pio; 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 = bcm->current_core->pio; 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 = bcm->current_core->pio->queue1; struct bcm43xx_pio_txpacket *packet; u16 tmp; assert(!queue->tx_suspended); assert(!list_empty(&queue->txfree)); tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) return -EBUSY; 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 (unlikely(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);//TODOif (!queue)return; free_txpacket(packet, 1); if (unlikely(queue->tx_suspended)) { queue->tx_suspended = 0; netif_wake_queue(queue->bcm->net_dev); } /* If there are packets on the txqueue, poke the tasklet. */ 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;return; tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk. 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://FIXME: endianess in this function. len = le16_to_cpu(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_be16(tmp);//FIXME? } 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 = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); *((u16 *)(skb->data + i)) = tmp; } if (len % 2) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); skb->data[len - 1] = (tmp & 0x00FF); if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) skb->data[0x20] = (tmp & 0xFF00) >> 8; else skb->data[0x1E] = (tmp & 0xFF00) >> 8; } bcm43xx_rx(queue->bcm, skb, rxhdr);}/* vim: set ts=8 sw=8 sts=8: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -