Message ID | 20121127224605.GA10228@electric-eye.fr.zoreil.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On 27/11/2012 23:46, Francois Romieu wrote: > David Laight <David.Laight@ACULAB.COM> : >> Stéphane ANCELOT <sancelot@free.fr> : >>> I had problem with it, my application sends a frame that is immediately >>> transmitted back by some slaves, there was abnormally 100us lost >>> between the send and receive call. >>> >>> Finally I found it was coming from the following register setup in the >>> driver : >>> >>> RTL_W16(IntrMitigate, 0x5151); >>> >>> Can you give me some details about it, since I do not have the RTL8169 >>> programming guide. >> That sounds like an 'interrupt mitigation' setting - which will cause >> RX interrupts to be delayed a short time in order to reduce the >> interrupt load on the kernel. >> >> There is usually an 'ethtool' setting to disable interrupt mitigation. > Something like the patch below against net-next could help once I will > have tested it. > > I completely guessed the Tx usec scale factor at gigabit speed (125 us, > 100 us, disabled, who knows ?) and I have no idea which specific chipsets > it should work with. using 0x5151 value at 100mb FDX, I know it introduced exactly 100us delay (Tx+Rx). > Hayes, may I expect some hindsight regarding: > 1 - the availability of the IntrMitigate (0xe2) register through the > 8169, 8168 and 810x line of chipsets > 2 - the Tx timer unit at gigabit speed > > It would save me some time.* Hayes, it would have spared myself a lot of time ;-) Have a look at what is driving this r8169 component : http://www.youtube.com/watch?v=wj30CeAFwuk&feature=plcp A question to nic components developers : I do not understand what competitive advantage keeping these things like a secret.... These things are mostly boring for people and oem like myself at Numalliance. Regards, Stephane Ancelot > diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c > index 248f883..2623b73 100644 > --- a/drivers/net/ethernet/realtek/r8169.c > +++ b/drivers/net/ethernet/realtek/r8169.c > @@ -349,6 +349,12 @@ enum rtl_registers { > RxMaxSize = 0xda, > CPlusCmd = 0xe0, > IntrMitigate = 0xe2, > + > +#define RTL_COALESCE_MASK 0x0f > +#define RTL_COALESCE_SHIFT 4 > +#define RTL_COALESCE_T_MAX (RTL_COALESCE_MASK) > +#define RTL_COALESCE_FRAME_MAX (RTL_COALESCE_MASK << 2) > + > RxDescAddrLow = 0xe4, > RxDescAddrHigh = 0xe8, > EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */ > @@ -1997,10 +2003,121 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) > } > } > > +static struct rtl_coalesce_scale { > + u32 speed; > + /* Rx / Tx */ > + u16 usecs[2]; > +} rtl_coalesce_info[] = { > + { .speed = SPEED_10, .usecs = { 8000, 10000 } }, > + { .speed = SPEED_100, .usecs = { 1000, 1000 } }, > + { .speed = SPEED_1000, .usecs = { 125, 125 } } > +}; > + > +static struct rtl_coalesce_scale *rtl_coalesce_scale(struct net_device *dev) > +{ > + struct ethtool_cmd ecmd; > + int rc, i; > + > + rc = rtl8169_get_settings(dev, &ecmd); > + if (rc < 0) > + return ERR_PTR(rc); > + > + for (i = 0; i < ARRAY_SIZE(rtl_coalesce_info); i++) { > + if (ethtool_cmd_speed(&ecmd) == rtl_coalesce_info[i].speed) > + return rtl_coalesce_info + i; > + } > + > + return ERR_PTR(-EINVAL); > +} > + > +static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) > +{ > + struct rtl8169_private *tp = netdev_priv(dev); > + void __iomem *ioaddr = tp->mmio_addr; > + struct rtl_coalesce_scale *scale; > + struct { > + u32 *max_frames; > + u32 *usecs; > + } coal_settings [] = { > + { &ec->rx_max_coalesced_frames, &ec->rx_coalesce_usecs }, > + { &ec->tx_max_coalesced_frames, &ec->tx_coalesce_usecs } > + }, *p = coal_settings; > + int i; > + u16 w; > + > + memset(ec, 0, sizeof(*ec)); > + > + for (w = RTL_R16(IntrMitigate); w; w >>= RTL_COALESCE_SHIFT, p++) { > + *p->max_frames = (w & RTL_COALESCE_MASK) << 2; > + w >>= RTL_COALESCE_SHIFT; > + *p->usecs = w & RTL_COALESCE_MASK; > + } > + > + /* Except for null parameeters, the meaning of coalescing parameters > + * depends on the link speed. > + */ > + scale = rtl_coalesce_scale(dev); > + if (PTR_ERR(scale) && (p != coal_settings)) > + return PTR_ERR(scale); > + > + for (i = 0; i < 2; i++) { > + p = coal_settings + i; > + *p->usecs *= scale->usecs[i]; > + if (!*p->usecs && !*p->max_frames) > + *p->max_frames = 1; > + } > + > + return 0; > +} > + > +static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) > +{ > + struct rtl8169_private *tp = netdev_priv(dev); > + void __iomem *ioaddr = tp->mmio_addr; > + struct rtl_coalesce_scale *scale; > + struct { > + u32 frames; > + u32 usecs; > + } coal_settings [] = { > + { ec->rx_max_coalesced_frames, ec->rx_coalesce_usecs }, > + { ec->tx_max_coalesced_frames, ec->tx_coalesce_usecs } > + }, *p = coal_settings; > + int i, rc; > + u16 w = 0; > + > + scale = rtl_coalesce_scale(dev); > + rc = PTR_ERR(scale); > + > + for (i = 0; i < 2; i++) { > + u32 units; > + > + if (!p->usecs && p->frames == 1) > + continue; > + if (rc < 0) > + goto out; > + > + units = p->usecs / scale->usecs[i]; > + if (units > RTL_COALESCE_T_MAX || p->usecs % scale->usecs[i] || > + p->frames > RTL_COALESCE_FRAME_MAX || p->frames % 4) > + return -EINVAL; > + > + w <<= RTL_COALESCE_SHIFT; > + w |= units; > + w <<= RTL_COALESCE_SHIFT; > + w |= p->frames >> 2; > + } > + > + RTL_W16(IntrMitigate, swab16(w)); > +out: > + return rc; > +} > + > static const struct ethtool_ops rtl8169_ethtool_ops = { > .get_drvinfo = rtl8169_get_drvinfo, > .get_regs_len = rtl8169_get_regs_len, > .get_link = ethtool_op_get_link, > + .get_coalesce = rtl_get_coalesce, > + .set_coalesce = rtl_set_coalesce, > .get_settings = rtl8169_get_settings, > .set_settings = rtl8169_set_settings, > .get_msglevel = rtl8169_get_msglevel, -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Francois Romieu [mailto:romieu@fr.zoreil.com] [...] > Something like the patch below against net-next could help once I will > have tested it. > > I completely guessed the Tx usec scale factor at gigabit > speed (125 us, > 100 us, disabled, who knows ?) and I have no idea which > specific chipsets > it should work with. > > Hayes, may I expect some hindsight regarding: > 1 - the availability of the IntrMitigate (0xe2) register through the > 8169, 8168 and 810x line of chipsets 8169, 8168, and 8136(810x) serial chipsets support it. > 2 - the Tx timer unit at gigabit speed The unit of the timer depneds on both the speed and the setting of CPlusCmd (0xe0) bit 1 and bit 0. For 8169 bit[1:0] \ speed 1000M 100M 10M 0 0 320ns 2.56us 40.96us 0 1 2.56us 20.48us 327.7us 1 0 5.12us 40.96us 655.4us 1 1 10.24us 81.92us 1.31ms For the other bit[1:0] \ speed 1000M 100M 10M 0 0 5us 2.56us 40.96us 0 1 40us 20.48us 327.7us 1 0 80us 40.96us 655.4us 1 1 160us 81.92us 1.31ms Best Regards, Hayes -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 248f883..2623b73 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -349,6 +349,12 @@ enum rtl_registers { RxMaxSize = 0xda, CPlusCmd = 0xe0, IntrMitigate = 0xe2, + +#define RTL_COALESCE_MASK 0x0f +#define RTL_COALESCE_SHIFT 4 +#define RTL_COALESCE_T_MAX (RTL_COALESCE_MASK) +#define RTL_COALESCE_FRAME_MAX (RTL_COALESCE_MASK << 2) + RxDescAddrLow = 0xe4, RxDescAddrHigh = 0xe8, EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */ @@ -1997,10 +2003,121 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } +static struct rtl_coalesce_scale { + u32 speed; + /* Rx / Tx */ + u16 usecs[2]; +} rtl_coalesce_info[] = { + { .speed = SPEED_10, .usecs = { 8000, 10000 } }, + { .speed = SPEED_100, .usecs = { 1000, 1000 } }, + { .speed = SPEED_1000, .usecs = { 125, 125 } } +}; + +static struct rtl_coalesce_scale *rtl_coalesce_scale(struct net_device *dev) +{ + struct ethtool_cmd ecmd; + int rc, i; + + rc = rtl8169_get_settings(dev, &ecmd); + if (rc < 0) + return ERR_PTR(rc); + + for (i = 0; i < ARRAY_SIZE(rtl_coalesce_info); i++) { + if (ethtool_cmd_speed(&ecmd) == rtl_coalesce_info[i].speed) + return rtl_coalesce_info + i; + } + + return ERR_PTR(-EINVAL); +} + +static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct rtl_coalesce_scale *scale; + struct { + u32 *max_frames; + u32 *usecs; + } coal_settings [] = { + { &ec->rx_max_coalesced_frames, &ec->rx_coalesce_usecs }, + { &ec->tx_max_coalesced_frames, &ec->tx_coalesce_usecs } + }, *p = coal_settings; + int i; + u16 w; + + memset(ec, 0, sizeof(*ec)); + + for (w = RTL_R16(IntrMitigate); w; w >>= RTL_COALESCE_SHIFT, p++) { + *p->max_frames = (w & RTL_COALESCE_MASK) << 2; + w >>= RTL_COALESCE_SHIFT; + *p->usecs = w & RTL_COALESCE_MASK; + } + + /* Except for null parameeters, the meaning of coalescing parameters + * depends on the link speed. + */ + scale = rtl_coalesce_scale(dev); + if (PTR_ERR(scale) && (p != coal_settings)) + return PTR_ERR(scale); + + for (i = 0; i < 2; i++) { + p = coal_settings + i; + *p->usecs *= scale->usecs[i]; + if (!*p->usecs && !*p->max_frames) + *p->max_frames = 1; + } + + return 0; +} + +static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct rtl_coalesce_scale *scale; + struct { + u32 frames; + u32 usecs; + } coal_settings [] = { + { ec->rx_max_coalesced_frames, ec->rx_coalesce_usecs }, + { ec->tx_max_coalesced_frames, ec->tx_coalesce_usecs } + }, *p = coal_settings; + int i, rc; + u16 w = 0; + + scale = rtl_coalesce_scale(dev); + rc = PTR_ERR(scale); + + for (i = 0; i < 2; i++) { + u32 units; + + if (!p->usecs && p->frames == 1) + continue; + if (rc < 0) + goto out; + + units = p->usecs / scale->usecs[i]; + if (units > RTL_COALESCE_T_MAX || p->usecs % scale->usecs[i] || + p->frames > RTL_COALESCE_FRAME_MAX || p->frames % 4) + return -EINVAL; + + w <<= RTL_COALESCE_SHIFT; + w |= units; + w <<= RTL_COALESCE_SHIFT; + w |= p->frames >> 2; + } + + RTL_W16(IntrMitigate, swab16(w)); +out: + return rc; +} + static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, .get_link = ethtool_op_get_link, + .get_coalesce = rtl_get_coalesce, + .set_coalesce = rtl_set_coalesce, .get_settings = rtl8169_get_settings, .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel,