diff options
author | Simon Kagstrom <simon.kagstrom@netinsight.net> | 2009-11-25 17:10:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-26 18:51:10 -0500 |
commit | 6dfc4b95b29d89dbdb45de04b1b1ff493ec8016d (patch) | |
tree | 3dd3b5bf678d066db0fd28368dc38d423d44f483 | |
parent | da95b2d422b6eb2b76789bbdbfafb7e07c493e7a (diff) |
via-velocity: Add ethtool interrupt coalescing support
(Partially from the upstream VIA driver). Tweaking the number of
frames-per-interrupt and timer-until-interrupt can reduce the amount of
CPU work quite a lot.
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/via-velocity.c | 160 | ||||
-rw-r--r-- | drivers/net/via-velocity.h | 7 |
2 files changed, 165 insertions, 2 deletions
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 04d3836bfa5d..7c362b242704 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c | |||||
@@ -1246,6 +1246,66 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) | |||||
1246 | } | 1246 | } | ||
1247 | } | 1247 | } | ||
1248 | 1248 | ||||
1249 | /** | ||||
1250 | * setup_queue_timers - Setup interrupt timers | ||||
1251 | * | ||||
1252 | * Setup interrupt frequency during suppression (timeout if the frame | ||||
1253 | * count isn't filled). | ||||
1254 | */ | ||||
1255 | static void setup_queue_timers(struct velocity_info *vptr) | ||||
1256 | { | ||||
1257 | /* Only for newer revisions */ | ||||
1258 | if (vptr->rev_id >= REV_ID_VT3216_A0) { | ||||
1259 | u8 txqueue_timer = 0; | ||||
1260 | u8 rxqueue_timer = 0; | ||||
1261 | |||||
1262 | if (vptr->mii_status & (VELOCITY_SPEED_1000 | | ||||
1263 | VELOCITY_SPEED_100)) { | ||||
1264 | txqueue_timer = vptr->options.txqueue_timer; | ||||
1265 | rxqueue_timer = vptr->options.rxqueue_timer; | ||||
1266 | } | ||||
1267 | |||||
1268 | writeb(txqueue_timer, &vptr->mac_regs->TQETMR); | ||||
1269 | writeb(rxqueue_timer, &vptr->mac_regs->RQETMR); | ||||
1270 | } | ||||
1271 | } | ||||
1272 | /** | ||||
1273 | * setup_adaptive_interrupts - Setup interrupt suppression | ||||
1274 | * | ||||
1275 | * @vptr velocity adapter | ||||
1276 | * | ||||
1277 | * The velocity is able to suppress interrupt during high interrupt load. | ||||
1278 | * This function turns on that feature. | ||||
1279 | */ | ||||
1280 | static void setup_adaptive_interrupts(struct velocity_info *vptr) | ||||
1281 | { | ||||
1282 | struct mac_regs __iomem *regs = vptr->mac_regs; | ||||
1283 | u16 tx_intsup = vptr->options.tx_intsup; | ||||
1284 | u16 rx_intsup = vptr->options.rx_intsup; | ||||
1285 | |||||
1286 | /* Setup default interrupt mask (will be changed below) */ | ||||
1287 | vptr->int_mask = INT_MASK_DEF; | ||||
1288 | |||||
1289 | /* Set Tx Interrupt Suppression Threshold */ | ||||
1290 | writeb(CAMCR_PS0, ®s->CAMCR); | ||||
1291 | if (tx_intsup != 0) { | ||||
1292 | vptr->int_mask &= ~(ISR_PTXI | ISR_PTX0I | ISR_PTX1I | | ||||
1293 | ISR_PTX2I | ISR_PTX3I); | ||||
1294 | writew(tx_intsup, ®s->ISRCTL); | ||||
1295 | } else | ||||
1296 | writew(ISRCTL_TSUPDIS, ®s->ISRCTL); | ||||
1297 | |||||
1298 | /* Set Rx Interrupt Suppression Threshold */ | ||||
1299 | writeb(CAMCR_PS1, ®s->CAMCR); | ||||
1300 | if (rx_intsup != 0) { | ||||
1301 | vptr->int_mask &= ~ISR_PRXI; | ||||
1302 | writew(rx_intsup, ®s->ISRCTL); | ||||
1303 | } else | ||||
1304 | writew(ISRCTL_RSUPDIS, ®s->ISRCTL); | ||||
1305 | |||||
1306 | /* Select page to interrupt hold timer */ | ||||
1307 | writeb(0, ®s->CAMCR); | ||||
1308 | } | ||||
1249 | 1309 | ||||
1250 | /** | 1310 | /** | ||
1251 | * velocity_init_registers - initialise MAC registers | 1311 | * velocity_init_registers - initialise MAC registers | ||
@@ -1332,7 +1392,7 @@ static void velocity_init_registers(struct velocity_info *vptr, | |||||
1332 | */ | 1392 | */ | ||
1333 | enable_mii_autopoll(regs); | 1393 | enable_mii_autopoll(regs); | ||
1334 | 1394 | ||||
1335 | vptr->int_mask = INT_MASK_DEF; | 1395 | setup_adaptive_interrupts(vptr); | ||
1336 | 1396 | ||||
1337 | writel(vptr->rx.pool_dma, ®s->RDBaseLo); | 1397 | writel(vptr->rx.pool_dma, ®s->RDBaseLo); | ||
1338 | writew(vptr->options.numrx - 1, ®s->RDCSize); | 1398 | writew(vptr->options.numrx - 1, ®s->RDCSize); | ||
@@ -1789,6 +1849,8 @@ static void velocity_error(struct velocity_info *vptr, int status) | |||||
1789 | BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); | 1849 | BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); | ||
1790 | else | 1850 | else | ||
1791 | BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); | 1851 | BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); | ||
1852 | |||||
1853 | setup_queue_timers(vptr); | ||||
1792 | } | 1854 | } | ||
1793 | /* | 1855 | /* | ||
1794 | * Get link status from PHYSR0 | 1856 | * Get link status from PHYSR0 | ||
@@ -3199,6 +3261,100 @@ static void velocity_set_msglevel(struct net_device *dev, u32 value) | |||||
3199 | msglevel = value; | 3261 | msglevel = value; | ||
3200 | } | 3262 | } | ||
3201 | 3263 | ||||
3264 | static int get_pending_timer_val(int val) | ||||
3265 | { | ||||
3266 | int mult_bits = val >> 6; | ||||
3267 | int mult = 1; | ||||
3268 | |||||
3269 | switch (mult_bits) | ||||
3270 | { | ||||
3271 | case 1: | ||||
3272 | mult = 4; break; | ||||
3273 | case 2: | ||||
3274 | mult = 16; break; | ||||
3275 | case 3: | ||||
3276 | mult = 64; break; | ||||
3277 | case 0: | ||||
3278 | default: | ||||
3279 | break; | ||||
3280 | } | ||||
3281 | |||||
3282 | return (val & 0x3f) * mult; | ||||
3283 | } | ||||
3284 | |||||
3285 | static void set_pending_timer_val(int *val, u32 us) | ||||
3286 | { | ||||
3287 | u8 mult = 0; | ||||
3288 | u8 shift = 0; | ||||
3289 | |||||
3290 | if (us >= 0x3f) { | ||||
3291 | mult = 1; /* mult with 4 */ | ||||
3292 | shift = 2; | ||||
3293 | } | ||||
3294 | if (us >= 0x3f * 4) { | ||||
3295 | mult = 2; /* mult with 16 */ | ||||
3296 | shift = 4; | ||||
3297 | } | ||||
3298 | if (us >= 0x3f * 16) { | ||||
3299 | mult = 3; /* mult with 64 */ | ||||
3300 | shift = 6; | ||||
3301 | } | ||||
3302 | |||||
3303 | *val = (mult << 6) | ((us >> shift) & 0x3f); | ||||
3304 | } | ||||
3305 | |||||
3306 | |||||
3307 | static int velocity_get_coalesce(struct net_device *dev, | ||||
3308 | struct ethtool_coalesce *ecmd) | ||||
3309 | { | ||||
3310 | struct velocity_info *vptr = netdev_priv(dev); | ||||
3311 | |||||
3312 | ecmd->tx_max_coalesced_frames = vptr->options.tx_intsup; | ||||
3313 | ecmd->rx_max_coalesced_frames = vptr->options.rx_intsup; | ||||
3314 | |||||
3315 | ecmd->rx_coalesce_usecs = get_pending_timer_val(vptr->options.rxqueue_timer); | ||||
3316 | ecmd->tx_coalesce_usecs = get_pending_timer_val(vptr->options.txqueue_timer); | ||||
3317 | |||||
3318 | return 0; | ||||
3319 | } | ||||
3320 | |||||
3321 | static int velocity_set_coalesce(struct net_device *dev, | ||||
3322 | struct ethtool_coalesce *ecmd) | ||||
3323 | { | ||||
3324 | struct velocity_info *vptr = netdev_priv(dev); | ||||
3325 | int max_us = 0x3f * 64; | ||||
3326 | |||||
3327 | /* 6 bits of */ | ||||
3328 | if (ecmd->tx_coalesce_usecs > max_us) | ||||
3329 | return -EINVAL; | ||||
3330 | if (ecmd->rx_coalesce_usecs > max_us) | ||||
3331 | return -EINVAL; | ||||
3332 | |||||
3333 | if (ecmd->tx_max_coalesced_frames > 0xff) | ||||
3334 | return -EINVAL; | ||||
3335 | if (ecmd->rx_max_coalesced_frames > 0xff) | ||||
3336 | return -EINVAL; | ||||
3337 | |||||
3338 | vptr->options.rx_intsup = ecmd->rx_max_coalesced_frames; | ||||
3339 | vptr->options.tx_intsup = ecmd->tx_max_coalesced_frames; | ||||
3340 | |||||
3341 | set_pending_timer_val(&vptr->options.rxqueue_timer, | ||||
3342 | ecmd->rx_coalesce_usecs); | ||||
3343 | set_pending_timer_val(&vptr->options.txqueue_timer, | ||||
3344 | ecmd->tx_coalesce_usecs); | ||||
3345 | |||||
3346 | /* Setup the interrupt suppression and queue timers */ | ||||
3347 | mac_disable_int(vptr->mac_regs); | ||||
3367 | .get_coalesce = velocity_get_coalesce, | ||||
3368 | .set_coalesce = velocity_set_coalesce, | ||||
3211 | .begin = velocity_ethtool_up, | 3369 | .begin = velocity_ethtool_up, | ||
3212 | .complete = velocity_ethtool_down | 3370 | .complete = velocity_ethtool_down | ||
3213 | }; | 3371 | }; | ||
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index ce894ffa7c91..499da64773ee 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h | |||||
@@ -1005,7 +1005,8 @@ struct mac_regs { | |||||
1005 | 1005 | ||||
1006 | volatile __le32 RDBaseLo; /* 0x38 */ | 1006 | volatile __le32 RDBaseLo; /* 0x38 */ | ||
1007 | volatile __le16 RDIdx; /* 0x3C */ | 1007 | volatile __le16 RDIdx; /* 0x3C */ | ||
1008 | volatile __le16 reserved_3E; | 1008 | volatile u8 TQETMR; /* 0x3E, VT3216 and above only */ | ||
1009 | volatile u8 RQETMR; /* 0x3F, VT3216 and above only */ | ||||
1009 | 1010 | ||||
1010 | volatile __le32 TDBaseLo[4]; /* 0x40 */ | 1011 | volatile __le32 TDBaseLo[4]; /* 0x40 */ | ||
1011 | 1012 | ||||
@@ -1491,6 +1492,10 @@ struct velocity_opt { | |||||
1491 | int rx_bandwidth_hi; | 1492 | int rx_bandwidth_hi; | ||
1492 | int rx_bandwidth_lo; | 1493 | int rx_bandwidth_lo; | ||
1493 | int rx_bandwidth_en; | 1494 | int rx_bandwidth_en; | ||
1495 | int rxqueue_timer; | ||||
1496 | int txqueue_timer; | ||||
1497 | int tx_intsup; | ||||
1498 | int rx_intsup; | ||||
1494 | u32 flags; | 1499 | u32 flags; | ||
1495 | }; | 1500 | }; | ||
1496 | 1501 | ||||