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

📄 sonic.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * sonic.c * * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) *  * This driver is based on work from Andreas Busse, but most of * the code is rewritten. *  * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) * *    Core code included by system sonic drivers *//* * Sources: Olivetti M700-10 Risc Personal Computer hardware handbook, * National Semiconductors data sheet for the DP83932B Sonic Ethernet * controller, and the files "8390.c" and "skeleton.c" in this directory. *//* * Open/initialize the SONIC controller. * * This routine should set everything up anew at each open, even *  registers that "should" only need to be set once at boot, so that *  there is non-reboot way to recover if something goes wrong. */static int sonic_open(struct net_device *dev){    if (sonic_debug > 2)      printk("sonic_open: initializing sonic driver.\n");        /*     * We don't need to deal with auto-irq stuff since we     * hardwire the sonic interrupt.     *//* * XXX Horrible work around:  We install sonic_interrupt as fast interrupt. * This means that during execution of the handler interrupt are disabled * covering another bug otherwise corrupting data.  This doesn't mean * this glue works ok under all situations. *///    if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {    if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) {	printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);	return -EAGAIN;    }    /*     * Initialize the SONIC     */    sonic_init(dev);    dev->tbusy = 0;    dev->interrupt = 0;    dev->start = 1;    if (sonic_debug > 2)      printk("sonic_open: Initialization done.\n");	    return 0;}/* * Close the SONIC device */static intsonic_close(struct net_device *dev){    unsigned int base_addr = dev->base_addr;        if (sonic_debug > 2)      printk ("sonic_close\n");    dev->tbusy = 1;    dev->start = 0;        /*     * stop the SONIC, disable interrupts     */    SONIC_WRITE(SONIC_ISR,0x7fff);    SONIC_WRITE(SONIC_IMR,0);    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);    sonic_free_irq(dev->irq, dev);		/* release the IRQ */    return 0;}/* * transmit packet */static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev){    struct sonic_local *lp = (struct sonic_local *)dev->priv;    unsigned int base_addr = dev->base_addr;    unsigned int laddr;    int entry,length;        if (sonic_debug > 2)      printk("sonic_send_packet: skb=%p, dev=%p\n",skb,dev);      if (dev->tbusy) {	int tickssofar = jiffies - dev->trans_start;	/* If we get here, some higher level has decided we are broken.	 There should really be a "kick me" function call instead. */      	if (sonic_debug > 1)	  printk("sonic_send_packet: called with dev->tbusy = 1 !\n");		if (tickssofar < 5)	  return 1;		printk("%s: transmit timed out.\n", dev->name);		/* Try to restart the adaptor. */	sonic_init(dev);	dev->tbusy=0;	dev->trans_start = jiffies;    }    /*      * Block a timer-based transmit from overlapping.  This could better be     * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.     */    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {	printk("%s: Transmitter access conflict.\n", dev->name);	return 1;    }        /*     * Map the packet data into the logical DMA address space     */    if ((laddr = vdma_alloc(PHYSADDR(skb->data),skb->len)) == ~0UL) {	printk("%s: no VDMA entry for transmit available.\n",dev->name);	dev_kfree_skb(skb);	dev->tbusy = 0;	return 1;    }    entry = lp->cur_tx & SONIC_TDS_MASK;        lp->tx_laddr[entry] = laddr;    lp->tx_skb[entry] = skb;        length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;    flush_cache_all();        /*     * Setup the transmit descriptor and issue the transmit command.     */    lp->tda[entry].tx_status = 0;		/* clear status */    lp->tda[entry].tx_frag_count = 1;		/* single fragment */    lp->tda[entry].tx_pktsize = length;		/* length of packet */        lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff;    lp->tda[entry].tx_frag_ptr_h = laddr >> 16;    lp->tda[entry].tx_frag_size  = length;    lp->cur_tx++;    lp->stats.tx_bytes += length;        if (sonic_debug > 2)      printk("sonic_send_packet: issueing Tx command\n");    SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP);    dev->trans_start = jiffies;    if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS)      dev->tbusy = 0;    else      lp->tx_full = 1;        return 0;}/* * The typical workload of the driver: * Handle the network interface interrupts. */static voidsonic_interrupt(int irq, void *dev_id, struct pt_regs * regs){    struct net_device *dev = (struct net_device *)dev_id;    unsigned int base_addr = dev->base_addr;    struct sonic_local *lp;    int status;    if (dev == NULL) {	printk ("sonic_interrupt: irq %d for unknown device.\n", irq);	return;    }    dev->interrupt = 1;    lp = (struct sonic_local *)dev->priv;    status = SONIC_READ(SONIC_ISR);    SONIC_WRITE(SONIC_ISR,0x7fff); /* clear all bits */      if (sonic_debug > 2)      printk("sonic_interrupt: ISR=%x\n",status);    if (status & SONIC_INT_PKTRX) {	sonic_rx(dev);				/* got packet(s) */    }        if (status & SONIC_INT_TXDN) {	int dirty_tx = lp->dirty_tx;	while (dirty_tx < lp->cur_tx) {	    int entry = dirty_tx & SONIC_TDS_MASK;	    int status = lp->tda[entry].tx_status;	    if (sonic_debug > 3)	      printk ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n",		      status,lp->cur_tx,lp->dirty_tx);	    if (status == 0) {		/* It still hasn't been Txed, kick the sonic again */		SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP);				break;	    }	    /* put back EOL and free descriptor */	    lp->tda[entry].tx_frag_count = 0;	    lp->tda[entry].tx_status = 0;	    if (status & 0x0001)	      lp->stats.tx_packets++;	    else {		lp->stats.tx_errors++;		if (status & 0x0642) lp->stats.tx_aborted_errors++;		if (status & 0x0180) lp->stats.tx_carrier_errors++;		if (status & 0x0020) lp->stats.tx_window_errors++;		if (status & 0x0004) lp->stats.tx_fifo_errors++;	    }	    /* We must free the original skb */	    if (lp->tx_skb[entry]) {		dev_kfree_skb(lp->tx_skb[entry]);		lp->tx_skb[entry] = 0;	    }	    /* and the VDMA address */	    vdma_free(lp->tx_laddr[entry]);	    dirty_tx++;	}		if (lp->tx_full && dev->tbusy	    && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) {	    /* The ring is no longer full, clear tbusy. */	    lp->tx_full = 0;	    dev->tbusy = 0;	    mark_bh(NET_BH);	}		lp->dirty_tx = dirty_tx;    }        /*     * check error conditions     */    if (status & SONIC_INT_RFO) {	printk ("%s: receive fifo underrun\n",dev->name);	lp->stats.rx_fifo_errors++;    }    if (status & SONIC_INT_RDE) {	printk ("%s: receive descriptors exhausted\n",dev->name);	lp->stats.rx_dropped++;    }    if (status & SONIC_INT_RBE) {	printk ("%s: receive buffer exhausted\n",dev->name);	lp->stats.rx_dropped++;	    }    if (status & SONIC_INT_RBAE) {	printk ("%s: receive buffer area exhausted\n",dev->name);	lp->stats.rx_dropped++;	    }    /* counter overruns; all counters are 16bit wide */    if (status & SONIC_INT_FAE)      lp->stats.rx_frame_errors += 65536;    if (status & SONIC_INT_CRC)      lp->stats.rx_crc_errors += 65536;    if (status & SONIC_INT_MP)      lp->stats.rx_missed_errors += 65536;    /* transmit error */    if (status & SONIC_INT_TXER)      lp->stats.tx_errors++;        /*     * clear interrupt bits and return     */    SONIC_WRITE(SONIC_ISR,status);    dev->interrupt = 0;    return;}/* * We have a good packet(s), get it/them out of the buffers. */static voidsonic_rx(struct net_device *dev){    unsigned int base_addr = dev->base_addr;    struct sonic_local *lp = (struct sonic_local *)dev->priv;    sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK];

⌨️ 快捷键说明

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