Skip to content

Commit

Permalink
ssb: Fix usage of struct device used for DMAing
Browse files Browse the repository at this point in the history
This fixes DMA on architectures where DMA is nontrivial, like PPC64.
We must use the host-device's (PCI) struct device for any DMA
operation instead of the SSB device. For this we add a new
struct device pointer to the SSB device structure that will always
point to the right device for DMAing.

Without this patch b43 and b44 drivers won't work on complex-DMA
architectures, that for example need dev->archdata for DMA operations.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Michael Buesch authored and linvjw committed Apr 15, 2008
1 parent 2d4543f commit 4ac5846
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 45 deletions.
52 changes: 26 additions & 26 deletions drivers/net/b44.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ 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->dev, dma_base,
dma_sync_single_range_for_device(sdev->dma_dev, dma_base,
offset & dma_desc_align_mask,
dma_desc_sync_size, dir);
}
Expand All @@ -158,7 +158,7 @@ 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->dev, dma_base,
dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base,
offset & dma_desc_align_mask,
dma_desc_sync_size, dir);
}
Expand Down Expand Up @@ -613,7 +613,7 @@ static void b44_tx(struct b44 *bp)

BUG_ON(skb == NULL);

dma_unmap_single(bp->sdev->dev,
dma_unmap_single(bp->sdev->dma_dev,
rp->mapping,
skb->len,
DMA_TO_DEVICE);
Expand Down Expand Up @@ -653,7 +653,7 @@ 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->dev, skb->data,
mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);

Expand All @@ -663,19 +663,19 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
/* Sigh... */
if (!dma_mapping_error(mapping))
dma_unmap_single(bp->sdev->dev, mapping,
dma_unmap_single(bp->sdev->dma_dev, 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->dev, skb->data,
mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
if (dma_mapping_error(mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
Expand Down Expand Up @@ -750,7 +750,7 @@ 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->dev, le32_to_cpu(src_desc->addr),
dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr),
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
}
Expand All @@ -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->dev, map,
dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
rh = (struct rx_header *) skb->data;
Expand Down Expand Up @@ -806,7 +806,7 @@ 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->dev, map,
dma_unmap_single(bp->sdev->dma_dev, map,
skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
skb_put(skb, len + RX_PKT_OFFSET);
Expand Down Expand Up @@ -966,24 +966,24 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_out;
}

mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(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->dev, mapping, len,
dma_unmap_single(bp->sdev->dma_dev, 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->dev, bounce_skb->data,
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->dev, mapping,
dma_unmap_single(bp->sdev->dma_dev, mapping,
len, DMA_TO_DEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
Expand Down Expand Up @@ -1082,7 +1082,7 @@ static void b44_free_rings(struct b44 *bp)

if (rp->skb == NULL)
continue;
dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ,
dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
Expand All @@ -1094,7 +1094,7 @@ static void b44_free_rings(struct b44 *bp)

if (rp->skb == NULL)
continue;
dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len,
dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
DMA_TO_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
Expand All @@ -1117,12 +1117,12 @@ 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->dev, bp->rx_ring_dma,
dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);

if (bp->flags & B44_FLAG_TX_RING_HACK)
dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma,
dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);

Expand All @@ -1144,24 +1144,24 @@ 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->dev, bp->rx_ring_dma,
dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
kfree(bp->rx_ring);
} else
dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
bp->rx_ring, bp->rx_ring_dma);
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->dev, bp->tx_ring_dma,
dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
kfree(bp->tx_ring);
} else
dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
bp->flags &= ~B44_FLAG_TX_RING_HACK;
Expand All @@ -1187,7 +1187,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->dev, size, &bp->rx_ring_dma, gfp);
bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, 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
Expand All @@ -1199,7 +1199,7 @@ 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->dev, rx_ring,
rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);

Expand All @@ -1214,7 +1214,7 @@ 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->dev, size, &bp->tx_ring_dma, gfp);
bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp);
if (!bp->tx_ring) {
/* Allocation may have failed due to dma_alloc_coherent
insisting on use of GFP_DMA, which is more restrictive
Expand All @@ -1226,7 +1226,7 @@ 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->dev, tx_ring,
tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);

Expand Down
27 changes: 14 additions & 13 deletions drivers/net/wireless/b43/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,10 @@ static inline
dma_addr_t dmaaddr;

if (tx) {
dmaaddr = dma_map_single(ring->dev->dev->dev,
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len, DMA_TO_DEVICE);
} else {
dmaaddr = dma_map_single(ring->dev->dev->dev,
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len, DMA_FROM_DEVICE);
}

Expand All @@ -388,9 +388,10 @@ static inline
dma_addr_t addr, size_t len, int tx)
{
if (tx) {
dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE);
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len, DMA_TO_DEVICE);
} else {
dma_unmap_single(ring->dev->dev->dev,
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
}
Expand All @@ -400,7 +401,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
dma_sync_single_for_cpu(ring->dev->dev->dev,
dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}

Expand All @@ -409,7 +410,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
dma_sync_single_for_device(ring->dev->dev->dev,
dma_sync_single_for_device(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}

Expand All @@ -425,7 +426,7 @@ static inline

static int alloc_ringmemory(struct b43_dmaring *ring)
{
struct device *dev = ring->dev->dev->dev;
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
Expand All @@ -439,7 +440,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
Expand All @@ -452,9 +453,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)

static void free_ringmemory(struct b43_dmaring *ring)
{
struct device *dev = ring->dev->dev->dev;
struct device *dma_dev = ring->dev->dev->dma_dev;

dma_free_coherent(dev, B43_DMA_RINGMEMSIZE,
dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase);
}

Expand Down Expand Up @@ -854,7 +855,7 @@ 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->dev,
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
Expand All @@ -869,7 +870,7 @@ 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->dev,
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
Expand All @@ -883,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
}
}

dma_unmap_single(dev->dev->dev,
dma_unmap_single(dev->dev->dma_dev,
dma_test, b43_txhdr_size(dev),
DMA_TO_DEVICE);
}
Expand Down
14 changes: 8 additions & 6 deletions drivers/ssb/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,15 +436,18 @@ 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;
}

Expand Down Expand Up @@ -1018,15 +1021,14 @@ EXPORT_SYMBOL(ssb_dma_translation);

int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
{
struct device *dev = ssb_dev->dev;
struct device *dma_dev = ssb_dev->dma_dev;

#ifdef CONFIG_SSB_PCIHOST
if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI &&
!dma_supported(dev, mask))
return -EIO;
if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI)
return dma_set_mask(dma_dev, mask);
#endif
dev->coherent_dma_mask = mask;
dev->dma_mask = &dev->coherent_dma_mask;
dma_dev->coherent_dma_mask = mask;
dma_dev->dma_mask = &dma_dev->coherent_dma_mask;

return 0;
}
Expand Down
4 changes: 4 additions & 0 deletions include/linux/ssb/ssb.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ 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;

Expand Down

0 comments on commit 4ac5846

Please sign in to comment.