⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8390.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 2 页
字号:
    struct ei_device *ei_local = (struct ei_device *) dev->priv;        outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */#ifdef EI_PINGPONG    /*     * There are two Tx buffers, see which one finished, and trigger     * the send of another one if it exists.     */    ei_local->txqueue--;    if (ei_local->tx1 < 0) {	if (ei_local->lasttx != 1 && ei_local->lasttx != -1)		printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",			   ei_local->name, ei_local->lasttx, ei_local->tx1);	ei_local->tx1 = 0;	dev->tbusy = 0;	if (ei_local->tx2 > 0) {		ei_local->txing = 1;		NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);		dev->trans_start = jiffies;		ei_local->tx2 = -1,		ei_local->lasttx = 2;	} else		ei_local->lasttx = 20, ei_local->txing = 0;    } else if (ei_local->tx2 < 0) {	if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)		printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",			   ei_local->name, ei_local->lasttx, ei_local->tx2);	ei_local->tx2 = 0;	dev->tbusy = 0;	if (ei_local->tx1 > 0) {		ei_local->txing = 1;		NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);		dev->trans_start = jiffies;		ei_local->tx1 = -1;		ei_local->lasttx = 1;	} else		ei_local->lasttx = 10, ei_local->txing = 0;    } else	printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",		   dev->name, ei_local->lasttx);#else	/* EI_PINGPONG */    /*     *  Single Tx buffer: mark it free so another packet can be loaded.     */    ei_local->txing = 0;    dev->tbusy = 0;#endif    /* Minimize Tx latency: update the statistics after we restart TXing. */    if (status & ENTSR_COL)	ei_local->stat.collisions++;    if (status & ENTSR_PTX)	ei_local->stat.tx_packets++;    else {	ei_local->stat.tx_errors++;	if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;	if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;	if (status & ENTSR_FU)  ei_local->stat.tx_fifo_errors++;	if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;	if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;    }    mark_bh (NET_BH);}/* We have a good packet(s), get it/them out of the buffers. */static void ei_receive(struct device *dev){    int e8390_base = dev->base_addr;    struct ei_device *ei_local = (struct ei_device *) dev->priv;    unsigned char rxing_page, this_frame, next_frame;    unsigned short current_offset;    int rx_pkt_count = 0;    struct e8390_pkt_hdr rx_frame;    int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;        while (++rx_pkt_count < 10) {		int pkt_len;				/* Get the rx page (incoming packet pointer). */		outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);		rxing_page = inb_p(e8390_base + EN1_CURPAG);		outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);				/* Remove one frame from the ring.  Boundary is always a page behind. */		this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;		if (this_frame >= ei_local->stop_page)			this_frame = ei_local->rx_start_page;				/* Someday we'll omit the previous, iff we never get this message.		   (There is at least one clone claimed to have a problem.)  */		if (ei_debug > 0  &&  this_frame != ei_local->current_page)			printk("%s: mismatched read page pointers %2x vs %2x.\n",				   dev->name, this_frame, ei_local->current_page);				if (this_frame == rxing_page)	/* Read all the frames? */			break;				/* Done for now */				current_offset = this_frame << 8;		ei_get_8390_hdr(dev, &rx_frame, this_frame);				pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);				next_frame = this_frame + 1 + ((pkt_len+4)>>8);				/* Check for bogosity warned by 3c503 book: the status byte is never		   written.  This happened a lot during testing! This code should be		   cleaned up someday. */		if (rx_frame.next != next_frame			&& rx_frame.next != next_frame + 1			&& rx_frame.next != next_frame - num_rx_pages			&& rx_frame.next != next_frame + 1 - num_rx_pages) {			ei_local->current_page = rxing_page;			outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);			ei_local->stat.rx_errors++;			continue;		}		if (pkt_len < 60  ||  pkt_len > 1518) {			if (ei_debug)				printk("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",					   dev->name, rx_frame.count, rx_frame.status,					   rx_frame.next);			ei_local->stat.rx_errors++;		} else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {			struct sk_buff *skb;						skb = dev_alloc_skb(pkt_len+2);			if (skb == NULL) {				if (ei_debug > 1)					printk("%s: Couldn't allocate a sk_buff of size %d.\n",						   dev->name, pkt_len);				ei_local->stat.rx_dropped++;				break;			} else {				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */				skb->dev = dev;				skb_put(skb, pkt_len);	/* Make room */				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));				skb->protocol=eth_type_trans(skb,dev);				netif_rx(skb);				ei_local->stat.rx_packets++;			}		} else {			int errs = rx_frame.status;			if (ei_debug)				printk("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",					   dev->name, rx_frame.status, rx_frame.next,					   rx_frame.count);			if (errs & ENRSR_FO)				ei_local->stat.rx_fifo_errors++;		}		next_frame = rx_frame.next;				/* This _should_ never happen: it's here for avoiding bad clones. */		if (next_frame >= ei_local->stop_page) {			printk("%s: next frame inconsistency, %#2x\n", dev->name,				   next_frame);			next_frame = ei_local->rx_start_page;		}		ei_local->current_page = next_frame;		outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);    }    /* We used to also ack ENISR_OVER here, but that would sometimes mask    a real overrun, leaving the 8390 in a stopped state with rec'vr off. */    outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);    return;}/*  * We have a receiver overrun: we have to kick the 8390 to get it started * again. Problem is that you have to kick it exactly as NS prescribes in * the updated datasheets, or "the NIC may act in an unpredictable manner." * This includes causing "the NIC to defer indefinitely when it is stopped * on a busy network."  Ugh. */static void ei_rx_overrun(struct device *dev){    int e8390_base = dev->base_addr;    unsigned long wait_start_time;    unsigned char was_txing, must_resend = 0;    struct ei_device *ei_local = (struct ei_device *) dev->priv;        /*     * Record whether a Tx was in progress and then issue the     * stop command.     */    was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);        if (ei_debug > 1)	printk("%s: Receiver overrun.\n", dev->name);    ei_local->stat.rx_over_errors++;        /*      * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.     * Early datasheets said to poll the reset bit, but now they say that     * it "is not a reliable indicator and subsequently should be ignored."     * We wait at least 10ms.     */    wait_start_time = jiffies;    while (jiffies - wait_start_time <= 1*HZ/100)	barrier();    /*     * Reset RBCR[01] back to zero as per magic incantation.     */    outb_p(0x00, e8390_base+EN0_RCNTLO);    outb_p(0x00, e8390_base+EN0_RCNTHI);    /*     * See if any Tx was interrupted or not. According to NS, this     * step is vital, and skipping it will cause no end of havoc.     */    if (was_txing) { 	unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);	if (!tx_completed) must_resend = 1;    }    /*     * Have to enter loopback mode and then restart the NIC before     * you are allowed to slurp packets up off the ring.     */    outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);    outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);    /*     * Clear the Rx ring of all the debris, and ack the interrupt.     */    ei_receive(dev);    outb_p(ENISR_OVER, e8390_base+EN0_ISR);    /*     * Leave loopback mode, and resend any packet that got stopped.     */    outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);     if (must_resend)    	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);	}static struct enet_statistics *get_stats(struct device *dev){    short ioaddr = dev->base_addr;    struct ei_device *ei_local = (struct ei_device *) dev->priv;        /* If the card is stopped, just return the present stats. */    if (dev->start == 0) return &ei_local->stat;    /* Read the counter registers, assuming we are in page 0. */    ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);    ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);    ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);        return &ei_local->stat;}/* *	Set or clear the multicast filter for this adaptor. */ static void set_multicast_list(struct device *dev){	short ioaddr = dev->base_addr;    	if(dev->flags&IFF_PROMISC)	{		outb_p(E8390_RXCONFIG | 0x18, ioaddr + EN0_RXCR);	}	else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)	{		/* The multicast-accept list is initialized to accept-all, and we		   rely on higher-level filtering for now. */		outb_p(E8390_RXCONFIG | 0x08, ioaddr + EN0_RXCR);	} 	else		outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR);}/* Initialize the rest of the 8390 device structure. */int ethdev_init(struct device *dev){    if (ei_debug > 1)		printk(version);        if (dev->priv == NULL) {		struct ei_device *ei_local;				dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);		if (dev->priv == NULL)			return -ENOMEM;		memset(dev->priv, 0, sizeof(struct ei_device));		ei_local = (struct ei_device *)dev->priv;    }        dev->hard_start_xmit = &ei_start_xmit;    dev->get_stats	= get_stats;    dev->set_multicast_list = &set_multicast_list;    ether_setup(dev);            return 0;}/* This page of functions should be 8390 generic *//* Follow National Semi's recommendations for initializing the "NIC". */void NS8390_init(struct device *dev, int startp){    int e8390_base = dev->base_addr;    struct ei_device *ei_local = (struct ei_device *) dev->priv;    int i;    int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;    unsigned long flags;        /* Follow National Semi's recommendations for initing the DP83902. */    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */    outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */    /* Clear the remote byte count registers. */    outb_p(0x00,  e8390_base + EN0_RCNTLO);    outb_p(0x00,  e8390_base + EN0_RCNTHI);    /* Set to monitor and loopback mode -- this is vital!. */    outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */    outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */    /* Set the transmit page and receive ring. */    outb_p(ei_local->tx_start_page,	 e8390_base + EN0_TPSR);    ei_local->tx1 = ei_local->tx2 = 0;    outb_p(ei_local->rx_start_page,	 e8390_base + EN0_STARTPG);    outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/    ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */    outb_p(ei_local->stop_page,	  e8390_base + EN0_STOPPG);    /* Clear the pending interrupts and mask. */    outb_p(0xFF, e8390_base + EN0_ISR);    outb_p(0x00,  e8390_base + EN0_IMR);        /* Copy the station address into the DS8390 registers,       and set the multicast hash bitmap to receive all multicasts. */    save_flags(flags);    cli();    outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */    for(i = 0; i < 6; i++) {		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);    }    /* Initialize the multicast list to accept-all.  If we enable multicast       the higher levels can do the filtering. */    for(i = 0; i < 8; i++)		outb_p(0xff, e8390_base + EN1_MULT + i);        outb_p(ei_local->rx_start_page,	 e8390_base + EN1_CURPAG);    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);    restore_flags(flags);    dev->tbusy = 0;    dev->interrupt = 0;    ei_local->tx1 = ei_local->tx2 = 0;    ei_local->txing = 0;    if (startp) {		outb_p(0xff,  e8390_base + EN0_ISR);		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);		outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */		/* 3c503 TechMan says rxconfig only after the NIC is started. */		outb_p(E8390_RXCONFIG,	e8390_base + EN0_RXCR); /* rx on,  */		dev->set_multicast_list(dev);		/* Get the multicast status right if this							   was a reset. */    }    return;}/* Trigger a transmit start, assuming the length is valid. */static void NS8390_trigger_send(struct device *dev, unsigned int length,								int start_page){    int e8390_base = dev->base_addr;        outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);        if (inb_p(e8390_base) & E8390_TRANS) {		printk("%s: trigger_send() called with the transmitter busy.\n",			   dev->name);		return;    }    outb_p(length & 0xff, e8390_base + EN0_TCNTLO);    outb_p(length >> 8, e8390_base + EN0_TCNTHI);    outb_p(start_page, e8390_base + EN0_TPSR);    outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);    return;}#ifdef MODULEint init_module(void){     return 0;}voidcleanup_module(void){}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 8390.c" *  version-control: t *  kept-new-versions: 5 *  c-indent-level: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -