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 /drivers/net/via-velocity.c | |
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>
Diffstat (limited to 'drivers/net/via-velocity.c')
-rw-r--r-- | drivers/net/via-velocity.c | 160 |
1 files changed, 159 insertions, 1 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); | ||
3348 | setup_adaptive_interrupts(vptr); | ||
3349 | setup_queue_timers(vptr); | ||
3350 | |||
3351 | mac_write_int_mask(vptr->int_mask, vptr->mac_regs); | ||
3352 | mac_clear_isr(vptr->mac_regs); | ||
3353 | mac_enable_int(vptr->mac_regs); | ||
3354 | |||
3355 | return 0; | ||
3356 | } | ||
3357 | |||
3202 | static const struct ethtool_ops velocity_ethtool_ops = { | 3358 | static const struct ethtool_ops velocity_ethtool_ops = { |
3203 | .get_settings = velocity_get_settings, | 3359 | .get_settings = velocity_get_settings, |
3204 | .set_settings = velocity_set_settings, | 3360 | .set_settings = velocity_set_settings, |
@@ -3208,6 +3364,8 @@ static const struct ethtool_ops velocity_ethtool_ops = { | |||
3208 | .get_msglevel = velocity_get_msglevel, | 3364 | .get_msglevel = velocity_get_msglevel, |
3209 | .set_msglevel = velocity_set_msglevel, | 3365 | .set_msglevel = velocity_set_msglevel, |
3210 | .get_link = velocity_get_link, | 3366 | .get_link = velocity_get_link, |
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 | }; |