diff options
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r-- | drivers/net/forcedeth.c | 164 |
1 files changed, 100 insertions, 64 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index c39344adecce..3682ec61e8a8 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -101,6 +101,7 @@ | |||
101 | * 0.46: 20 Oct 2005: Add irq optimization modes. | 101 | * 0.46: 20 Oct 2005: Add irq optimization modes. |
102 | * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. | 102 | * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. |
103 | * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single | 103 | * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single |
104 | * 0.49: 10 Dec 2005: Fix tso for large buffers. | ||
104 | * | 105 | * |
105 | * Known bugs: | 106 | * Known bugs: |
106 | * We suspect that on some hardware no TX done interrupts are generated. | 107 | * We suspect that on some hardware no TX done interrupts are generated. |
@@ -112,7 +113,7 @@ | |||
112 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few | 113 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few |
113 | * superfluous timer interrupts from the nic. | 114 | * superfluous timer interrupts from the nic. |
114 | */ | 115 | */ |
115 | #define FORCEDETH_VERSION "0.48" | 116 | #define FORCEDETH_VERSION "0.49" |
116 | #define DRV_NAME "forcedeth" | 117 | #define DRV_NAME "forcedeth" |
117 | 118 | ||
118 | #include <linux/module.h> | 119 | #include <linux/module.h> |
@@ -349,6 +350,8 @@ typedef union _ring_type { | |||
349 | #define NV_TX2_VALID (1<<31) | 350 | #define NV_TX2_VALID (1<<31) |
350 | #define NV_TX2_TSO (1<<28) | 351 | #define NV_TX2_TSO (1<<28) |
351 | #define NV_TX2_TSO_SHIFT 14 | 352 | #define NV_TX2_TSO_SHIFT 14 |
353 | #define NV_TX2_TSO_MAX_SHIFT 14 | ||
354 | #define NV_TX2_TSO_MAX_SIZE (1<<NV_TX2_TSO_MAX_SHIFT) | ||
352 | #define NV_TX2_CHECKSUM_L3 (1<<27) | 355 | #define NV_TX2_CHECKSUM_L3 (1<<27) |
353 | #define NV_TX2_CHECKSUM_L4 (1<<26) | 356 | #define NV_TX2_CHECKSUM_L4 (1<<26) |
354 | 357 | ||
@@ -408,15 +411,15 @@ typedef union _ring_type { | |||
408 | #define NV_WATCHDOG_TIMEO (5*HZ) | 411 | #define NV_WATCHDOG_TIMEO (5*HZ) |
409 | 412 | ||
410 | #define RX_RING 128 | 413 | #define RX_RING 128 |
411 | #define TX_RING 64 | 414 | #define TX_RING 256 |
412 | /* | 415 | /* |
413 | * If your nic mysteriously hangs then try to reduce the limits | 416 | * If your nic mysteriously hangs then try to reduce the limits |
414 | * to 1/0: It might be required to set NV_TX_LASTPACKET in the | 417 | * to 1/0: It might be required to set NV_TX_LASTPACKET in the |
415 | * last valid ring entry. But this would be impossible to | 418 | * last valid ring entry. But this would be impossible to |
416 | * implement - probably a disassembly error. | 419 | * implement - probably a disassembly error. |
417 | */ | 420 | */ |
418 | #define TX_LIMIT_STOP 63 | 421 | #define TX_LIMIT_STOP 255 |
419 | #define TX_LIMIT_START 62 | 422 | #define TX_LIMIT_START 254 |
420 | 423 | ||
421 | /* rx/tx mac addr + type + vlan + align + slack*/ | 424 | /* rx/tx mac addr + type + vlan + align + slack*/ |
422 | #define NV_RX_HEADERS (64) | 425 | #define NV_RX_HEADERS (64) |
@@ -535,6 +538,7 @@ struct fe_priv { | |||
535 | unsigned int next_tx, nic_tx; | 538 | unsigned int next_tx, nic_tx; |
536 | struct sk_buff *tx_skbuff[TX_RING]; | 539 | struct sk_buff *tx_skbuff[TX_RING]; |
537 | dma_addr_t tx_dma[TX_RING]; | 540 | dma_addr_t tx_dma[TX_RING]; |
541 | unsigned int tx_dma_len[TX_RING]; | ||
538 | u32 tx_flags; | 542 | u32 tx_flags; |
539 | }; | 543 | }; |
540 | 544 | ||
@@ -935,6 +939,7 @@ static void nv_init_tx(struct net_device *dev) | |||
935 | else | 939 | else |
936 | np->tx_ring.ex[i].FlagLen = 0; | 940 | np->tx_ring.ex[i].FlagLen = 0; |
937 | np->tx_skbuff[i] = NULL; | 941 | np->tx_skbuff[i] = NULL; |
942 | np->tx_dma[i] = 0; | ||
938 | } | 943 | } |
939 | } | 944 | } |
940 | 945 | ||
@@ -945,30 +950,27 @@ static int nv_init_ring(struct net_device *dev) | |||
945 | return nv_alloc_rx(dev); | 950 | return nv_alloc_rx(dev); |
946 | } | 951 | } |
947 | 952 | ||
948 | static void nv_release_txskb(struct net_device *dev, unsigned int skbnr) | 953 | static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) |
949 | { | 954 | { |
950 | struct fe_priv *np = netdev_priv(dev); | 955 | struct fe_priv *np = netdev_priv(dev); |
951 | struct sk_buff *skb = np->tx_skbuff[skbnr]; | 956 | |
952 | unsigned int j, entry, fragments; | 957 | dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n", |
953 | 958 | dev->name, skbnr); | |
954 | dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n", | 959 | |
955 | dev->name, skbnr, np->tx_skbuff[skbnr]); | 960 | if (np->tx_dma[skbnr]) { |
956 | 961 | pci_unmap_page(np->pci_dev, np->tx_dma[skbnr], | |
957 | entry = skbnr; | 962 | np->tx_dma_len[skbnr], |
958 | if ((fragments = skb_shinfo(skb)->nr_frags) != 0) { | 963 | PCI_DMA_TODEVICE); |
959 | for (j = fragments; j >= 1; j--) { | 964 | np->tx_dma[skbnr] = 0; |
960 | skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1]; | 965 | } |
961 | pci_unmap_page(np->pci_dev, np->tx_dma[entry], | 966 | |
962 | frag->size, | 967 | if (np->tx_skbuff[skbnr]) { |
963 | PCI_DMA_TODEVICE); | 968 | dev_kfree_skb_irq(np->tx_skbuff[skbnr]); |
964 | entry = (entry - 1) % TX_RING; | 969 | np->tx_skbuff[skbnr] = NULL; |
965 | } | 970 | return 1; |
971 | } else { | ||
972 | return 0; | ||
966 | } | 973 | } |
967 | pci_unmap_single(np->pci_dev, np->tx_dma[entry], | ||
968 | skb->len - skb->data_len, | ||
969 | PCI_DMA_TODEVICE); | ||
970 | dev_kfree_skb_irq(skb); | ||
971 | np->tx_skbuff[skbnr] = NULL; | ||
972 | } | 974 | } |
973 | 975 | ||
974 | static void nv_drain_tx(struct net_device *dev) | 976 | static void nv_drain_tx(struct net_device *dev) |
@@ -981,10 +983,8 @@ static void nv_drain_tx(struct net_device *dev) | |||
981 | np->tx_ring.orig[i].FlagLen = 0; | 983 | np->tx_ring.orig[i].FlagLen = 0; |
982 | else | 984 | else |
983 | np->tx_ring.ex[i].FlagLen = 0; | 985 | np->tx_ring.ex[i].FlagLen = 0; |
984 | if (np->tx_skbuff[i]) { | 986 | if (nv_release_txskb(dev, i)) |
985 | nv_release_txskb(dev, i); | ||
986 | np->stats.tx_dropped++; | 987 | np->stats.tx_dropped++; |
987 | } | ||
988 | } | 988 | } |
989 | } | 989 | } |
990 | 990 | ||
@@ -1021,68 +1021,105 @@ static void drain_ring(struct net_device *dev) | |||
1021 | static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) | 1021 | static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) |
1022 | { | 1022 | { |
1023 | struct fe_priv *np = netdev_priv(dev); | 1023 | struct fe_priv *np = netdev_priv(dev); |
1024 | u32 tx_flags = 0; | ||
1024 | u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); | 1025 | u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); |
1025 | unsigned int fragments = skb_shinfo(skb)->nr_frags; | 1026 | unsigned int fragments = skb_shinfo(skb)->nr_frags; |
1026 | unsigned int nr = (np->next_tx + fragments) % TX_RING; | 1027 | unsigned int nr = (np->next_tx - 1) % TX_RING; |
1028 | unsigned int start_nr = np->next_tx % TX_RING; | ||
1027 | unsigned int i; | 1029 | unsigned int i; |
1030 | u32 offset = 0; | ||
1031 | u32 bcnt; | ||
1032 | u32 size = skb->len-skb->data_len; | ||
1033 | u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); | ||
1034 | |||
1035 | /* add fragments to entries count */ | ||
1036 | for (i = 0; i < fragments; i++) { | ||
1037 | entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) + | ||
1038 | ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); | ||
1039 | } | ||
1028 | 1040 | ||
1029 | spin_lock_irq(&np->lock); | 1041 | spin_lock_irq(&np->lock); |
1030 | 1042 | ||
1031 | if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) { | 1043 | if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) { |
1032 | spin_unlock_irq(&np->lock); | 1044 | spin_unlock_irq(&np->lock); |
1033 | netif_stop_queue(dev); | 1045 | netif_stop_queue(dev); |
1034 | return NETDEV_TX_BUSY; | 1046 | return NETDEV_TX_BUSY; |
1035 | } | 1047 | } |
1036 | 1048 | ||
1037 | np->tx_skbuff[nr] = skb; | 1049 | /* setup the header buffer */ |
1038 | 1050 | do { | |
1039 | if (fragments) { | 1051 | bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; |
1040 | dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments); | 1052 | nr = (nr + 1) % TX_RING; |
1041 | /* setup descriptors in reverse order */ | 1053 | |
1042 | for (i = fragments; i >= 1; i--) { | 1054 | np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt, |
1043 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; | 1055 | PCI_DMA_TODEVICE); |
1044 | np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size, | 1056 | np->tx_dma_len[nr] = bcnt; |
1045 | PCI_DMA_TODEVICE); | 1057 | |
1058 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { | ||
1059 | np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); | ||
1060 | np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); | ||
1061 | } else { | ||
1062 | np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; | ||
1063 | np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; | ||
1064 | np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); | ||
1065 | } | ||
1066 | tx_flags = np->tx_flags; | ||
1067 | offset += bcnt; | ||
1068 | size -= bcnt; | ||
1069 | } while(size); | ||
1070 | |||
1071 | /* setup the fragments */ | ||
1072 | for (i = 0; i < fragments; i++) { | ||
1073 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
1074 | u32 size = frag->size; | ||
1075 | offset = 0; | ||
1076 | |||
1077 | do { | ||
1078 | bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; | ||
1079 | nr = (nr + 1) % TX_RING; | ||
1080 | |||
1081 | np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, | ||
1082 | PCI_DMA_TODEVICE); | ||
1083 | np->tx_dma_len[nr] = bcnt; | ||
1046 | 1084 | ||
1047 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { | 1085 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { |
1048 | np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); | 1086 | np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); |
1049 | np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); | 1087 | np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); |
1050 | } else { | 1088 | } else { |
1051 | np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; | 1089 | np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; |
1052 | np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; | 1090 | np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; |
1053 | np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); | 1091 | np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); |
1054 | } | 1092 | } |
1055 | 1093 | offset += bcnt; | |
1056 | nr = (nr - 1) % TX_RING; | 1094 | size -= bcnt; |
1095 | } while (size); | ||
1096 | } | ||
1057 | 1097 | ||
1058 | if (np->desc_ver == DESC_VER_1) | 1098 | /* set last fragment flag */ |
1059 | tx_flags_extra &= ~NV_TX_LASTPACKET; | 1099 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { |
1060 | else | 1100 | np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra); |
1061 | tx_flags_extra &= ~NV_TX2_LASTPACKET; | 1101 | } else { |
1062 | } | 1102 | np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra); |
1063 | } | 1103 | } |
1064 | 1104 | ||
1105 | np->tx_skbuff[nr] = skb; | ||
1106 | |||
1065 | #ifdef NETIF_F_TSO | 1107 | #ifdef NETIF_F_TSO |
1066 | if (skb_shinfo(skb)->tso_size) | 1108 | if (skb_shinfo(skb)->tso_size) |
1067 | tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); | 1109 | tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); |
1068 | else | 1110 | else |
1069 | #endif | 1111 | #endif |
1070 | tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); | 1112 | tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); |
1071 | 1113 | ||
1072 | np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len, | 1114 | /* set tx flags */ |
1073 | PCI_DMA_TODEVICE); | ||
1074 | |||
1075 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { | 1115 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { |
1076 | np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); | 1116 | np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); |
1077 | np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); | ||
1078 | } else { | 1117 | } else { |
1079 | np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; | 1118 | np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); |
1080 | np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; | ||
1081 | np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); | ||
1082 | } | 1119 | } |
1083 | 1120 | ||
1084 | dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n", | 1121 | dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", |
1085 | dev->name, np->next_tx, tx_flags_extra); | 1122 | dev->name, np->next_tx, entries, tx_flags_extra); |
1086 | { | 1123 | { |
1087 | int j; | 1124 | int j; |
1088 | for (j=0; j<64; j++) { | 1125 | for (j=0; j<64; j++) { |
@@ -1093,7 +1130,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1093 | dprintk("\n"); | 1130 | dprintk("\n"); |
1094 | } | 1131 | } |
1095 | 1132 | ||
1096 | np->next_tx += 1 + fragments; | 1133 | np->next_tx += entries; |
1097 | 1134 | ||
1098 | dev->trans_start = jiffies; | 1135 | dev->trans_start = jiffies; |
1099 | spin_unlock_irq(&np->lock); | 1136 | spin_unlock_irq(&np->lock); |
@@ -1140,7 +1177,6 @@ static void nv_tx_done(struct net_device *dev) | |||
1140 | np->stats.tx_packets++; | 1177 | np->stats.tx_packets++; |
1141 | np->stats.tx_bytes += skb->len; | 1178 | np->stats.tx_bytes += skb->len; |
1142 | } | 1179 | } |
1143 | nv_release_txskb(dev, i); | ||
1144 | } | 1180 | } |
1145 | } else { | 1181 | } else { |
1146 | if (Flags & NV_TX2_LASTPACKET) { | 1182 | if (Flags & NV_TX2_LASTPACKET) { |
@@ -1156,9 +1192,9 @@ static void nv_tx_done(struct net_device *dev) | |||
1156 | np->stats.tx_packets++; | 1192 | np->stats.tx_packets++; |
1157 | np->stats.tx_bytes += skb->len; | 1193 | np->stats.tx_bytes += skb->len; |
1158 | } | 1194 | } |
1159 | nv_release_txskb(dev, i); | ||
1160 | } | 1195 | } |
1161 | } | 1196 | } |
1197 | nv_release_txskb(dev, i); | ||
1162 | np->nic_tx++; | 1198 | np->nic_tx++; |
1163 | } | 1199 | } |
1164 | if (np->next_tx - np->nic_tx < TX_LIMIT_START) | 1200 | if (np->next_tx - np->nic_tx < TX_LIMIT_START) |
@@ -2456,7 +2492,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2456 | np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; | 2492 | np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; |
2457 | dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; | 2493 | dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; |
2458 | #ifdef NETIF_F_TSO | 2494 | #ifdef NETIF_F_TSO |
2459 | /* disabled dev->features |= NETIF_F_TSO; */ | 2495 | dev->features |= NETIF_F_TSO; |
2460 | #endif | 2496 | #endif |
2461 | } | 2497 | } |
2462 | 2498 | ||