diff options
| author | <jgarzik@pretzel.yyz.us> | 2005-05-27 22:07:02 -0400 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@pobox.com> | 2005-05-27 22:07:02 -0400 |
| commit | 1f15d694522af9cd7492695f11dd2dc77b6cf098 (patch) | |
| tree | 7f67a4c38456ec73359d576a5c602d18c3c3ef72 /drivers/net/forcedeth.c | |
| parent | fff9cfd99c0f88645c3f50d7476d6c8cef99f140 (diff) | |
| parent | 254feb882a7c6e4e51416dff6a97d847fbbba551 (diff) | |
Automatic merge of /spare/repo/netdev-2.6 branch master
Diffstat (limited to 'drivers/net/forcedeth.c')
| -rw-r--r-- | drivers/net/forcedeth.c | 103 |
1 files changed, 86 insertions, 17 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index cda48c5d72a9..4ebcd052e150 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
| @@ -81,6 +81,7 @@ | |||
| 81 | * cause DMA to kfree'd memory. | 81 | * cause DMA to kfree'd memory. |
| 82 | * 0.31: 14 Nov 2004: ethtool support for getting/setting link | 82 | * 0.31: 14 Nov 2004: ethtool support for getting/setting link |
| 83 | * capabilities. | 83 | * capabilities. |
| 84 | * 0.32: 16 Apr 2005: RX_ERROR4 handling added. | ||
| 84 | * | 85 | * |
| 85 | * Known bugs: | 86 | * Known bugs: |
| 86 | * We suspect that on some hardware no TX done interrupts are generated. | 87 | * We suspect that on some hardware no TX done interrupts are generated. |
| @@ -92,7 +93,7 @@ | |||
| 92 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few | 93 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few |
| 93 | * superfluous timer interrupts from the nic. | 94 | * superfluous timer interrupts from the nic. |
| 94 | */ | 95 | */ |
| 95 | #define FORCEDETH_VERSION "0.31" | 96 | #define FORCEDETH_VERSION "0.32" |
| 96 | #define DRV_NAME "forcedeth" | 97 | #define DRV_NAME "forcedeth" |
| 97 | 98 | ||
| 98 | #include <linux/module.h> | 99 | #include <linux/module.h> |
| @@ -109,6 +110,7 @@ | |||
| 109 | #include <linux/mii.h> | 110 | #include <linux/mii.h> |
| 110 | #include <linux/random.h> | 111 | #include <linux/random.h> |
| 111 | #include <linux/init.h> | 112 | #include <linux/init.h> |
| 113 | #include <linux/if_vlan.h> | ||
| 112 | 114 | ||
| 113 | #include <asm/irq.h> | 115 | #include <asm/irq.h> |
| 114 | #include <asm/io.h> | 116 | #include <asm/io.h> |
| @@ -1013,6 +1015,59 @@ static void nv_tx_timeout(struct net_device *dev) | |||
| 1013 | spin_unlock_irq(&np->lock); | 1015 | spin_unlock_irq(&np->lock); |
| 1014 | } | 1016 | } |
| 1015 | 1017 | ||
| 1018 | /* | ||
| 1019 | * Called when the nic notices a mismatch between the actual data len on the | ||
| 1020 | * wire and the len indicated in the 802 header | ||
| 1021 | */ | ||
| 1022 | static int nv_getlen(struct net_device *dev, void *packet, int datalen) | ||
| 1023 | { | ||
| 1024 | int hdrlen; /* length of the 802 header */ | ||
| 1025 | int protolen; /* length as stored in the proto field */ | ||
| 1026 | |||
| 1027 | /* 1) calculate len according to header */ | ||
| 1028 | if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) { | ||
| 1029 | protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto ); | ||
| 1030 | hdrlen = VLAN_HLEN; | ||
| 1031 | } else { | ||
| 1032 | protolen = ntohs( ((struct ethhdr *)packet)->h_proto); | ||
| 1033 | hdrlen = ETH_HLEN; | ||
| 1034 | } | ||
| 1035 | dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n", | ||
| 1036 | dev->name, datalen, protolen, hdrlen); | ||
| 1037 | if (protolen > ETH_DATA_LEN) | ||
| 1038 | return datalen; /* Value in proto field not a len, no checks possible */ | ||
| 1039 | |||
| 1040 | protolen += hdrlen; | ||
| 1041 | /* consistency checks: */ | ||
| 1042 | if (datalen > ETH_ZLEN) { | ||
| 1043 | if (datalen >= protolen) { | ||
| 1044 | /* more data on wire than in 802 header, trim of | ||
| 1045 | * additional data. | ||
| 1046 | */ | ||
| 1047 | dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n", | ||
| 1048 | dev->name, protolen); | ||
| 1049 | return protolen; | ||
| 1050 | } else { | ||
| 1051 | /* less data on wire than mentioned in header. | ||
| 1052 | * Discard the packet. | ||
| 1053 | */ | ||
| 1054 | dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n", | ||
| 1055 | dev->name); | ||
| 1056 | return -1; | ||
| 1057 | } | ||
| 1058 | } else { | ||
| 1059 | /* short packet. Accept only if 802 values are also short */ | ||
| 1060 | if (protolen > ETH_ZLEN) { | ||
| 1061 | dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n", | ||
| 1062 | dev->name); | ||
| 1063 | return -1; | ||
| 1064 | } | ||
| 1065 | dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n", | ||
| 1066 | dev->name, datalen); | ||
| 1067 | return datalen; | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | |||
| 1016 | static void nv_rx_process(struct net_device *dev) | 1071 | static void nv_rx_process(struct net_device *dev) |
| 1017 | { | 1072 | { |
| 1018 | struct fe_priv *np = get_nvpriv(dev); | 1073 | struct fe_priv *np = get_nvpriv(dev); |
| @@ -1064,7 +1119,7 @@ static void nv_rx_process(struct net_device *dev) | |||
| 1064 | np->stats.rx_errors++; | 1119 | np->stats.rx_errors++; |
| 1065 | goto next_pkt; | 1120 | goto next_pkt; |
| 1066 | } | 1121 | } |
| 1067 | if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { | 1122 | if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { |
| 1068 | np->stats.rx_errors++; | 1123 | np->stats.rx_errors++; |
| 1069 | goto next_pkt; | 1124 | goto next_pkt; |
| 1070 | } | 1125 | } |
| @@ -1078,22 +1133,24 @@ static void nv_rx_process(struct net_device *dev) | |||
| 1078 | np->stats.rx_errors++; | 1133 | np->stats.rx_errors++; |
| 1079 | goto next_pkt; | 1134 | goto next_pkt; |
| 1080 | } | 1135 | } |
| 1081 | if (Flags & NV_RX_ERROR) { | 1136 | if (Flags & NV_RX_ERROR4) { |
| 1082 | /* framing errors are soft errors, the rest is fatal. */ | 1137 | len = nv_getlen(dev, np->rx_skbuff[i]->data, len); |
| 1083 | if (Flags & NV_RX_FRAMINGERR) { | 1138 | if (len < 0) { |
| 1084 | if (Flags & NV_RX_SUBSTRACT1) { | ||
| 1085 | len--; | ||
| 1086 | } | ||
| 1087 | } else { | ||
| 1088 | np->stats.rx_errors++; | 1139 | np->stats.rx_errors++; |
| 1089 | goto next_pkt; | 1140 | goto next_pkt; |
| 1090 | } | 1141 | } |
| 1091 | } | 1142 | } |
| 1143 | /* framing errors are soft errors. */ | ||
| 1144 | if (Flags & NV_RX_FRAMINGERR) { | ||
| 1145 | if (Flags & NV_RX_SUBSTRACT1) { | ||
| 1146 | len--; | ||
| 1147 | } | ||
| 1148 | } | ||
| 1092 | } else { | 1149 | } else { |
| 1093 | if (!(Flags & NV_RX2_DESCRIPTORVALID)) | 1150 | if (!(Flags & NV_RX2_DESCRIPTORVALID)) |
| 1094 | goto next_pkt; | 1151 | goto next_pkt; |
| 1095 | 1152 | ||
| 1096 | if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) { | 1153 | if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { |
| 1097 | np->stats.rx_errors++; | 1154 | np->stats.rx_errors++; |
| 1098 | goto next_pkt; | 1155 | goto next_pkt; |
| 1099 | } | 1156 | } |
| @@ -1107,17 +1164,19 @@ static void nv_rx_process(struct net_device *dev) | |||
| 1107 | np->stats.rx_errors++; | 1164 | np->stats.rx_errors++; |
| 1108 | goto next_pkt; | 1165 | goto next_pkt; |
| 1109 | } | 1166 | } |
| 1110 | if (Flags & NV_RX2_ERROR) { | 1167 | if (Flags & NV_RX2_ERROR4) { |
| 1111 | /* framing errors are soft errors, the rest is fatal. */ | 1168 | len = nv_getlen(dev, np->rx_skbuff[i]->data, len); |
| 1112 | if (Flags & NV_RX2_FRAMINGERR) { | 1169 | if (len < 0) { |
| 1113 | if (Flags & NV_RX2_SUBSTRACT1) { | ||
| 1114 | len--; | ||
| 1115 | } | ||
| 1116 | } else { | ||
| 1117 | np->stats.rx_errors++; | 1170 | np->stats.rx_errors++; |
| 1118 | goto next_pkt; | 1171 | goto next_pkt; |
| 1119 | } | 1172 | } |
| 1120 | } | 1173 | } |
| 1174 | /* framing errors are soft errors */ | ||
| 1175 | if (Flags & NV_RX2_FRAMINGERR) { | ||
| 1176 | if (Flags & NV_RX2_SUBSTRACT1) { | ||
| 1177 | len--; | ||
| 1178 | } | ||
| 1179 | } | ||
| 1121 | Flags &= NV_RX2_CHECKSUMMASK; | 1180 | Flags &= NV_RX2_CHECKSUMMASK; |
| 1122 | if (Flags == NV_RX2_CHECKSUMOK1 || | 1181 | if (Flags == NV_RX2_CHECKSUMOK1 || |
| 1123 | Flags == NV_RX2_CHECKSUMOK2 || | 1182 | Flags == NV_RX2_CHECKSUMOK2 || |
| @@ -1480,6 +1539,13 @@ static void nv_do_nic_poll(unsigned long data) | |||
| 1480 | enable_irq(dev->irq); | 1539 | enable_irq(dev->irq); |
| 1481 | } | 1540 | } |
| 1482 | 1541 | ||
| 1542 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
| 1543 | static void nv_poll_controller(struct net_device *dev) | ||
| 1544 | { | ||
| 1545 | nv_do_nic_poll((unsigned long) dev); | ||
| 1546 | } | ||
| 1547 | #endif | ||
| 1548 | |||
| 1483 | static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | 1549 | static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
| 1484 | { | 1550 | { |
| 1485 | struct fe_priv *np = get_nvpriv(dev); | 1551 | struct fe_priv *np = get_nvpriv(dev); |
| @@ -1962,6 +2028,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
| 1962 | dev->get_stats = nv_get_stats; | 2028 | dev->get_stats = nv_get_stats; |
| 1963 | dev->change_mtu = nv_change_mtu; | 2029 | dev->change_mtu = nv_change_mtu; |
| 1964 | dev->set_multicast_list = nv_set_multicast; | 2030 | dev->set_multicast_list = nv_set_multicast; |
| 2031 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
| 2032 | dev->poll_controller = nv_poll_controller; | ||
| 2033 | #endif | ||
| 1965 | SET_ETHTOOL_OPS(dev, &ops); | 2034 | SET_ETHTOOL_OPS(dev, &ops); |
| 1966 | dev->tx_timeout = nv_tx_timeout; | 2035 | dev->tx_timeout = nv_tx_timeout; |
| 1967 | dev->watchdog_timeo = NV_WATCHDOG_TIMEO; | 2036 | dev->watchdog_timeo = NV_WATCHDOG_TIMEO; |
