?? bcm43xx_dma.c
字號(hào):
desc->dma32.address = cpu_to_le32(addr); }}static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, struct bcm43xx_dmadesc_generic *desc, struct bcm43xx_dmadesc_meta *meta, gfp_t gfp_flags){ struct bcm43xx_rxhdr *rxhdr; struct bcm43xx_hwxmitstatus *xmitstat; dma_addr_t dmaaddr; struct sk_buff *skb; assert(!ring->tx); skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); if (unlikely(!skb)) return -ENOMEM; dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); /* This hardware bug work-around adapted from the b44 driver. The chip may be unable to do PCI DMA to/from anything above 1GB */ if (pci_dma_mapping_error(dmaaddr) || dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { /* This one has 30-bit addressing... */ if (!pci_dma_mapping_error(dmaaddr)) pci_unmap_single(ring->bcm->pci_dev, dmaaddr, ring->rx_buffersize, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb); skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA); if (skb == NULL) return -ENOMEM; dmaaddr = pci_map_single(ring->bcm->pci_dev, skb->data, ring->rx_buffersize, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(dmaaddr) || dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { assert(0); dev_kfree_skb_any(skb); return -ENOMEM; } } meta->skb = skb; meta->dmaaddr = dmaaddr; skb->dev = ring->bcm->net_dev; fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0); rxhdr = (struct bcm43xx_rxhdr *)(skb->data); rxhdr->frame_length = 0; rxhdr->flags1 = 0; xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data); xmitstat->cookie = 0; return 0;}/* Allocate the initial descbuffers. * This is used for an RX ring only. */static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring){ int i, err = -ENOMEM; struct bcm43xx_dmadesc_generic *desc; struct bcm43xx_dmadesc_meta *meta; for (i = 0; i < ring->nr_slots; i++) { desc = bcm43xx_dma_idx2desc(ring, i, &meta); err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); if (err) goto err_unwind; } mb(); ring->used_slots = ring->nr_slots; err = 0;out: return err;err_unwind: for (i--; i >= 0; i--) { desc = bcm43xx_dma_idx2desc(ring, i, &meta); unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb(meta->skb); } goto out;}/* Do initial setup of the DMA controller. * Reset the controller, write the ring busaddress * and switch the "enable" bit on. */static int dmacontroller_setup(struct bcm43xx_dmaring *ring){ int err = 0; u32 value; u32 addrext; if (ring->tx) { if (ring->dma64) { u64 ringbase = (u64)(ring->dmabase); addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT); value = BCM43xx_DMA64_TXENABLE; value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT) & BCM43xx_DMA64_TXADDREXT_MASK; bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value); bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, (ringbase & 0xFFFFFFFF)); bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING) | ring->routing); } else { u32 ringbase = (u32)(ring->dmabase); addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT); value = BCM43xx_DMA32_TXENABLE; value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT) & BCM43xx_DMA32_TXADDREXT_MASK; bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value); bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, (ringbase & ~BCM43xx_DMA32_ROUTING) | ring->routing); } } else { err = alloc_initial_descbuffers(ring); if (err) goto out; if (ring->dma64) { u64 ringbase = (u64)(ring->dmabase); addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT); value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT); value |= BCM43xx_DMA64_RXENABLE; value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT) & BCM43xx_DMA64_RXADDREXT_MASK; bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, (ringbase & 0xFFFFFFFF)); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING) | ring->routing); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200); } else { u32 ringbase = (u32)(ring->dmabase); addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT); value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT); value |= BCM43xx_DMA32_RXENABLE; value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT) & BCM43xx_DMA32_RXADDREXT_MASK; bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value); bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, (ringbase & ~BCM43xx_DMA32_ROUTING) | ring->routing); bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200); } }out: return err;}/* Shutdown the DMA controller. */static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring){ if (ring->tx) { bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64); if (ring->dma64) { bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0); bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0); } else bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0); } else { bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64); if (ring->dma64) { bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0); } else bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0); }}static void free_all_descbuffers(struct bcm43xx_dmaring *ring){ struct bcm43xx_dmadesc_generic *desc; struct bcm43xx_dmadesc_meta *meta; int i; if (!ring->used_slots) return; for (i = 0; i < ring->nr_slots; i++) { desc = bcm43xx_dma_idx2desc(ring, i, &meta); if (!meta->skb) { assert(ring->tx); continue; } if (ring->tx) { unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); } else { unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); } free_descriptor_buffer(ring, meta, 0); }}/* Main initialization function. */staticstruct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, int controller_index, int for_tx, int dma64){ struct bcm43xx_dmaring *ring; int err; int nr_slots; ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) goto out; nr_slots = BCM43xx_RXRING_SLOTS; if (for_tx) nr_slots = BCM43xx_TXRING_SLOTS; ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta), GFP_KERNEL); if (!ring->meta) goto err_kfree_ring; ring->routing = BCM43xx_DMA32_CLIENTTRANS; if (dma64) ring->routing = BCM43xx_DMA64_CLIENTTRANS;#ifdef CONFIG_BCM947XX if (bcm->pci_dev->bus->number == 0) ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;#endif ring->bcm = bcm; ring->nr_slots = nr_slots; ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; assert(ring->suspend_mark < ring->resume_mark); ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index); ring->index = controller_index; ring->dma64 = !!dma64; if (for_tx) { ring->tx = 1; ring->current_slot = -1; } else { if (ring->index == 0) { ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE; ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET; } else if (ring->index == 3) { ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE; ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET; } else assert(0); } err = alloc_ringmemory(ring); if (err) goto err_kfree_meta; err = dmacontroller_setup(ring); if (err) goto err_free_ringmemory; return ring;out: printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n"); return ring;err_free_ringmemory: free_ringmemory(ring);err_kfree_meta: kfree(ring->meta);err_kfree_ring: kfree(ring); ring = NULL; goto out;}/* Main cleanup function. */static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring){ if (!ring) return; dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base, (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); /* Device IRQs are disabled prior entering this function, * so no need to take care of concurrency with rx handler stuff. */ dmacontroller_cleanup(ring); free_all_descbuffers(ring); free_ringmemory(ring); kfree(ring->meta); kfree(ring);}void bcm43xx_dma_free(struct bcm43xx_private *bcm){ struct bcm43xx_dma *dma; if (bcm43xx_using_pio(bcm)) return; dma = bcm43xx_current_dma(bcm); bcm43xx_destroy_dmaring(dma->rx_ring3); dma->rx_ring3 = NULL; bcm43xx_destroy_dmaring(dma->rx_ring0); dma->rx_ring0 = NULL; bcm43xx_destroy_dmaring(dma->tx_ring5); dma->tx_ring5 = NULL; bcm43xx_destroy_dmaring(dma->tx_ring4); dma->tx_ring4 = NULL; bcm43xx_destroy_dmaring(dma->tx_ring3); dma->tx_ring3 = NULL; bcm43xx_destroy_dmaring(dma->tx_ring2); dma->tx_ring2 = NULL; bcm43xx_destroy_dmaring(dma->tx_ring1); dma->tx_ring1 = NULL; bcm43xx_destroy_dmaring(dma->tx_ring0); dma->tx_ring0 = NULL;}int bcm43xx_dma_init(struct bcm43xx_private *bcm){ struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; int err = -ENOMEM; int dma64 = 0; bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm); if (bcm->dma_mask == DMA_64BIT_MASK) dma64 = 1; err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask); if (err) goto no_dma; err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask); if (err) goto no_dma; /* setup TX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64); if (!ring) goto out; dma->tx_ring0 = ring; ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64); if (!ring) goto err_destroy_tx0; dma->tx_ring1 = ring; ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64); if (!ring) goto err_destroy_tx1; dma->tx_ring2 = ring; ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64); if (!ring) goto err_destroy_tx2; dma->tx_ring3 = ring; ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64); if (!ring) goto err_destroy_tx3; dma->tx_ring4 = ring; ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64); if (!ring) goto err_destroy_tx4; dma->tx_ring5 = ring; /* setup RX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64); if (!ring) goto err_destroy_tx5; dma->rx_ring0 = ring; if (bcm->current_core->rev < 5) { ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64); if (!ring) goto err_destroy_rx0; dma->rx_ring3 = ring; } dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", (bcm->dma_mask == DMA_64BIT_MASK) ? 64 : (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30); err = 0;out: return err;err_destroy_rx0: bcm43xx_destroy_dmaring(dma->rx_ring0); dma->rx_ring0 = NULL;err_destroy_tx5: bcm43xx_destroy_dmaring(dma->tx_ring5); dma->tx_ring5 = NULL;err_destroy_tx4: bcm43xx_destroy_dmaring(dma->tx_ring4); dma->tx_ring4 = NULL;err_destroy_tx3: bcm43xx_destroy_dmaring(dma->tx_ring3); dma->tx_ring3 = NULL;err_destroy_tx2: bcm43xx_destroy_dmaring(dma->tx_ring2); dma->tx_ring2 = NULL;err_destroy_tx1: bcm43xx_destroy_dmaring(dma->tx_ring1); dma->tx_ring1 = NULL;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -