ssb, b43, b43legacy, b44: Rewrite SSB DMA API
authorMichael Buesch <mb@bu3sch.de>
Fri, 20 Jun 2008 09:50:29 +0000 (11:50 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 27 Jun 2008 13:09:15 +0000 (09:09 -0400)
This is a rewrite of the DMA API for SSB devices.
This is needed, because the old (non-existing) "API" made too many bad
assumptions on the API of the host-bus (PCI).
This introduces an almost complete SSB-DMA-API that maps to the lowlevel
bus-API based on the bustype.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/b44.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43legacy/dma.c
drivers/ssb/Kconfig
drivers/ssb/main.c
include/linux/ssb/ssb.h

index 59dce6aa08659cf6b8fce2ad876962d27eae7529..c3bda5ce67c488dba1fc7f51469f16522c5b1080 100644 (file)
@@ -148,9 +148,9 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
                                                unsigned long offset,
                                                enum dma_data_direction dir)
 {
-       dma_sync_single_range_for_device(sdev->dma_dev, dma_base,
-                                        offset & dma_desc_align_mask,
-                                        dma_desc_sync_size, dir);
+       ssb_dma_sync_single_range_for_device(sdev, dma_base,
+                                            offset & dma_desc_align_mask,
+                                            dma_desc_sync_size, dir);
 }
 
 static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
@@ -158,9 +158,9 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
                                             unsigned long offset,
                                             enum dma_data_direction dir)
 {
-       dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base,
-                                     offset & dma_desc_align_mask,
-                                     dma_desc_sync_size, dir);
+       ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
+                                         offset & dma_desc_align_mask,
+                                         dma_desc_sync_size, dir);
 }
 
 static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
@@ -613,10 +613,10 @@ static void b44_tx(struct b44 *bp)
 
                BUG_ON(skb == NULL);
 
-               dma_unmap_single(bp->sdev->dma_dev,
-                                rp->mapping,
-                                skb->len,
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(bp->sdev,
+                                    rp->mapping,
+                                    skb->len,
+                                    DMA_TO_DEVICE);
                rp->skb = NULL;
                dev_kfree_skb_irq(skb);
        }
@@ -653,29 +653,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
        if (skb == NULL)
                return -ENOMEM;
 
-       mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
-                                RX_PKT_BUF_SZ,
-                                DMA_FROM_DEVICE);
+       mapping = ssb_dma_map_single(bp->sdev, skb->data,
+                                    RX_PKT_BUF_SZ,
+                                    DMA_FROM_DEVICE);
 
        /* Hardware bug work-around, the chip is unable to do PCI DMA
           to/from anything above 1GB :-( */
-       if (dma_mapping_error(mapping) ||
+       if (ssb_dma_mapping_error(bp->sdev, mapping) ||
                mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
                /* Sigh... */
-               if (!dma_mapping_error(mapping))
-                       dma_unmap_single(bp->sdev->dma_dev, mapping,
-                                       RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
+               if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                       ssb_dma_unmap_single(bp->sdev, mapping,
+                                            RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
                dev_kfree_skb_any(skb);
                skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
                if (skb == NULL)
                        return -ENOMEM;
-               mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
-                                        RX_PKT_BUF_SZ,
-                                        DMA_FROM_DEVICE);
-               if (dma_mapping_error(mapping) ||
+               mapping = ssb_dma_map_single(bp->sdev, skb->data,
+                                            RX_PKT_BUF_SZ,
+                                            DMA_FROM_DEVICE);
+               if (ssb_dma_mapping_error(bp->sdev, mapping) ||
                        mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
-                       if (!dma_mapping_error(mapping))
-                               dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+                       if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                               ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
                        dev_kfree_skb_any(skb);
                        return -ENOMEM;
                }
@@ -750,9 +750,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
                                             dest_idx * sizeof(dest_desc),
                                             DMA_BIDIRECTIONAL);
 
-       dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr),
-                                  RX_PKT_BUF_SZ,
-                                  DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_device(bp->sdev, le32_to_cpu(src_desc->addr),
+                                      RX_PKT_BUF_SZ,
+                                      DMA_FROM_DEVICE);
 }
 
 static int b44_rx(struct b44 *bp, int budget)
@@ -772,7 +772,7 @@ static int b44_rx(struct b44 *bp, int budget)
                struct rx_header *rh;
                u16 len;
 
-               dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
+               ssb_dma_sync_single_for_cpu(bp->sdev, map,
                                            RX_PKT_BUF_SZ,
                                            DMA_FROM_DEVICE);
                rh = (struct rx_header *) skb->data;
@@ -806,8 +806,8 @@ static int b44_rx(struct b44 *bp, int budget)
                        skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
                        if (skb_size < 0)
                                goto drop_it;
-                       dma_unmap_single(bp->sdev->dma_dev, map,
-                                        skb_size, DMA_FROM_DEVICE);
+                       ssb_dma_unmap_single(bp->sdev, map,
+                                            skb_size, DMA_FROM_DEVICE);
                        /* Leave out rx_header */
                        skb_put(skb, len + RX_PKT_OFFSET);
                        skb_pull(skb, RX_PKT_OFFSET);
@@ -966,25 +966,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
                goto err_out;
        }
 
-       mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
-       if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
+       mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
+       if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
                struct sk_buff *bounce_skb;
 
                /* Chip can't handle DMA to/from >1GB, use bounce buffer */
-               if (!dma_mapping_error(mapping))
-                       dma_unmap_single(bp->sdev->dma_dev, mapping, len,
-                                       DMA_TO_DEVICE);
+               if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                       ssb_dma_unmap_single(bp->sdev, mapping, len,
+                                            DMA_TO_DEVICE);
 
                bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb)
                        goto err_out;
 
-               mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
-                                        len, DMA_TO_DEVICE);
-               if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
-                       if (!dma_mapping_error(mapping))
-                               dma_unmap_single(bp->sdev->dma_dev, mapping,
-                                        len, DMA_TO_DEVICE);
+               mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
+                                            len, DMA_TO_DEVICE);
+               if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
+                       if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                               ssb_dma_unmap_single(bp->sdev, mapping,
+                                                    len, DMA_TO_DEVICE);
                        dev_kfree_skb_any(bounce_skb);
                        goto err_out;
                }
@@ -1082,8 +1082,8 @@ static void b44_free_rings(struct b44 *bp)
 
                if (rp->skb == NULL)
                        continue;
-               dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
-                                       DMA_FROM_DEVICE);
+               ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
+                                    DMA_FROM_DEVICE);
                dev_kfree_skb_any(rp->skb);
                rp->skb = NULL;
        }
@@ -1094,8 +1094,8 @@ static void b44_free_rings(struct b44 *bp)
 
                if (rp->skb == NULL)
                        continue;
-               dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
-                                       DMA_TO_DEVICE);
+               ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
+                                    DMA_TO_DEVICE);
                dev_kfree_skb_any(rp->skb);
                rp->skb = NULL;
        }
@@ -1117,14 +1117,14 @@ static void b44_init_rings(struct b44 *bp)
        memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
 
        if (bp->flags & B44_FLAG_RX_RING_HACK)
-               dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
-                                         DMA_TABLE_BYTES,
-                                         DMA_BIDIRECTIONAL);
+               ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
+                                              DMA_TABLE_BYTES,
+                                              DMA_BIDIRECTIONAL);
 
        if (bp->flags & B44_FLAG_TX_RING_HACK)
-               dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
-                                         DMA_TABLE_BYTES,
-                                         DMA_TO_DEVICE);
+               ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
+                                              DMA_TABLE_BYTES,
+                                              DMA_TO_DEVICE);
 
        for (i = 0; i < bp->rx_pending; i++) {
                if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1144,25 +1144,27 @@ static void b44_free_consistent(struct b44 *bp)
        bp->tx_buffers = NULL;
        if (bp->rx_ring) {
                if (bp->flags & B44_FLAG_RX_RING_HACK) {
-                       dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
-                                       DMA_TABLE_BYTES,
-                                       DMA_BIDIRECTIONAL);
+                       ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
+                                            DMA_TABLE_BYTES,
+                                            DMA_BIDIRECTIONAL);
                        kfree(bp->rx_ring);
                } else
-                       dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
-                                           bp->rx_ring, bp->rx_ring_dma);
+                       ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
+                                               bp->rx_ring, bp->rx_ring_dma,
+                                               GFP_KERNEL);
                bp->rx_ring = NULL;
                bp->flags &= ~B44_FLAG_RX_RING_HACK;
        }
        if (bp->tx_ring) {
                if (bp->flags & B44_FLAG_TX_RING_HACK) {
-                       dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
-                                       DMA_TABLE_BYTES,
-                                       DMA_TO_DEVICE);
+                       ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
+                                            DMA_TABLE_BYTES,
+                                            DMA_TO_DEVICE);
                        kfree(bp->tx_ring);
                } else
-                       dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
-                                           bp->tx_ring, bp->tx_ring_dma);
+                       ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
+                                               bp->tx_ring, bp->tx_ring_dma,
+                                               GFP_KERNEL);
                bp->tx_ring = NULL;
                bp->flags &= ~B44_FLAG_TX_RING_HACK;
        }
@@ -1187,7 +1189,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                goto out_err;
 
        size = DMA_TABLE_BYTES;
-       bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->rx_ring_dma, gfp);
+       bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
        if (!bp->rx_ring) {
                /* Allocation may have failed due to pci_alloc_consistent
                   insisting on use of GFP_DMA, which is more restrictive
@@ -1199,11 +1201,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                if (!rx_ring)
                        goto out_err;
 
-               rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
-                                           DMA_TABLE_BYTES,
-                                           DMA_BIDIRECTIONAL);
+               rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
+                                                DMA_TABLE_BYTES,
+                                                DMA_BIDIRECTIONAL);
 
-               if (dma_mapping_error(rx_ring_dma) ||
+               if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
                        rx_ring_dma + size > DMA_30BIT_MASK) {
                        kfree(rx_ring);
                        goto out_err;
@@ -1214,9 +1216,9 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                bp->flags |= B44_FLAG_RX_RING_HACK;
        }
 
-       bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp);
+       bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
        if (!bp->tx_ring) {
-               /* Allocation may have failed due to dma_alloc_coherent
+               /* Allocation may have failed due to ssb_dma_alloc_consistent
                   insisting on use of GFP_DMA, which is more restrictive
                   than necessary...  */
                struct dma_desc *tx_ring;
@@ -1226,11 +1228,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                if (!tx_ring)
                        goto out_err;
 
-               tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
+               tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
                                            DMA_TABLE_BYTES,
                                            DMA_TO_DEVICE);
 
-               if (dma_mapping_error(tx_ring_dma) ||
+               if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
                        tx_ring_dma + size > DMA_30BIT_MASK) {
                        kfree(tx_ring);
                        goto out_err;
index 8a09a1db08dbc4521f8645caf35c9d04825c8cc5..098f886976f658fe636c39aa8a9f3810d227e25f 100644 (file)
@@ -328,11 +328,11 @@ static inline
        dma_addr_t dmaaddr;
 
        if (tx) {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len, DMA_TO_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len, DMA_TO_DEVICE);
        } else {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len, DMA_FROM_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len, DMA_FROM_DEVICE);
        }
 
        return dmaaddr;
@@ -343,11 +343,11 @@ static inline
                          dma_addr_t addr, size_t len, int tx)
 {
        if (tx) {
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len, DMA_TO_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len, DMA_TO_DEVICE);
        } else {
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len, DMA_FROM_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len, DMA_FROM_DEVICE);
        }
 }
 
@@ -356,8 +356,8 @@ static inline
                                 dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
-                               addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_cpu(ring->dev->dev,
+                                   addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -365,8 +365,8 @@ static inline
                                    dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_device(ring->dev->dev->dma_dev,
-                                  addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_device(ring->dev->dev,
+                                      addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -381,7 +381,6 @@ static inline
 
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
        gfp_t flags = GFP_KERNEL;
 
        /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
@@ -392,11 +391,14 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         * For unknown reasons - possibly a hardware error - the BCM4311 rev
         * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
         * which accounts for the GFP_DMA flag below.
+        *
+        * The flags here must match the flags in free_ringmemory below!
         */
        if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
-       ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
-                                           &(ring->dmabase), flags);
+       ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
+                                                 B43_DMA_RINGMEMSIZE,
+                                                 &(ring->dmabase), flags);
        if (!ring->descbase) {
                b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
                return -ENOMEM;
@@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
+       gfp_t flags = GFP_KERNEL;
+
+       if (ring->type == B43_DMA_64BIT)
+               flags |= GFP_DMA;
 
-       dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
-                         ring->descbase, ring->dmabase);
+       ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
+                               ring->descbase, ring->dmabase, flags);
 }
 
 /* Reset the RX DMA channel */
@@ -518,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
                                  dma_addr_t addr,
                                  size_t buffersize, bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(addr)))
+       if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -844,10 +849,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->dev->dma_dev,
-                                         ring->txhdr_cache,
-                                         b43_txhdr_size(dev),
-                                         DMA_TO_DEVICE);
+               dma_test = ssb_dma_map_single(dev->dev,
+                                             ring->txhdr_cache,
+                                             b43_txhdr_size(dev),
+                                             DMA_TO_DEVICE);
 
                if (b43_dma_mapping_error(ring, dma_test,
                                          b43_txhdr_size(dev), 1)) {
@@ -859,10 +864,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->dev->dma_dev,
-                                                 ring->txhdr_cache,
-                                                 b43_txhdr_size(dev),
-                                                 DMA_TO_DEVICE);
+                       dma_test = ssb_dma_map_single(dev->dev,
+                                                     ring->txhdr_cache,
+                                                     b43_txhdr_size(dev),
+                                                     DMA_TO_DEVICE);
 
                        if (b43_dma_mapping_error(ring, dma_test,
                                                  b43_txhdr_size(dev), 1)) {
@@ -873,9 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        }
                }
 
-               dma_unmap_single(dev->dev->dma_dev,
-                                dma_test, b43_txhdr_size(dev),
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(dev->dev,
+                                    dma_test, b43_txhdr_size(dev),
+                                    DMA_TO_DEVICE);
        }
 
        err = alloc_ringmemory(ring);
index 33cc256c5baf5311a0f52b9d93ab3411ca95a316..9736b2f56a7599785ba6637315d1fe7e46bc9218 100644 (file)
@@ -393,13 +393,13 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
        dma_addr_t dmaaddr;
 
        if (tx)
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len,
-                                        DMA_TO_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len,
+                                            DMA_TO_DEVICE);
        else
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len,
-                                        DMA_FROM_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len,
+                                            DMA_FROM_DEVICE);
 
        return dmaaddr;
 }
@@ -411,13 +411,13 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
                      int tx)
 {
        if (tx)
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len,
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len,
+                                    DMA_TO_DEVICE);
        else
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len,
-                                DMA_FROM_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len,
+                                    DMA_FROM_DEVICE);
 }
 
 static inline
@@ -427,8 +427,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
 {
        B43legacy_WARN_ON(ring->tx);
 
-       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
-                               addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_cpu(ring->dev->dev,
+                                   addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -438,8 +438,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
 {
        B43legacy_WARN_ON(ring->tx);
 
-       dma_sync_single_for_device(ring->dev->dev->dma_dev,
-                                  addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_device(ring->dev->dev,
+                                      addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -458,10 +458,11 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
 
 static int alloc_ringmemory(struct b43legacy_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
-
-       ring->descbase = dma_alloc_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
-                                           &(ring->dmabase), GFP_KERNEL);
+       /* GFP flags must match the flags in free_ringmemory()! */
+       ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
+                                                 B43legacy_DMA_RINGMEMSIZE,
+                                                 &(ring->dmabase),
+                                                 GFP_KERNEL);
        if (!ring->descbase) {
                b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
                             " failed\n");
@@ -474,10 +475,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
 
 static void free_ringmemory(struct b43legacy_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
-
-       dma_free_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
-                         ring->descbase, ring->dmabase);
+       ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
+                               ring->descbase, ring->dmabase, GFP_KERNEL);
 }
 
 /* Reset the RX DMA channel */
@@ -589,7 +588,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
                                         size_t buffersize,
                                         bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(addr)))
+       if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -893,9 +892,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
-                                         sizeof(struct b43legacy_txhdr_fw3),
-                                         DMA_TO_DEVICE);
+               dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache,
+                                             sizeof(struct b43legacy_txhdr_fw3),
+                                             DMA_TO_DEVICE);
 
                if (b43legacy_dma_mapping_error(ring, dma_test,
                                        sizeof(struct b43legacy_txhdr_fw3), 1)) {
@@ -907,7 +906,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->dev->dma_dev,
+                               dma_test = ssb_dma_map_single(dev->dev,
                                        ring->txhdr_cache,
                                        sizeof(struct b43legacy_txhdr_fw3),
                                        DMA_TO_DEVICE);
@@ -917,9 +916,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                                goto err_kfree_txhdr_cache;
                }
 
-               dma_unmap_single(dev->dev->dma_dev,
-                                dma_test, sizeof(struct b43legacy_txhdr_fw3),
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(dev->dev, dma_test,
+                                    sizeof(struct b43legacy_txhdr_fw3),
+                                    DMA_TO_DEVICE);
        }
 
        ring->dev = dev;
index cd845b8acd17b006ac4021120f0aee8bec85f045..307b1f62d949c42c49940d9ca7dd206943076e67 100644 (file)
@@ -2,7 +2,7 @@ menu "Sonics Silicon Backplane"
 
 config SSB_POSSIBLE
        bool
-       depends on HAS_IOMEM
+       depends on HAS_IOMEM && HAS_DMA
        default y
 
 config SSB
index d184f2aea78d1f0a4b2e2df05c5d79bf8d4a75d9..d831a2beff393079d9a20686494bf022be1f7651 100644 (file)
@@ -462,18 +462,15 @@ static int ssb_devices_register(struct ssb_bus *bus)
 #ifdef CONFIG_SSB_PCIHOST
                        sdev->irq = bus->host_pci->irq;
                        dev->parent = &bus->host_pci->dev;
-                       sdev->dma_dev = &bus->host_pci->dev;
 #endif
                        break;
                case SSB_BUSTYPE_PCMCIA:
 #ifdef CONFIG_SSB_PCMCIAHOST
                        sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
                        dev->parent = &bus->host_pcmcia->dev;
-                       sdev->dma_dev = &bus->host_pcmcia->dev;
 #endif
                        break;
                case SSB_BUSTYPE_SSB:
-                       sdev->dma_dev = dev;
                        break;
                }
 
@@ -1156,36 +1153,82 @@ u32 ssb_dma_translation(struct ssb_device *dev)
 {
        switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
-       case SSB_BUSTYPE_PCMCIA:
                return 0;
        case SSB_BUSTYPE_PCI:
                return SSB_PCI_DMA;
+       default:
+               __ssb_dma_not_implemented(dev);
        }
        return 0;
 }
 EXPORT_SYMBOL(ssb_dma_translation);
 
-int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
+int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
 {
-       struct device *dma_dev = ssb_dev->dma_dev;
-       int err = 0;
+       int err;
 
-#ifdef CONFIG_SSB_PCIHOST
-       if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) {
-               err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask);
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               err = pci_set_dma_mask(dev->bus->host_pci, mask);
                if (err)
                        return err;
-               err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, mask);
+               err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
                return err;
+       case SSB_BUSTYPE_SSB:
+               return dma_set_mask(dev->dev, mask);
+       default:
+               __ssb_dma_not_implemented(dev);
        }
-#endif
-       dma_dev->coherent_dma_mask = mask;
-       dma_dev->dma_mask = &dma_dev->coherent_dma_mask;
-
-       return err;
+       return -ENOSYS;
 }
 EXPORT_SYMBOL(ssb_dma_set_mask);
 
