diff mbox

[4/6] e1000: Fixing the received/transmitted octets' counters

Message ID 1445154799-31083-5-git-send-email-leonid.bloch@ravellosystems.com
State New
Headers show

Commit Message

Leonid Bloch Oct. 18, 2015, 7:53 a.m. UTC
Previously, the lower parts of these counters (TORL, TOTL) were
resetting after reaching their maximal values, and since the continuation
of counting in the higher parts (TORH, TOTH) was triggered by an
overflow event of the lower parts, the count was not correct.

Additionally, TORH and TOTH were counting the corresponding frames, and
not the octets, as they supposed to do.

Additionally, these 64-bit registers did not stick at their maximal
values when (and if) they reached them.

This fix resolves all the issues mentioned above, and makes the octet
counters behave according to Intel's specs.

Signed-off-by: Leonid Bloch <leonid.bloch@ravellosystems.com>
Signed-off-by: Dmitry Fleytman <dmitry.fleytman@ravellosystems.com>
---
 hw/net/e1000.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

Comments

Jason Wang Oct. 20, 2015, 6:16 a.m. UTC | #1
On 10/18/2015 03:53 PM, Leonid Bloch wrote:
> Previously, the lower parts of these counters (TORL, TOTL) were
> resetting after reaching their maximal values, and since the continuation
> of counting in the higher parts (TORH, TOTH) was triggered by an
> overflow event of the lower parts, the count was not correct.
>
> Additionally, TORH and TOTH were counting the corresponding frames, and
> not the octets, as they supposed to do.
>
> Additionally, these 64-bit registers did not stick at their maximal
> values when (and if) they reached them.
>
> This fix resolves all the issues mentioned above, and makes the octet
> counters behave according to Intel's specs.
>
> Signed-off-by: Leonid Bloch <leonid.bloch@ravellosystems.com>
> Signed-off-by: Dmitry Fleytman <dmitry.fleytman@ravellosystems.com>
> ---
>  hw/net/e1000.c | 34 ++++++++++++++++++++++++++--------
>  1 file changed, 26 insertions(+), 8 deletions(-)
>
> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
> index 5530285..7f977b6 100644
> --- a/hw/net/e1000.c
> +++ b/hw/net/e1000.c
> @@ -583,6 +583,28 @@ inc_reg_if_not_full(E1000State *s, int index)
>      }
>  }
>  
> +static void
> +grow_8reg_if_not_full(E1000State *s, int index, int size)
> +{
> +    uint32_t lo = s->mac_reg[index];
> +    uint32_t hi = s->mac_reg[index+1];
> +
> +    if (lo == 0xffffffff) {
> +        if ((hi += size) > s->mac_reg[index+1]) {
> +            s->mac_reg[index+1] = hi;
> +        } else if (s->mac_reg[index+1] != 0xffffffff) {
> +            s->mac_reg[index+1] = 0xffffffff;
> +        }
> +    } else {
> +        if (((lo += size) < s->mac_reg[index])
> +            && (s->mac_reg[index] = 0xffffffff)) {  /* setting low to full */
> +            s->mac_reg[index+1] += ++lo;
> +        } else {
> +            s->mac_reg[index] = lo;
> +        }
> +    }
> +}

How about something easier:

uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] <<32;
if (sum + size < sum) {
    sum = 0xffffffffffffffff;
} else {
    sum += size;
}
s->max_reg[index] = sum;
s->max_reg[index+1] = sum >> 32;

