diff options
Diffstat (limited to 'drivers/net/mv643xx_eth.c')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 133 |
1 files changed, 103 insertions, 30 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e8fbc0badf7e..c32d623061d9 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -1221,6 +1221,85 @@ static void mib_counters_timer_wrapper(unsigned long _mp) | |||
1221 | } | 1221 | } |
1222 | 1222 | ||
1223 | 1223 | ||
1224 | /* interrupt coalescing *****************************************************/ | ||
1225 | /* | ||
1226 | * Hardware coalescing parameters are set in units of 64 t_clk | ||
1227 | * cycles. I.e.: | ||
1228 | * | ||
1229 | * coal_delay_in_usec = 64000000 * register_value / t_clk_rate | ||
1230 | * | ||
1231 | * register_value = coal_delay_in_usec * t_clk_rate / 64000000 | ||
1232 | * | ||
1233 | * In the ->set*() methods, we round the computed register value | ||
1234 | * to the nearest integer. | ||
1235 | */ | ||
1236 | static unsigned int get_rx_coal(struct mv643xx_eth_private *mp) | ||
1237 | { | ||
1238 | u32 val = rdlp(mp, SDMA_CONFIG); | ||
1239 | u64 temp; | ||
1240 | |||
1241 | if (mp->shared->extended_rx_coal_limit) | ||
1242 | temp = ((val & 0x02000000) >> 10) | ((val & 0x003fff80) >> 7); | ||
1243 | else | ||
1244 | temp = (val & 0x003fff00) >> 8; | ||
1245 | |||
1246 | temp *= 64000000; | ||
1247 | do_div(temp, mp->shared->t_clk); | ||
1248 | |||
1249 | return (unsigned int)temp; | ||
1250 | } | ||
1251 | |||
1252 | static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec) | ||
1253 | { | ||
1254 | u64 temp; | ||
1255 | u32 val; | ||
1256 | |||
1257 | temp = (u64)usec * mp->shared->t_clk; | ||
1258 | temp += 31999999; | ||
1259 | do_div(temp, 64000000); | ||
1260 | |||
1261 | val = rdlp(mp, SDMA_CONFIG); | ||
1262 | if (mp->shared->extended_rx_coal_limit) { | ||
1263 | if (temp > 0xffff) | ||
1264 | temp = 0xffff; | ||
1265 | val &= ~0x023fff80; | ||
1266 | val |= (temp & 0x8000) << 10; | ||
1267 | val |= (temp & 0x7fff) << 7; | ||
1268 | } else { | ||
1269 | if (temp > 0x3fff) | ||
1270 | temp = 0x3fff; | ||
1271 | val &= ~0x003fff00; | ||
1272 | val |= (temp & 0x3fff) << 8; | ||
1273 | } | ||
1274 | wrlp(mp, SDMA_CONFIG, val); | ||
1275 | } | ||
1276 | |||
1277 | static unsigned int get_tx_coal(struct mv643xx_eth_private *mp) | ||
1278 | { | ||
1279 | u64 temp; | ||
1280 | |||
1281 | temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4; | ||
1282 | temp *= 64000000; | ||
1283 | do_div(temp, mp->shared->t_clk); | ||
1284 | |||
1285 | return (unsigned int)temp; | ||
1286 | } | ||
1287 | |||
1288 | static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec) | ||
1289 | { | ||
1290 | u64 temp; | ||
1291 | |||
1292 | temp = (u64)usec * mp->shared->t_clk; | ||
1293 | temp += 31999999; | ||
1294 | do_div(temp, 64000000); | ||
1295 | |||
1296 | if (temp > 0x3fff) | ||
1297 | temp = 0x3fff; | ||
1298 | |||
1299 | wrlp(mp, TX_FIFO_URGENT_THRESHOLD, temp << 4); | ||
1300 | } | ||
1301 | |||
1302 | |||
1224 | /* ethtool ******************************************************************/ | 1303 | /* ethtool ******************************************************************/ |
1225 | struct mv643xx_eth_stats { | 1304 | struct mv643xx_eth_stats { |
1226 | char stat_string[ETH_GSTRING_LEN]; | 1305 | char stat_string[ETH_GSTRING_LEN]; |
@@ -1384,6 +1463,28 @@ static u32 mv643xx_eth_get_link(struct net_device *dev) | |||
1384 | return !!netif_carrier_ok(dev); | 1463 | return !!netif_carrier_ok(dev); |
1385 | } | 1464 | } |
1386 | 1465 | ||
1466 | static int | ||
1467 | mv643xx_eth_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) | ||
1468 | { | ||
1469 | struct mv643xx_eth_private *mp = netdev_priv(dev); | ||
1470 | |||
1471 | ec->rx_coalesce_usecs = get_rx_coal(mp); | ||
1472 | ec->tx_coalesce_usecs = get_tx_coal(mp); | ||
1473 | |||
1474 | return 0; | ||
1475 | } | ||
1476 | |||
1477 | static int | ||
1478 | mv643xx_eth_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) | ||
1479 | { | ||
1480 | struct mv643xx_eth_private *mp = netdev_priv(dev); | ||
1481 | |||
1482 | set_rx_coal(mp, ec->rx_coalesce_usecs); | ||
1483 | set_tx_coal(mp, ec->tx_coalesce_usecs); | ||
1484 | |||
1485 | return 0; | ||
1486 | } | ||
1487 | |||
1387 | static void mv643xx_eth_get_strings(struct net_device *dev, | 1488 | static void mv643xx_eth_get_strings(struct net_device *dev, |
1388 | uint32_t stringset, uint8_t *data) | 1489 | uint32_t stringset, uint8_t *data) |
1389 | { | 1490 | { |
@@ -1438,6 +1539,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { | |||
1438 | .get_drvinfo = mv643xx_eth_get_drvinfo, | 1539 | .get_drvinfo = mv643xx_eth_get_drvinfo, |
1439 | .nway_reset = mv643xx_eth_nway_reset, | 1540 | .nway_reset = mv643xx_eth_nway_reset, |
1440 | .get_link = mv643xx_eth_get_link, | 1541 | .get_link = mv643xx_eth_get_link, |
1542 | .get_coalesce = mv643xx_eth_get_coalesce, | ||
1543 | .set_coalesce = mv643xx_eth_set_coalesce, | ||
1441 | .set_sg = ethtool_op_set_sg, | 1544 | .set_sg = ethtool_op_set_sg, |
1442 | .get_strings = mv643xx_eth_get_strings, | 1545 | .get_strings = mv643xx_eth_get_strings, |
1443 | .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, | 1546 | .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, |
@@ -2053,36 +2156,6 @@ static void port_start(struct mv643xx_eth_private *mp) | |||
2053 | } | 2156 | } |
2054 | } | 2157 | } |
2055 | 2158 | ||
2056 | static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) | ||
2057 | { | ||
2058 | unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; | ||
2059 | u32 val; | ||
2060 | |||
2061 | val = rdlp(mp, SDMA_CONFIG); | ||
2062 | if (mp->shared->extended_rx_coal_limit) { | ||
2063 | if (coal > 0xffff) | ||
2064 | coal = 0xffff; | ||
2065 | val &= ~0x023fff80; | ||
2066 | val |= (coal & 0x8000) << 10; | ||
2067 | val |= (coal & 0x7fff) << 7; | ||
2068 | } else { | ||
2069 | if (coal > 0x3fff) | ||
2070 | coal = 0x3fff; | ||
2071 | val &= ~0x003fff00; | ||
2072 | val |= (coal & 0x3fff) << 8; | ||
2073 | } | ||
2074 | wrlp(mp, SDMA_CONFIG, val); | ||
2075 | } | ||
2076 | |||
2077 | static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) | ||
2078 | { | ||
2079 | unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; | ||
2080 | |||
2081 | if (coal > 0x3fff) | ||
2082 | coal = 0x3fff; | ||
2083 | wrlp(mp, TX_FIFO_URGENT_THRESHOLD, (coal & 0x3fff) << 4); | ||
2084 | } | ||
2085 | |||
2086 | static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) | 2159 | static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) |
2087 | { | 2160 | { |
2088 | int skb_size; | 2161 | int skb_size; |