示例#1
0
/*
 * Either use the shared memory (if enabled on the board) or put the packet
 * out through the ASIC FIFO.
 */
static void
el2_block_output(struct net_device *dev, int count,
		 const unsigned char *buf, int start_page)
{
    unsigned short int *wrd;
    int boguscount;		/* timeout counter */
    unsigned short word;	/* temporary for better machine code */

    if (ei_status.word16)      /* Tx packets go into bank 0 on EL2/16 card */
	outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
    else
	outb(EGACFR_NORM, E33G_GACFR);

    if (dev->mem_start) {	/* Shared memory transfer */
	unsigned long dest_addr = dev->mem_start +
	    ((start_page - ei_status.tx_start_page) << 8);
	isa_memcpy_toio(dest_addr, buf, count);
	outb(EGACFR_NORM, E33G_GACFR);	/* Back to bank1 in case on bank0 */
	return;
    }

/*
 *  No shared memory, put the packet out the other way.
 *  Set up then start the internal memory transfer to Tx Start Page
 */

    word = (unsigned short)start_page;
    outb(word&0xFF, E33G_DMAAH);
    outb(word>>8, E33G_DMAAL);

    outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT
	   | ECNTRL_START, E33G_CNTRL);

/*
 *  Here I am going to write data to the FIFO as quickly as possible.
 *  Note that E33G_FIFOH is defined incorrectly. It is really
 *  E33G_FIFOL, the lowest port address for both the byte and
 *  word write. Variable 'count' is NOT checked. Caller must supply a
 *  valid count. Note that I may write a harmless extra byte to the
 *  8390 if the byte-count was not even.
 */
    wrd = (unsigned short int *) buf;
    count  = (count + 1) >> 1;
    for(;;)
    {
        boguscount = 0x1000;
        while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
        {
            if(!boguscount--)
            {
                printk("%s: FIFO blocked in el2_block_output.\n", dev->name);
                el2_reset_8390(dev);
                goto blocked;
            }
        }
        if(count > WRD_COUNT)
        {
            outsw(E33G_FIFOH, wrd, WRD_COUNT);
            wrd   += WRD_COUNT;
            count -= WRD_COUNT;
        }
        else
        {
            outsw(E33G_FIFOH, wrd, count);
            break;
        }
    }
    blocked:;
    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
    return;
}
示例#2
0
文件: 3c503.c 项目: 274914765/C
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 {
        memcpy_fromio(skb->data, base + ring_offset, count);
    }
    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;
}