> +
>  static inline int
>  vlan_enabled(E1000State *s)
>  {
> @@ -632,7 +654,7 @@ static void
>  xmit_seg(E1000State *s)
>  {
>      uint16_t len, *sp;
> -    unsigned int frames = s->tx.tso_frames, css, sofar, n;
> +    unsigned int frames = s->tx.tso_frames, css, sofar;
>      struct e1000_tx *tp = &s->tx;
>  
>      if (tp->tse && tp->cptse) {
> @@ -678,10 +700,8 @@ xmit_seg(E1000State *s)
>      } else
>          e1000_send_packet(s, tp->data, tp->size);
>      inc_reg_if_not_full(s, TPT);
> +    grow_8reg_if_not_full(s, TOTL, s->tx.size);
>      s->mac_reg[GPTC] = s->mac_reg[TPT];
> -    n = s->mac_reg[TOTL];
> -    if ((s->mac_reg[TOTL] += s->tx.size) < n)
> -        s->mac_reg[TOTH]++;
>  }
>  
>  static void
> @@ -1096,11 +1116,9 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
>      /* TOR - Total Octets Received:
>       * This register includes bytes received in a packet from the <Destination
>       * Address> field through the <CRC> field, inclusively.
> +     * Always include FCS length (4) in size.
>       */
> -    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
> -    if (n < s->mac_reg[TORL])
> -        s->mac_reg[TORH]++;
> -    s->mac_reg[TORL] = n;
> +    grow_8reg_if_not_full(s, TORL, size+4);
>  
>      n = E1000_ICS_RXT0;
>      if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
Leonid Bloch Oct. 21, 2015, 12:20 p.m. UTC | #2
On Tue, Oct 20, 2015 at 9:16 AM, Jason Wang <jasowang@redhat.com> wrote:
>
>
> On 10/18/2015 03:53 PM, Leonid Bloch wrote:
>> Previously, the lower parts of these counters (TORL, TOTL) were
>> resetting after reaching their maximal values, and since the continuation
>> of counting in the higher parts (TORH, TOTH) was triggered by an
>> overflow event of the lower parts, the count was not correct.
>>
>> Additionally, TORH and TOTH were counting the corresponding frames, and
>> not the octets, as they supposed to do.
>>
>> Additionally, these 64-bit registers did not stick at their maximal
>> values when (and if) they reached them.
>>
>> This fix resolves all the issues mentioned above, and makes the octet
>> counters behave according to Intel's specs.
>>
>> Signed-off-by: Leonid Bloch <leonid.bloch@ravellosystems.com>
>> Signed-off-by: Dmitry Fleytman <dmitry.fleytman@ravellosystems.com>
>> ---
>>  hw/net/e1000.c | 34 ++++++++++++++++++++++++++--------
>>  1 file changed, 26 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
>> index 5530285..7f977b6 100644
>> --- a/hw/net/e1000.c
>> +++ b/hw/net/e1000.c
>> @@ -583,6 +583,28 @@ inc_reg_if_not_full(E1000State *s, int index)
>>      }
>>  }
>>
>> +static void
>> +grow_8reg_if_not_full(E1000State *s, int index, int size)
>> +{
>> +    uint32_t lo = s->mac_reg[index];
>> +    uint32_t hi = s->mac_reg[index+1];
>> +
>> +    if (lo == 0xffffffff) {
>> +        if ((hi += size) > s->mac_reg[index+1]) {
>> +            s->mac_reg[index+1] = hi;
>> +        } else if (s->mac_reg[index+1] != 0xffffffff) {
>> +            s->mac_reg[index+1] = 0xffffffff;
>> +        }
>> +    } else {
>> +        if (((lo += size) < s->mac_reg[index])
>> +            && (s->mac_reg[index] = 0xffffffff)) {  /* setting low to full */
>> +            s->mac_reg[index+1] += ++lo;
>> +        } else {
>> +            s->mac_reg[index] = lo;
>> +        }
>> +    }
>> +}
>
> How about something easier:
>
> uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] <<32;
> if (sum + size < sum) {
>     sum = 0xffffffffffffffff;
> } else {
>     sum += size;
> }
> s->max_reg[index] = sum;
> s->max_reg[index+1] = sum >> 32;

Yes, that is better! Few small changes:

uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32;

