aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/via-velocity.c
diff options
context:
space:
mode:
authorSimon Kagstrom <simon.kagstrom@netinsight.net>2009-11-25 17:10:12 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-26 18:51:10 -0500
commit6dfc4b95b29d89dbdb45de04b1b1ff493ec8016d (patch)
tree3dd3b5bf678d066db0fd28368dc38d423d44f483 /drivers/net/via-velocity.c
parentda95b2d422b6eb2b76789bbdbfafb7e07c493e7a (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.c160
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 */
1255static 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 */
1280static 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, &regs->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, &regs->ISRCTL);
1295 } else
1296 writew(ISRCTL_TSUPDIS, &regs->ISRCTL);
1297
1298 /* Set Rx Interrupt Suppression Threshold */
1299 writeb(CAMCR_PS1, &regs->CAMCR);
1300 if (rx_intsup != 0) {
1301 vptr->int_mask &= ~ISR_PRXI;
1302 writew(rx_intsup, &regs->ISRCTL);
1303 } else
1304 writew(ISRCTL_RSUPDIS, &regs->ISRCTL);
1305
1306 /* Select page to interrupt hold timer */
1307 writeb(0, &regs->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, &regs->RDBaseLo); 1397 writel(vptr->rx.pool_dma, &regs->RDBaseLo);
1338 writew(vptr->options.numrx - 1, &regs->RDCSize); 1398 writew(vptr->options.numrx - 1, &regs->RDCSize);
@@ -1789,6 +1849,8 @@ static void velocity_error(struct velocity_info *vptr, int status)
1789 BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG); 1849 BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
1790 else 1850 else
1791 BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG); 1851 BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->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
3264static 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
3285static 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
3307static 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
3321static 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
3202static const struct ethtool_ops velocity_ethtool_ops = { 3358static 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};