/* Block input and output are easy on shared memory ethercards. The E21xx makes block_input() especially easy by wrapping the top ring buffer to the bottom automatically. */ static void e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { short ioaddr = dev->base_addr; char __iomem *shared_mem = ei_status.mem; mem_on(ioaddr, shared_mem, (ring_offset>>8)); /* Packet is always in one chunk -- we can copy + cksum. */ eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0); mem_off(ioaddr); }
static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256; if (ring_offset + count > ES_STOP_PG*256) { /* Packet wraps over end of ring buffer. */ int semi_count = ES_STOP_PG*256 - ring_offset; memcpy_fromio(skb->data, xfer_start, semi_count); count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem, count); } else { /* Packet is in one chunk. */ eth_io_copy_and_sum(skb, xfer_start, count, 0); } }
static void ac_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { void __iomem *start = ei_status.mem + ring_offset - AC_START_PG*256; if (ring_offset + count > AC_STOP_PG*256) { /* We must wrap the input move. */ int semi_count = AC_STOP_PG*256 - ring_offset; memcpy_fromio(skb->data, start, semi_count); count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES*256, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ eth_io_copy_and_sum(skb, start, count, 0); } }
static void el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { int boguscount = 0; void __iomem *base = ei_status.mem; unsigned short int *buf; unsigned short word; /* Maybe enable shared memory just be to be safe... nahh.*/ if (base) { /* Use the shared memory. */ ring_offset -= (EL2_MB1_START_PG<<8); if (ring_offset + count > EL2_MEMSIZE) { /* We must wrap the input move. */ int semi_count = EL2_MEMSIZE - ring_offset; memcpy_fromio(skb->data, base + ring_offset, semi_count); count -= semi_count; memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ eth_io_copy_and_sum(skb, base + ring_offset, count, 0); } return; } /* * No shared memory, use programmed I/O. */ word = (unsigned short) ring_offset; outb(word>>8, E33G_DMAAH); outb(word&0xFF, E33G_DMAAL); outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT | ECNTRL_START, E33G_CNTRL); /* * Here I also try to get data as fast as possible. I am betting that I * can read one extra byte without clobbering anything in the kernel because * this would only occur on an odd byte-count and allocation of skb->data * is word-aligned. Variable 'count' is NOT checked. Caller must check * for a valid count. * [This is currently quite safe.... but if one day the 3c503 explodes * you know where to come looking ;)] */ buf = (unsigned short int *) skb->data; count = (count + 1) >> 1; for(;;) { boguscount = 0x1000; while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0) { if(!boguscount--) { printk("%s: FIFO blocked in el2_block_input.\n", dev->name); el2_reset_8390(dev); goto blocked; } } if(count > WRD_COUNT) { insw(E33G_FIFOH, buf, WRD_COUNT); buf += WRD_COUNT; count -= WRD_COUNT; } else { insw(E33G_FIFOH, buf, count); break; } } blocked: ; outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); return; }