aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/b44.c134
-rw-r--r--drivers/net/b44.h2
2 files changed, 128 insertions, 8 deletions
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index d27e870e59ab..282ebd15f011 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -106,6 +106,29 @@ static int b44_poll(struct net_device *dev, int *budget);
106static void b44_poll_controller(struct net_device *dev); 106static void b44_poll_controller(struct net_device *dev);
107#endif 107#endif
108 108
109static int dma_desc_align_mask;
110static int dma_desc_sync_size;
111
112static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
113 dma_addr_t dma_base,
114 unsigned long offset,
115 enum dma_data_direction dir)
116{
117 dma_sync_single_range_for_device(&pdev->dev, dma_base,
118 offset & dma_desc_align_mask,
119 dma_desc_sync_size, dir);
120}
121
122static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
123 dma_addr_t dma_base,
124 unsigned long offset,
125 enum dma_data_direction dir)
126{
127 dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
128 offset & dma_desc_align_mask,
129 dma_desc_sync_size, dir);
130}
131
109static inline unsigned long br32(const struct b44 *bp, unsigned long reg) 132static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
110{ 133{
111 return readl(bp->regs + reg); 134 return readl(bp->regs + reg);
@@ -668,6 +691,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
668 dp->ctrl = cpu_to_le32(ctrl); 691 dp->ctrl = cpu_to_le32(ctrl);
669 dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); 692 dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
670 693
694 if (bp->flags & B44_FLAG_RX_RING_HACK)
695 b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
696 dest_idx * sizeof(dp),
697 DMA_BIDIRECTIONAL);
698
671 return RX_PKT_BUF_SZ; 699 return RX_PKT_BUF_SZ;
672} 700}
673 701
@@ -692,6 +720,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
692 pci_unmap_addr_set(dest_map, mapping, 720 pci_unmap_addr_set(dest_map, mapping,
693 pci_unmap_addr(src_map, mapping)); 721 pci_unmap_addr(src_map, mapping));
694 722
723 if (bp->flags & B44_FLAG_RX_RING_HACK)
724 b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
725 src_idx * sizeof(src_desc),
726 DMA_BIDIRECTIONAL);
727
695 ctrl = src_desc->ctrl; 728 ctrl = src_desc->ctrl;
696 if (dest_idx == (B44_RX_RING_SIZE - 1)) 729 if (dest_idx == (B44_RX_RING_SIZE - 1))
697 ctrl |= cpu_to_le32(DESC_CTRL_EOT); 730 ctrl |= cpu_to_le32(DESC_CTRL_EOT);
@@ -700,8 +733,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
700 733
701 dest_desc->ctrl = ctrl; 734 dest_desc->ctrl = ctrl;
702 dest_desc->addr = src_desc->addr; 735 dest_desc->addr = src_desc->addr;
736
703 src_map->skb = NULL; 737 src_map->skb = NULL;
704 738
739 if (bp->flags & B44_FLAG_RX_RING_HACK)
740 b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
741 dest_idx * sizeof(dest_desc),
742 DMA_BIDIRECTIONAL);
743
705 pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, 744 pci_dma_sync_single_for_device(bp->pdev, src_desc->addr,
706 RX_PKT_BUF_SZ, 745 RX_PKT_BUF_SZ,
707 PCI_DMA_FROMDEVICE); 746 PCI_DMA_FROMDEVICE);
@@ -959,6 +998,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
959 bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); 998 bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl);
960 bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); 999 bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
961 1000
1001 if (bp->flags & B44_FLAG_TX_RING_HACK)
1002 b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
1003 entry * sizeof(bp->tx_ring[0]),
1004 DMA_TO_DEVICE);
1005
962 entry = NEXT_TX(entry); 1006 entry = NEXT_TX(entry);
963 1007
964 bp->tx_prod = entry; 1008 bp->tx_prod = entry;
@@ -1064,6 +1108,16 @@ static void b44_init_rings(struct b44 *bp)
1064 memset(bp->rx_ring, 0, B44_RX_RING_BYTES); 1108 memset(bp->rx_ring, 0, B44_RX_RING_BYTES);
1065 memset(bp->tx_ring, 0, B44_TX_RING_BYTES); 1109 memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
1066 1110
1111 if (bp->flags & B44_FLAG_RX_RING_HACK)
1112 dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
1113 DMA_TABLE_BYTES,
1114 PCI_DMA_BIDIRECTIONAL);
1115
1116 if (bp->flags & B44_FLAG_TX_RING_HACK)
1117 dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
1118 DMA_TABLE_BYTES,
1119 PCI_DMA_TODEVICE);
1120
1067 for (i = 0; i < bp->rx_pending; i++) { 1121 for (i = 0; i < bp->rx_pending; i++) {
1068 if (b44_alloc_rx_skb(bp, -1, i) < 0) 1122 if (b44_alloc_rx_skb(bp, -1, i) < 0)
1069 break; 1123 break;
@@ -1085,14 +1139,28 @@ static void b44_free_consistent(struct b44 *bp)
1085 bp->tx_buffers = NULL; 1139 bp->tx_buffers = NULL;
1086 } 1140 }
1087 if (bp->rx_ring) { 1141 if (bp->rx_ring) {
1088 pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, 1142 if (bp->flags & B44_FLAG_RX_RING_HACK) {
1089 bp->rx_ring, bp->rx_ring_dma); 1143 dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
1144 DMA_TABLE_BYTES,
1145 DMA_BIDIRECTIONAL);
1146 kfree(bp->rx_ring);
1147 } else
1148 pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
1149 bp->rx_ring, bp->rx_ring_dma);
1090 bp->rx_ring = NULL; 1150 bp->rx_ring = NULL;
1151 bp->flags &= ~B44_FLAG_RX_RING_HACK;
1091 } 1152 }
1092 if (bp->tx_ring) { 1153 if (bp->tx_ring) {
1093 pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, 1154 if (bp->flags & B44_FLAG_TX_RING_HACK) {
1094 bp->tx_ring, bp->tx_ring_dma); 1155 dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
1156 DMA_TABLE_BYTES,
1157 DMA_TO_DEVICE);
1158 kfree(bp->tx_ring);
1159 } else
1160 pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
1161 bp->tx_ring, bp->tx_ring_dma);
1095 bp->tx_ring = NULL; 1162 bp->tx_ring = NULL;
1163 bp->flags &= ~B44_FLAG_TX_RING_HACK;
1096 } 1164 }
1097} 1165}
1098 1166
@@ -1118,12 +1186,56 @@ static int b44_alloc_consistent(struct b44 *bp)
1118 1186
1119 size = DMA_TABLE_BYTES; 1187 size = DMA_TABLE_BYTES;
1120 bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); 1188 bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
1121 if (!bp->rx_ring) 1189 if (!bp->rx_ring) {
1122 goto out_err; 1190 /* Allocation may have failed due to pci_alloc_consistent
1191 insisting on use of GFP_DMA, which is more restrictive
1192 than necessary... */
1193 struct dma_desc *rx_ring;
1194 dma_addr_t rx_ring_dma;
1195
1196 if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
1197 goto out_err;
1198
1199 memset(rx_ring, 0, size);
1200 rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
1201 DMA_TABLE_BYTES,
1202 DMA_BIDIRECTIONAL);
1203
1204 if (rx_ring_dma + size > B44_DMA_MASK) {
1205 kfree(rx_ring);
1206 goto out_err;
1207 }
1208
1209 bp->rx_ring = rx_ring;
1210 bp->rx_ring_dma = rx_ring_dma;
1211 bp->flags |= B44_FLAG_RX_RING_HACK;
1212 }
1123 1213
1124 bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); 1214 bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
1125 if (!bp->tx_ring) 1215 if (!bp->tx_ring) {
1126 goto out_err; 1216 /* Allocation may have failed due to pci_alloc_consistent
1217 insisting on use of GFP_DMA, which is more restrictive
1218 than necessary... */
1219 struct dma_desc *tx_ring;
1220 dma_addr_t tx_ring_dma;
1221
1222 if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
1223 goto out_err;
1224
1225 memset(tx_ring, 0, size);
1226 tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
1227 DMA_TABLE_BYTES,
1228 DMA_TO_DEVICE);
1229
1230 if (tx_ring_dma + size > B44_DMA_MASK) {
1231 kfree(tx_ring);
1232 goto out_err;
1233 }
1234
1235 bp->tx_ring = tx_ring;
1236 bp->tx_ring_dma = tx_ring_dma;
1237 bp->flags |= B44_FLAG_TX_RING_HACK;
1238 }
1127 1239
1128 return 0; 1240 return 0;
1129 1241
@@ -1973,6 +2085,12 @@ static struct pci_driver b44_driver = {
1973 2085
1974static int __init b44_init(void) 2086static int __init b44_init(void)
1975{ 2087{
2088 unsigned int dma_desc_align_size = dma_get_cache_alignment();
2089
2090 /* Setup paramaters for syncing RX/TX DMA descriptors */
2091 dma_desc_align_mask = ~(dma_desc_align_size - 1);
2092 dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc));
2093
1976 return pci_module_init(&b44_driver); 2094 return pci_module_init(&b44_driver);
1977} 2095}
1978 2096
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 11c40a2e71c7..593cb0ad4100 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -400,6 +400,8 @@ struct b44 {
400#define B44_FLAG_ADV_100HALF 0x04000000 400#define B44_FLAG_ADV_100HALF 0x04000000
401#define B44_FLAG_ADV_100FULL 0x08000000 401#define B44_FLAG_ADV_100FULL 0x08000000
402#define B44_FLAG_INTERNAL_PHY 0x10000000 402#define B44_FLAG_INTERNAL_PHY 0x10000000
403#define B44_FLAG_RX_RING_HACK 0x20000000
404#define B44_FLAG_TX_RING_HACK 0x40000000
403 405
404 u32 rx_offset; 406 u32 rx_offset;
405 407