Index: stand/i386/libi386/pxe.c =================================================================== --- stand/i386/libi386/pxe.c +++ stand/i386/libi386/pxe.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -434,14 +435,26 @@ static int pxe_netif_receive(void **pkt) { + static bool data_pending; t_PXENV_UNDI_ISR *isr; char *buf, *ptr, *frame; size_t size, rsize; + buf = NULL; + rsize = 0; isr = bio_alloc(sizeof(*isr)); if (isr == NULL) return (-1); + /* + * We can save ourselves the next two pxe calls because we already know + * we weren't done grabbing everything. + */ + if (data_pending) { + data_pending = false; + goto nextbuf; + } + bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_START; pxe_call(PXENV_UNDI_ISR, isr); @@ -458,47 +471,43 @@ return (-1); } - while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) { - /* - * Wait till transmit is done. - */ - bzero(isr, sizeof(*isr)); - isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - pxe_call(PXENV_UNDI_ISR, isr); - if (isr->Status != 0 || - isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { - bio_free(isr, sizeof(*isr)); - return (-1); - } - } - - while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) { - if (isr->Status != 0 || - isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { - bio_free(isr, sizeof(*isr)); - return (-1); + while (isr->Status == 0 && + isr->FuncFlag != PXENV_UNDI_ISR_OUT_DONE) { + if (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) + goto nextbuf; + + if (buf == NULL) { + /* + * Grab size from the first frame, + * allocate rx buf + */ + size = isr->FrameLength; + buf = malloc(size + ETHER_ALIGN); + if (buf == NULL) { + bio_free(isr, sizeof(*isr)); + return (-1); + } + ptr = buf + ETHER_ALIGN; } - bzero(isr, sizeof(*isr)); - isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - pxe_call(PXENV_UNDI_ISR, isr); - } - - size = isr->FrameLength; - buf = malloc(size + ETHER_ALIGN); - if (buf == NULL) { - bio_free(isr, sizeof(*isr)); - return (-1); - } - ptr = buf + ETHER_ALIGN; - rsize = 0; - while (rsize < size) { frame = (char *)((uintptr_t)isr->Frame.segment << 4); frame += isr->Frame.offset; bcopy(PTOV(frame), ptr, isr->BufferLength); ptr += isr->BufferLength; rsize += isr->BufferLength; + /* + * We may have caught an additional frame, just drop it on the + * floor for our next call into here. It'd perhaps be nice to + * be able to chain packets, but our network stack in libsa is + * just not ready for that. + */ + if (rsize >= size) { + data_pending = true; + break; + } + +nextbuf: bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; pxe_call(PXENV_UNDI_ISR, isr); @@ -507,11 +516,6 @@ free(buf); return (-1); } - - /* Did we got another update? */ - if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) - continue; - break; } *pkt = buf;