diff options
Diffstat (limited to 'drivers/net/b44.c')
-rw-r--r-- | drivers/net/b44.c | 164 |
1 files changed, 143 insertions, 21 deletions
diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 94939f570f78..0ee3e27969c6 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/version.h> | 21 | #include <linux/version.h> |
22 | #include <linux/dma-mapping.h> | ||
22 | 23 | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
@@ -106,6 +107,29 @@ static int b44_poll(struct net_device *dev, int *budget); | |||
106 | static void b44_poll_controller(struct net_device *dev); | 107 | static void b44_poll_controller(struct net_device *dev); |
107 | #endif | 108 | #endif |
108 | 109 | ||
110 | static int dma_desc_align_mask; | ||
111 | static int dma_desc_sync_size; | ||
112 | |||
113 | static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, | ||
114 | dma_addr_t dma_base, | ||
115 | unsigned long offset, | ||
116 | enum dma_data_direction dir) | ||
117 | { | ||
118 | dma_sync_single_range_for_device(&pdev->dev, dma_base, | ||
119 | offset & dma_desc_align_mask, | ||
120 | dma_desc_sync_size, dir); | ||
121 | } | ||
122 | |||
123 | static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, | ||
124 | dma_addr_t dma_base, | ||
125 | unsigned long offset, | ||
126 | enum dma_data_direction dir) | ||
127 | { | ||
128 | dma_sync_single_range_for_cpu(&pdev->dev, dma_base, | ||
129 | offset & dma_desc_align_mask, | ||
130 | dma_desc_sync_size, dir); | ||
131 | } | ||
132 | |||
109 | static inline unsigned long br32(const struct b44 *bp, unsigned long reg) | 133 | static inline unsigned long br32(const struct b44 *bp, unsigned long reg) |
110 | { | 134 | { |
111 | return readl(bp->regs + reg); | 135 | return readl(bp->regs + reg); |
@@ -668,6 +692,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) | |||
668 | dp->ctrl = cpu_to_le32(ctrl); | 692 | dp->ctrl = cpu_to_le32(ctrl); |
669 | dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); | 693 | dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); |
670 | 694 | ||
695 | if (bp->flags & B44_FLAG_RX_RING_HACK) | ||
696 | b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, | ||
697 | dest_idx * sizeof(dp), | ||
698 | DMA_BIDIRECTIONAL); | ||
699 | |||
671 | return RX_PKT_BUF_SZ; | 700 | return RX_PKT_BUF_SZ; |
672 | } | 701 | } |
673 | 702 | ||
@@ -692,6 +721,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) | |||
692 | pci_unmap_addr_set(dest_map, mapping, | 721 | pci_unmap_addr_set(dest_map, mapping, |
693 | pci_unmap_addr(src_map, mapping)); | 722 | pci_unmap_addr(src_map, mapping)); |
694 | 723 | ||
724 | if (bp->flags & B44_FLAG_RX_RING_HACK) | ||
725 | b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, | ||
726 | src_idx * sizeof(src_desc), | ||
727 | DMA_BIDIRECTIONAL); | ||
728 | |||
695 | ctrl = src_desc->ctrl; | 729 | ctrl = src_desc->ctrl; |
696 | if (dest_idx == (B44_RX_RING_SIZE - 1)) | 730 | if (dest_idx == (B44_RX_RING_SIZE - 1)) |
697 | ctrl |= cpu_to_le32(DESC_CTRL_EOT); | 731 | ctrl |= cpu_to_le32(DESC_CTRL_EOT); |
@@ -700,8 +734,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) | |||
700 | 734 | ||
701 | dest_desc->ctrl = ctrl; | 735 | dest_desc->ctrl = ctrl; |
702 | dest_desc->addr = src_desc->addr; | 736 | dest_desc->addr = src_desc->addr; |
737 | |||
703 | src_map->skb = NULL; | 738 | src_map->skb = NULL; |
704 | 739 | ||
740 | if (bp->flags & B44_FLAG_RX_RING_HACK) | ||
741 | b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, | ||
742 | dest_idx * sizeof(dest_desc), | ||
743 | DMA_BIDIRECTIONAL); | ||
744 | |||
705 | pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, | 745 | pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, |
706 | RX_PKT_BUF_SZ, | 746 | RX_PKT_BUF_SZ, |
707 | PCI_DMA_FROMDEVICE); | 747 | PCI_DMA_FROMDEVICE); |
@@ -959,6 +999,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
959 | bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); | 999 | bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); |
960 | bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); | 1000 | bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); |
961 | 1001 | ||
1002 | if (bp->flags & B44_FLAG_TX_RING_HACK) | ||
1003 | b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, | ||
1004 | entry * sizeof(bp->tx_ring[0]), | ||
1005 | DMA_TO_DEVICE); | ||
1006 | |||
962 | entry = NEXT_TX(entry); | 1007 | entry = NEXT_TX(entry); |
963 | 1008 | ||
964 | bp->tx_prod = entry; | 1009 | bp->tx_prod = entry; |
@@ -1064,6 +1109,16 @@ static void b44_init_rings(struct b44 *bp) | |||
1064 | memset(bp->rx_ring, 0, B44_RX_RING_BYTES); | 1109 | memset(bp->rx_ring, 0, B44_RX_RING_BYTES); |
1065 | memset(bp->tx_ring, 0, B44_TX_RING_BYTES); | 1110 | memset(bp->tx_ring, 0, B44_TX_RING_BYTES); |
1066 | 1111 | ||
1112 | if (bp->flags & B44_FLAG_RX_RING_HACK) | ||
1113 | dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, | ||
1114 | DMA_TABLE_BYTES, | ||
1115 | PCI_DMA_BIDIRECTIONAL); | ||
1116 | |||
1117 | if (bp->flags & B44_FLAG_TX_RING_HACK) | ||
1118 | dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, | ||
1119 | DMA_TABLE_BYTES, | ||
1120 | PCI_DMA_TODEVICE); | ||
1121 | |||
1067 | for (i = 0; i < bp->rx_pending; i++) { | 1122 | for (i = 0; i < bp->rx_pending; i++) { |
1068 | if (b44_alloc_rx_skb(bp, -1, i) < 0) | 1123 | if (b44_alloc_rx_skb(bp, -1, i) < 0) |
1069 | break; | 1124 | break; |
@@ -1076,23 +1131,33 @@ static void b44_init_rings(struct b44 *bp) | |||
1076 | */ | 1131 | */ |
1077 | static void b44_free_consistent(struct b44 *bp) | 1132 | static void b44_free_consistent(struct b44 *bp) |
1078 | { | 1133 | { |
1079 | if (bp->rx_buffers) { | 1134 | kfree(bp->rx_buffers); |
1080 | kfree(bp->rx_buffers); | 1135 | bp->rx_buffers = NULL; |
1081 | bp->rx_buffers = NULL; | 1136 | kfree(bp->tx_buffers); |
1082 | } | 1137 | bp->tx_buffers = NULL; |
1083 | if (bp->tx_buffers) { | ||
1084 | kfree(bp->tx_buffers); | ||
1085 | bp->tx_buffers = NULL; | ||
1086 | } | ||
1087 | if (bp->rx_ring) { | 1138 | if (bp->rx_ring) { |
1088 | pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, | 1139 | if (bp->flags & B44_FLAG_RX_RING_HACK) { |
1089 | bp->rx_ring, bp->rx_ring_dma); | 1140 | dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, |
1141 | DMA_TABLE_BYTES, | ||
1142 | DMA_BIDIRECTIONAL); | ||
1143 | kfree(bp->rx_ring); | ||
1144 | } else | ||
1145 | pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, | ||
1146 | bp->rx_ring, bp->rx_ring_dma); | ||
1090 | bp->rx_ring = NULL; | 1147 | bp->rx_ring = NULL; |
1148 | bp->flags &= ~B44_FLAG_RX_RING_HACK; | ||
1091 | } | 1149 | } |
1092 | if (bp->tx_ring) { | 1150 | if (bp->tx_ring) { |
1093 | pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, | 1151 | if (bp->flags & B44_FLAG_TX_RING_HACK) { |
1094 | bp->tx_ring, bp->tx_ring_dma); | 1152 | dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, |
1153 | DMA_TABLE_BYTES, | ||
1154 | DMA_TO_DEVICE); | ||
1155 | kfree(bp->tx_ring); | ||
1156 | } else | ||
1157 | pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, | ||
1158 | bp->tx_ring, bp->tx_ring_dma); | ||
1095 | bp->tx_ring = NULL; | 1159 | bp->tx_ring = NULL; |
1160 | bp->flags &= ~B44_FLAG_TX_RING_HACK; | ||
1096 | } | 1161 | } |
1097 | } | 1162 | } |
1098 | 1163 | ||
@@ -1118,12 +1183,56 @@ static int b44_alloc_consistent(struct b44 *bp) | |||
1118 | 1183 | ||
1119 | size = DMA_TABLE_BYTES; | 1184 | size = DMA_TABLE_BYTES; |
1120 | bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); | 1185 | bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); |
1121 | if (!bp->rx_ring) | 1186 | if (!bp->rx_ring) { |
1122 | goto out_err; | 1187 | /* Allocation may have failed due to pci_alloc_consistent |
1188 | insisting on use of GFP_DMA, which is more restrictive | ||
1189 | than necessary... */ | ||
1190 | struct dma_desc *rx_ring; | ||
1191 | dma_addr_t rx_ring_dma; | ||
1192 | |||
1193 | if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) | ||
1194 | goto out_err; | ||
1195 | |||
1196 | memset(rx_ring, 0, size); | ||
1197 | rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, | ||
1198 | DMA_TABLE_BYTES, | ||
1199 | DMA_BIDIRECTIONAL); | ||
1200 | |||
1201 | if (rx_ring_dma + size > B44_DMA_MASK) { | ||
1202 | kfree(rx_ring); | ||
1203 | goto out_err; | ||
1204 | } | ||
1205 | |||
1206 | bp->rx_ring = rx_ring; | ||
1207 | bp->rx_ring_dma = rx_ring_dma; | ||
1208 | bp->flags |= B44_FLAG_RX_RING_HACK; | ||
1209 | } | ||
1123 | 1210 | ||
1124 | bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); | 1211 | bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); |
1125 | if (!bp->tx_ring) | 1212 | if (!bp->tx_ring) { |
1126 | goto out_err; | 1213 | /* Allocation may have failed due to pci_alloc_consistent |
1214 | insisting on use of GFP_DMA, which is more restrictive | ||
1215 | than necessary... */ | ||
1216 | struct dma_desc *tx_ring; | ||
1217 | dma_addr_t tx_ring_dma; | ||
1218 | |||
1219 | if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) | ||
1220 | goto out_err; | ||
1221 | |||
1222 | memset(tx_ring, 0, size); | ||
1223 | tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, | ||
1224 | DMA_TABLE_BYTES, | ||
1225 | DMA_TO_DEVICE); | ||
1226 | |||
1227 | if (tx_ring_dma + size > B44_DMA_MASK) { | ||
1228 | kfree(tx_ring); | ||
1229 | goto out_err; | ||
1230 | } | ||
1231 | |||
1232 | bp->tx_ring = tx_ring; | ||
1233 | bp->tx_ring_dma = tx_ring_dma; | ||
1234 | bp->flags |= B44_FLAG_TX_RING_HACK; | ||
1235 | } | ||
1127 | 1236 | ||
1128 | return 0; | 1237 | return 0; |
1129 | 1238 | ||
@@ -1507,14 +1616,14 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
1507 | 1616 | ||
1508 | cmd->advertising = 0; | 1617 | cmd->advertising = 0; |
1509 | if (bp->flags & B44_FLAG_ADV_10HALF) | 1618 | if (bp->flags & B44_FLAG_ADV_10HALF) |
1510 | cmd->advertising |= ADVERTISE_10HALF; | 1619 | cmd->advertising |= ADVERTISED_10baseT_Half; |
1511 | if (bp->flags & B44_FLAG_ADV_10FULL) | 1620 | if (bp->flags & B44_FLAG_ADV_10FULL) |
1512 | cmd->advertising |= ADVERTISE_10FULL; | 1621 | cmd->advertising |= ADVERTISED_10baseT_Full; |
1513 | if (bp->flags & B44_FLAG_ADV_100HALF) | 1622 | if (bp->flags & B44_FLAG_ADV_100HALF) |
1514 | cmd->advertising |= ADVERTISE_100HALF; | 1623 | cmd->advertising |= ADVERTISED_100baseT_Half; |
1515 | if (bp->flags & B44_FLAG_ADV_100FULL) | 1624 | if (bp->flags & B44_FLAG_ADV_100FULL) |
1516 | cmd->advertising |= ADVERTISE_100FULL; | 1625 | cmd->advertising |= ADVERTISED_100baseT_Full; |
1517 | cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | 1626 | cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; |
1518 | cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? | 1627 | cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? |
1519 | SPEED_100 : SPEED_10; | 1628 | SPEED_100 : SPEED_10; |
1520 | cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? | 1629 | cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? |
@@ -1676,6 +1785,7 @@ static struct ethtool_ops b44_ethtool_ops = { | |||
1676 | .set_pauseparam = b44_set_pauseparam, | 1785 | .set_pauseparam = b44_set_pauseparam, |
1677 | .get_msglevel = b44_get_msglevel, | 1786 | .get_msglevel = b44_get_msglevel, |
1678 | .set_msglevel = b44_set_msglevel, | 1787 | .set_msglevel = b44_set_msglevel, |
1788 | .get_perm_addr = ethtool_op_get_perm_addr, | ||
1679 | }; | 1789 | }; |
1680 | 1790 | ||
1681 | static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 1791 | static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
@@ -1718,6 +1828,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) | |||
1718 | bp->dev->dev_addr[3] = eeprom[80]; | 1828 | bp->dev->dev_addr[3] = eeprom[80]; |
1719 | bp->dev->dev_addr[4] = eeprom[83]; | 1829 | bp->dev->dev_addr[4] = eeprom[83]; |
1720 | bp->dev->dev_addr[5] = eeprom[82]; | 1830 | bp->dev->dev_addr[5] = eeprom[82]; |
1831 | memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); | ||
1721 | 1832 | ||
1722 | bp->phy_addr = eeprom[90] & 0x1f; | 1833 | bp->phy_addr = eeprom[90] & 0x1f; |
1723 | 1834 | ||
@@ -1930,6 +2041,8 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1930 | b44_free_rings(bp); | 2041 | b44_free_rings(bp); |
1931 | 2042 | ||
1932 | spin_unlock_irq(&bp->lock); | 2043 | spin_unlock_irq(&bp->lock); |
2044 | |||
2045 | free_irq(dev->irq, dev); | ||
1933 | pci_disable_device(pdev); | 2046 | pci_disable_device(pdev); |
1934 | return 0; | 2047 | return 0; |
1935 | } | 2048 | } |
@@ -1946,6 +2059,9 @@ static int b44_resume(struct pci_dev *pdev) | |||
1946 | if (!netif_running(dev)) | 2059 | if (!netif_running(dev)) |
1947 | return 0; | 2060 | return 0; |
1948 | 2061 | ||
2062 | if (request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev)) | ||
2063 | printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); | ||
2064 | |||
1949 | spin_lock_irq(&bp->lock); | 2065 | spin_lock_irq(&bp->lock); |
1950 | 2066 | ||
1951 | b44_init_rings(bp); | 2067 | b44_init_rings(bp); |
@@ -1971,6 +2087,12 @@ static struct pci_driver b44_driver = { | |||
1971 | 2087 | ||
1972 | static int __init b44_init(void) | 2088 | static int __init b44_init(void) |
1973 | { | 2089 | { |
2090 | unsigned int dma_desc_align_size = dma_get_cache_alignment(); | ||
2091 | |||
2092 | /* Setup paramaters for syncing RX/TX DMA descriptors */ | ||
2093 | dma_desc_align_mask = ~(dma_desc_align_size - 1); | ||
2094 | dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc)); | ||
2095 | |||
1974 | return pci_module_init(&b44_driver); | 2096 | return pci_module_init(&b44_driver); |
1975 | } | 2097 | } |
1976 | 2098 | ||