if (sum + size < sum) {
    sum = ~0;
} else {
    sum += size;
}
s->mac_reg[index] = sum;
s->mac_reg[index+1] = sum >> 32;

>
>> +
>>  static inline int
>>  vlan_enabled(E1000State *s)
>>  {
>> @@ -632,7 +654,7 @@ static void
>>  xmit_seg(E1000State *s)
>>  {
>>      uint16_t len, *sp;
>> -    unsigned int frames = s->tx.tso_frames, css, sofar, n;
>> +    unsigned int frames = s->tx.tso_frames, css, sofar;
>>      struct e1000_tx *tp = &s->tx;
>>
>>      if (tp->tse && tp->cptse) {
>> @@ -678,10 +700,8 @@ xmit_seg(E1000State *s)
>>      } else
>>          e1000_send_packet(s, tp->data, tp->size);
>>      inc_reg_if_not_full(s, TPT);
>> +    grow_8reg_if_not_full(s, TOTL, s->tx.size);
>>      s->mac_reg[GPTC] = s->mac_reg[TPT];
>> -    n = s->mac_reg[TOTL];
>> -    if ((s->mac_reg[TOTL] += s->tx.size) < n)
>> -        s->mac_reg[TOTH]++;
>>  }
>>
>>  static void
>> @@ -1096,11 +1116,9 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
>>      /* TOR - Total Octets Received:
>>       * This register includes bytes received in a packet from the <Destination
>>       * Address> field through the <CRC> field, inclusively.
>> +     * Always include FCS length (4) in size.
>>       */
>> -    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
>> -    if (n < s->mac_reg[TORL])
>> -        s->mac_reg[TORH]++;
>> -    s->mac_reg[TORL] = n;
>> +    grow_8reg_if_not_full(s, TORL, size+4);
>>
>>      n = E1000_ICS_RXT0;
>>      if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
>
Jason Wang Oct. 22, 2015, 7:20 a.m. UTC | #3
On 10/21/2015 08:20 PM, Leonid Bloch wrote:
> On Tue, Oct 20, 2015 at 9:16 AM, Jason Wang <jasowang@redhat.com> wrote:
>> >
>> >
>> > On 10/18/2015 03:53 PM, Leonid Bloch wrote:
>>> >> Previously, the lower parts of these counters (TORL, TOTL) were
>>> >> resetting after reaching their maximal values, and since the continuation
>>> >> of counting in the higher parts (TORH, TOTH) was triggered by an
>>> >> overflow event of the lower parts, the count was not correct.
>>> >>
>>> >> Additionally, TORH and TOTH were counting the corresponding frames, and
>>> >> not the octets, as they supposed to do.
>>> >>
>>> >> Additionally, these 64-bit registers did not stick at their maximal
>>> >> values when (and if) they reached them.
>>> >>
>>> >> This fix resolves all the issues mentioned above, and makes the octet
>>> >> counters behave according to Intel's specs.
>>> >>
>>> >> Signed-off-by: Leonid Bloch <leonid.bloch@ravellosystems.com>
>>> >> Signed-off-by: Dmitry Fleytman <dmitry.fleytman@ravellosystems.com>
>>> >> ---
>>> >>  hw/net/e1000.c | 34 ++++++++++++++++++++++++++--------
>>> >>  1 file changed, 26 insertions(+), 8 deletions(-)
>>> >>
>>> >> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
>>> >> index 5530285..7f977b6 100644
>>> >> --- a/hw/net/e1000.c
>>> >> +++ b/hw/net/e1000.c
>>> >> @@ -583,6 +583,28 @@ inc_reg_if_not_full(E1000State *s, int index)
>>> >>      }
>>> >>  }
>>> >>
>>> >> +static void
>>> >> +grow_8reg_if_not_full(E1000State *s, int index, int size)
>>> >> +{
>>> >> +    uint32_t lo = s->mac_reg[index];
>>> >> +    uint32_t hi = s->mac_reg[index+1];
>>> >> +
>>> >> +    if (lo == 0xffffffff) {
>>> >> +        if ((hi += size) > s->mac_reg[index+1]) {
>>> >> +            s->mac_reg[index+1] = hi;
>>> >> +        } else if (s->mac_reg[index+1] != 0xffffffff) {
>>> >> +            s->mac_reg[index+1] = 0xffffffff;
>>> >> +        }
>>> >> +    } else {
>>> >> +        if (((lo += size) < s->mac_reg[index])
>>> >> +            && (s->mac_reg[index] = 0xffffffff)) {  /* setting low to full */
>>> >> +            s->mac_reg[index+1] += ++lo;
>>> >> +        } else {
>>> >> +            s->mac_reg[index] = lo;
>>> >> +        }
>>> >> +    }
>>> >> +}
>> >
>> > How about something easier:
>> >
>> > uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] <<32;
>> > if (sum + size < sum) {
>> >     sum = 0xffffffffffffffff;
>> > } else {
>> >     sum += size;
>> > }
>> > s->max_reg[index] = sum;
>> > s->max_reg[index+1] = sum >> 32;
> Yes, that is better! Few small changes:
>
> uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32;
>
> if (sum + size < sum) {
>     sum = ~0;
> } else {
>     sum += size;
> }
> s->mac_reg[index] = sum;
> s->mac_reg[index+1] = sum >> 32;
>
>> >

