Page MenuHomeFreeBSD

D31512.id94179.diff
No OneTemporary

D31512.id94179.diff

Index: stand/i386/libi386/pxe.c
===================================================================
--- stand/i386/libi386/pxe.c
+++ stand/i386/libi386/pxe.c
@@ -30,6 +30,8 @@
__FBSDID("$FreeBSD$");
#include <stand.h>
+#include <errno.h>
+#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
@@ -432,91 +434,133 @@
}
static int
-pxe_netif_receive(void **pkt)
+pxe_netif_receive_isr(t_PXENV_UNDI_ISR *isr, void **pkt, ssize_t *retsize)
{
- t_PXENV_UNDI_ISR *isr;
+ static bool data_pending;
char *buf, *ptr, *frame;
size_t size, rsize;
- isr = bio_alloc(sizeof(*isr));
- if (isr == NULL)
- return (-1);
+ buf = NULL;
+ size = rsize = 0;
+
+ /*
+ * 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;
+ }
+ /*
+ * We explicitly don't check for OURS/NOT_OURS as a result of START;
+ * it's been reported that some cards are known to mishandle these.
+ */
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_START;
pxe_call(PXENV_UNDI_ISR, isr);
- if (isr->Status != 0) {
- bio_free(isr, sizeof(*isr));
- return (-1);
- }
+ /* We could translate Status... */
+ if (isr->Status != 0)
+ return (ENXIO);
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
pxe_call(PXENV_UNDI_ISR, isr);
- if (isr->Status != 0) {
- bio_free(isr, sizeof(*isr));
- return (-1);
- }
-
- while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
+ if (isr->Status != 0)
+ return (ENXIO);
+ else if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_BUSY)
/*
- * Wait till transmit is done.
+ * Let the caller decide if we need to be restarted. It will
+ * currently blindly restart us, but it could check timeout in
+ * the future.
*/
- 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);
- }
- }
+ return (ERESTART);
- 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);
+ /*
+ * By design, we'll hardly ever hit this terminal condition unless we
+ * pick up nothing but tx interrupts here. More frequently, we will
+ * process rx buffers until we hit the terminal condition in the middle.
+ */
+ while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_DONE) {
+ /*
+ * This might have given us PXENV_UNDI_ISR_OUT_TRANSMIT, in
+ * which case we can just disregard and move on to the next
+ * buffer/frame.
+ */
+ if (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE)
+ goto nextbuf;
+
+ if (buf == NULL) {
+ /*
+ * Grab size from the first Frame that we picked up,
+ * allocate an rx buf to hold. Careful here, as we may
+ * see a fragmented frame that's spread out across
+ * multiple GET_NEXT calls.
+ */
+ size = isr->FrameLength;
+ buf = malloc(size + ETHER_ALIGN);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ 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;
+ /*
+ * Stop here before we risk catching the start of another frame.
+ * It would be nice to continue reading until we actually get a
+ * PXENV_UNDI_ISR_OUT_DONE, but our network stack in libsa isn't
+ * suitable for reading more than one packet at a time.
+ */
+ 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);
if (isr->Status != 0) {
- bio_free(isr, sizeof(*isr));
free(buf);
- return (-1);
+ return (ENXIO);
}
-
- /* Did we got another update? */
- if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE)
- continue;
- break;
}
*pkt = buf;
+ *retsize = rsize;
+ return (0);
+}
+
+static int
+pxe_netif_receive(void **pkt, ssize_t *size)
+{
+ t_PXENV_UNDI_ISR *isr;
+ int ret;
+
+ isr = bio_alloc(sizeof(*isr));
+ if (isr == NULL)
+ return (ENOMEM);
+
+ /*
+ * This completely ignores the timeout specified in pxe_netif_get(), but
+ * we shouldn't be running long enough here for that to make a
+ * difference.
+ */
+ for (;;) {
+ /* We'll only really re-enter for PXENV_UNDI_ISR_OUT_BUSY. */
+ ret = pxe_netif_receive_isr(isr, pkt, size);
+ if (ret != ERESTART)
+ break;
+ }
+
bio_free(isr, sizeof(*isr));
- return (rsize);
+ return (ret);
}
static ssize_t
@@ -525,16 +569,19 @@
time_t t;
void *ptr;
int ret = -1;
+ ssize_t size;
t = getsecs();
+ size = 0;
while ((getsecs() - t) < timeout) {
- ret = pxe_netif_receive(&ptr);
+ ret = pxe_netif_receive(&ptr, &size);
if (ret != -1) {
*pkt = ptr;
break;
}
}
- return (ret);
+
+ return (ret == 0 ? size : -1);
}
static ssize_t

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 19, 1:28 PM (21 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14717280
Default Alt Text
D31512.id94179.diff (5 KB)

Event Timeline