diff options
-rw-r--r-- | drivers/net/b44.c | 134 | ||||
-rw-r--r-- | drivers/net/b44.h | 2 |
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); | |||
106 | static void b44_poll_controller(struct net_device *dev); | 106 | static void b44_poll_controller(struct net_device *dev); |
107 | #endif | 107 | #endif |
108 | 108 | ||
109 | static int dma_desc_align_mask; | ||
110 | static int dma_desc_sync_size; | ||
111 | |||
112 | static 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 | |||
122 | static 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 | |||
109 | static inline unsigned long br32(const struct b44 *bp, unsigned long reg) | 132 | static 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 | ||
1974 | static int __init b44_init(void) | 2086 | static 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 | ||