+void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t gfp_flags)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               if (gfp_flags & GFP_DMA) {
+                       /* Workaround: The PCI API does not support passing
+                        * a GFP flag. */
+                       return dma_alloc_coherent(&dev->bus->host_pci->dev,
+                                                 size, dma_handle, gfp_flags);
+               }
+               return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
+       case SSB_BUSTYPE_SSB:
+               return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(ssb_dma_alloc_consistent);
+
+void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
+                            void *vaddr, dma_addr_t dma_handle,
+                            gfp_t gfp_flags)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               if (gfp_flags & GFP_DMA) {
+                       /* Workaround: The PCI API does not support passing
+                        * a GFP flag. */
+                       dma_free_coherent(&dev->bus->host_pci->dev,
+                                         size, vaddr, dma_handle);
+                       return;
+               }
+               pci_free_consistent(dev->bus->host_pci, size,
+                                   vaddr, dma_handle);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_free_coherent(dev->dev, size, vaddr, dma_handle);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+EXPORT_SYMBOL(ssb_dma_free_consistent);
+
 int ssb_bus_may_powerdown(struct ssb_bus *bus)
 {
        struct ssb_chipcommon *cc;
index 50dfd0dc4093c6137c70c7ae6a50e1379ec08508..0fe5a0ded3eac17f4075d2cbdfcfb88153031238 100644 (file)
@@ -137,9 +137,6 @@ struct ssb_device {
        const struct ssb_bus_ops *ops;
 
        struct device *dev;
-       /* Pointer to the device that has to be used for
-        * any DMA related operation. */
-       struct device *dma_dev;
 
        struct ssb_bus *bus;
        struct ssb_device_id id;
@@ -399,13 +396,151 @@ static inline void ssb_block_write(struct ssb_device *dev, const void *buffer,
 #endif /* CONFIG_SSB_BLOCKIO */
 
 
+/* The SSB DMA API. Use this API for any DMA operation on the device.
+ * This API basically is a wrapper that calls the correct DMA API for
+ * the host device type the SSB device is attached to. */
+
 /* Translation (routing) bits that need to be ORed to DMA
  * addresses before they are given to a device. */
 extern u32 ssb_dma_translation(struct ssb_device *dev);
 #define SSB_DMA_TRANSLATION_MASK       0xC0000000
 #define SSB_DMA_TRANSLATION_SHIFT      30
 
-extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask);
+extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
+
+extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
+                                      dma_addr_t *dma_handle, gfp_t gfp_flags);
+extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
+                                   void *vaddr, dma_addr_t dma_handle,
+                                   gfp_t gfp_flags);
+
+static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
+{
+#ifdef CONFIG_SSB_DEBUG
+       printk(KERN_ERR "SSB: BUG! Calling DMA API for "
+              "unsupported bustype %d\n", dev->bus->bustype);
+#endif /* DEBUG */
+}
+
+static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               return pci_dma_mapping_error(addr);
+       case SSB_BUSTYPE_SSB:
+               return dma_mapping_error(addr);
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+       return -ENOSYS;
+}
+
+static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
+                                           size_t size, enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               return pci_map_single(dev->bus->host_pci, p, size, dir);
+       case SSB_BUSTYPE_SSB:
+               return dma_map_single(dev->dev, p, size, dir);
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+       return 0;
+}
+
+static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
+                                       size_t size, enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_unmap_single(dev->dev, dma_addr, size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
+                                              dma_addr_t dma_addr,
+                                              size_t size,
+                                              enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
+                                           size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
+                                                 dma_addr_t dma_addr,
+                                                 size_t size,
+                                                 enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
+                                              size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
+                                                    dma_addr_t dma_addr,
+                                                    unsigned long offset,
+                                                    size_t size,
+                                                    enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               /* Just sync everything. That's all the PCI API can do. */
+               pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
+                                           offset + size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
+                                             size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
+                                                       dma_addr_t dma_addr,
+                                                       unsigned long offset,
+                                                       size_t size,
+                                                       enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               /* Just sync everything. That's all the PCI API can do. */
+               pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
+                                              offset + size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
+                                                size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
 
 
 #ifdef CONFIG_SSB_PCIHOST