On Fri, 7 Nov 2025 at 03:50, Jason Wang <[email protected]> wrote:
>
> On Tue, Nov 4, 2025 at 1:59 AM Peter Maydell <[email protected]> wrote:
> >
> >      do {
> > +        /*
> > +         * Loop processing descriptors while we have packet data to
> > +         * DMA to the guest.  desc_offset tracks how much data we have
> > +         * sent to the guest in total over all descriptors, and goes
> > +         * from 0 up to total_size (the size of everything to send to
> > +         * the guest including possible trailing 4 bytes of CRC data).
> > +         */
> >          hwaddr ba[MAX_PS_BUFFERS];
> >          E1000EBAState bastate = { { 0 } };
> >          bool is_last = false;
> > @@ -1512,23 +1519,27 @@ e1000e_write_packet_to_guest(E1000ECore *core, 
> > struct NetRxPkt *pkt,
> >          e1000e_read_rx_descr(core, &desc, ba);
> >
> >          if (ba[0]) {
> > -            size_t desc_size = total_size - desc_offset;
> > -
> > -            if (desc_size > core->rx_desc_buf_size) {
> > -                desc_size = core->rx_desc_buf_size;
> > -            }
> > +            /* Total amount of data DMA'd to the guest in this iteration */
> > +            size_t desc_size = 0;
> > +            /*
> > +             * Total space available in this descriptor (we will update
> > +             * this as we use it up)
> > +             */
> > +            size_t rx_desc_buf_size = core->rx_desc_buf_size;
> >
> >              if (desc_offset < size) {
> > -                static const uint32_t fcs_pad;
> >                  size_t iov_copy;
> > +                /* Amount of data to copy from the incoming packet */
> >                  size_t copy_size = size - desc_offset;
> > -                if (copy_size > core->rx_desc_buf_size) {
> > -                    copy_size = core->rx_desc_buf_size;
> > -                }
> >
> >                  /* For PS mode copy the packet header first */
> >                  if (do_ps) {
> >                      if (is_first) {
> > +                        /*
> > +                         * e1000e_do_ps() guarantees that buffer 0 has 
> > enough
> > +                         * space for the header; otherwise we will not 
> > split
> > +                         * the packet (i.e. do_ps is false).
> > +                         */
> >                          size_t ps_hdr_copied = 0;
> >                          do {
> >                              iov_copy = MIN(ps_hdr_len - ps_hdr_copied,
> > @@ -1550,14 +1561,26 @@ e1000e_write_packet_to_guest(E1000ECore *core, 
> > struct NetRxPkt *pkt,
> >                          } while (ps_hdr_copied < ps_hdr_len);
> >
> >                          is_first = false;
> > +                        desc_size += ps_hdr_len;
> >                      } else {
> >                          /* Leave buffer 0 of each descriptor except first 
> > */
> >                          /* empty as per spec 7.1.5.1                      
> > */
> >                          e1000e_write_hdr_frag_to_rx_buffers(core, ba, 
> > &bastate,
> >                                                              NULL, 0);
> >                      }
> > +                    rx_desc_buf_size -= core->rxbuf_sizes[0];
> >                  }
> >
> > +                /*
> > +                 * Clamp the amount of packet data we copy into what will 
> > fit
> > +                 * into the remaining buffers in the descriptor.
> > +                 */
> > +                if (copy_size > rx_desc_buf_size) {
> > +                    copy_size = rx_desc_buf_size;
> > +                }
> > +                desc_size += copy_size;
> > +                rx_desc_buf_size -= copy_size;
> > +
> >                  /* Copy packet payload */
> >                  while (copy_size) {
> >                      iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
> > @@ -1574,12 +1597,22 @@ e1000e_write_packet_to_guest(E1000ECore *core, 
> > struct NetRxPkt *pkt,
> >                          iov_ofs = 0;
> >                      }
> >                  }
> > +            }
> >
> > -                if (desc_offset + desc_size >= total_size) {
> > -                    /* Simulate FCS checksum presence in the last 
> > descriptor */
> > -                    e1000e_write_payload_frag_to_rx_buffers(core, ba, 
> > &bastate,
> > -                          (const char *) &fcs_pad, 
> > e1000x_fcs_len(core->mac));
> > -                }
> > +            if (rx_desc_buf_size &&
> > +                desc_offset >= size && desc_offset < total_size) {
> > +                /*
> > +                 * We are in the last 4 bytes corresponding to the FCS 
> > checksum.
> > +                 * We only ever write zeroes here (unlike the hardware).
> > +                 */
> > +                static const uint32_t fcs_pad;
> > +                /* Amount of space for the trailing checksum */
> > +                size_t fcs_len = MIN(rx_desc_buf_size,
> > +                                     total_size - desc_offset);
> > +                e1000e_write_payload_frag_to_rx_buffers(core, ba, &bastate,
> > +                                                        (const char 
> > *)&fcs_pad,
> > +                                                        fcs_len);
> > +                desc_size += fcs_len;
> >              }
> >              desc_offset += desc_size;
>
> This should be done before the if (rx_desc_bufs_size && ... ?

No. That if() block deals with adding (possibly part of) the 4
checksum bytes. Those are part of the total data we DMA to
the guest, and so the if() block adds fcs_len to desc_size,
and those extra bytes need to be added to desc_offset.

> >              if (desc_offset >= total_size) {

Otherwise conditions like this and the loop termination condition
would not fire, because desc_offset would not get up to total_size.

thanks
-- PMM

Reply via email to