start_xmit(E1000State *s)

{

    PCIDevice *d = PCI_DEVICE(s);

    dma_addr_t base;

    struct e1000_tx_desc desc;

    uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;



    if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {

        DBGOUT(TX, "tx disabled\n");

        return;

    }



    while (s->mac_reg[TDH] != s->mac_reg[TDT]) {

        base = tx_desc_base(s) +

               sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];

        pci_dma_read(d, base, &desc, sizeof(desc));



        DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],

               (void *)(intptr_t)desc.buffer_addr, desc.lower.data,

               desc.upper.data);



        process_tx_desc(s, &desc);

        cause |= txdesc_writeback(s, base, &desc);



        if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])

            s->mac_reg[TDH] = 0;

        /*

         * the following could happen only if guest sw assigns

         * bogus values to TDT/TDLEN.

         * there's nothing too intelligent we could do about this.

         */

        if (s->mac_reg[TDH] == tdh_start) {

            DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",

                   tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);

            break;

        }

    }

    set_ics(s, 0, cause);

}