Looks good to me.
diff mbox

Patch

diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 5530285..7f977b6 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -583,6 +583,28 @@  inc_reg_if_not_full(E1000State *s, int index)
     }
 }
 
+static void
+grow_8reg_if_not_full(E1000State *s, int index, int size)
+{
+    uint32_t lo = s->mac_reg[index];
+    uint32_t hi = s->mac_reg[index+1];
+
+    if (lo == 0xffffffff) {
+        if ((hi += size) > s->mac_reg[index+1]) {
+            s->mac_reg[index+1] = hi;
+        } else if (s->mac_reg[index+1] != 0xffffffff) {
+            s->mac_reg[index+1] = 0xffffffff;
+        }
+    } else {
+        if (((lo += size) < s->mac_reg[index])
+            && (s->mac_reg[index] = 0xffffffff)) {  /* setting low to full */
+            s->mac_reg[index+1] += ++lo;
+        } else {
+            s->mac_reg[index] = lo;
+        }
+    }
+}
+
 static inline int
 vlan_enabled(E1000State *s)
 {
@@ -632,7 +654,7 @@  static void
 xmit_seg(E1000State *s)
 {
     uint16_t len, *sp;
-    unsigned int frames = s->tx.tso_frames, css, sofar, n;
+    unsigned int frames = s->tx.tso_frames, css, sofar;
     struct e1000_tx *tp = &s->tx;
 
     if (tp->tse && tp->cptse) {
@@ -678,10 +700,8 @@  xmit_seg(E1000State *s)
     } else
         e1000_send_packet(s, tp->data, tp->size);
     inc_reg_if_not_full(s, TPT);
+    grow_8reg_if_not_full(s, TOTL, s->tx.size);
     s->mac_reg[GPTC] = s->mac_reg[TPT];
-    n = s->mac_reg[TOTL];
-    if ((s->mac_reg[TOTL] += s->tx.size) < n)
-        s->mac_reg[TOTH]++;
 }
 
 static void
@@ -1096,11 +1116,9 @@  e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
     /* TOR - Total Octets Received:
      * This register includes bytes received in a packet from the <Destination
      * Address> field through the <CRC> field, inclusively.
+     * Always include FCS length (4) in size.
      */
-    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
-    if (n < s->mac_reg[TORL])
-        s->mac_reg[TORH]++;
-    s->mac_reg[TORL] = n;
+    grow_8reg_if_not_full(s, TORL, size+4);
 
     n = E1000_ICS_RXT0;
     if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])