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

📄 smc91c92_cs.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
    smc->stats.tx_bytes += skb->len;    /* The card should use the just-allocated buffer. */    outw(packet_no, ioaddr + PNR_ARR);    /* point to the beginning of the packet */    outw(PTR_AUTOINC , ioaddr + POINTER);    /* Send the packet length (+6 for status, length and ctl byte)       and the status word (set to zeros). */    {	u_char *buf = skb->data;	u_int length = skb->len; /* The chip will pad to ethernet min. */	DEBUG(2, "%s: Trying to xmit packet of length %d.\n",	      dev->name, length);		/* send the packet length: +6 for status word, length, and ctl */	outw(0, ioaddr + DATA_1);	outw(length + 6, ioaddr + DATA_1);	outsw(ioaddr + DATA_1, buf, length >> 1);		/* The odd last byte, if there is one, goes in the control word. */	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);    }    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |	 (inw(ioaddr + INTERRUPT) & 0xff00),	 ioaddr + INTERRUPT);    /* The chip does the rest of the work. */    outw(MC_ENQUEUE , ioaddr + MMU_CMD);    smc->saved_skb = NULL;    dev_kfree_skb_irq(skb);    dev->trans_start = jiffies;    netif_start_queue(dev);    return;}/*====================================================================*/static void smc_tx_timeout(struct net_device *dev){    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "	   "Tx_status %2.2x status %4.4x.\n",	   dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));    smc->stats.tx_errors++;    smc_reset(dev);    dev->trans_start = jiffies;    smc->saved_skb = NULL;    netif_wake_queue(dev);}static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev){    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    u_short num_pages;    short time_out, ir;    netif_stop_queue(dev);    DEBUG(2, "%s: smc_start_xmit(length = %d) called,"	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));    if (smc->saved_skb) {	/* THIS SHOULD NEVER HAPPEN. */	smc->stats.tx_aborted_errors++;	printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",	       dev->name);	return 1;    }    smc->saved_skb = skb;    num_pages = skb->len >> 8;    if (num_pages > 7) {	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);	dev_kfree_skb (skb);	smc->saved_skb = NULL;	smc->stats.tx_dropped++;	return 0;		/* Do not re-queue this packet. */    }    /* A packet is now waiting. */    smc->packets_waiting++;    SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */    /* need MC_RESET to keep the memory consistent. errata? */    if (smc->rx_ovrn) {	outw(MC_RESET, ioaddr + MMU_CMD);	smc->rx_ovrn = 0;    }    /* Allocate the memory; send the packet now if we win. */    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {	ir = inw(ioaddr+INTERRUPT);	if (ir & IM_ALLOC_INT) {	    /* Acknowledge the interrupt, send the packet. */	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);	    smc_hardware_send_packet(dev);	/* Send the packet now.. */	    return 0;	}    }    /* Otherwise defer until the Tx-space-allocated interrupt. */    DEBUG(2, "%s: memory allocation deferred.\n", dev->name);    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);    return 0;}/*======================================================================    Handle a Tx anomolous event.  Entered while in Window 2.======================================================================*/static void smc_tx_err(struct net_device * dev){    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;    int tx_status;    /* select this as the packet to read from */    outw(packet_no, ioaddr + PNR_ARR);    /* read the first word from this packet */    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);    tx_status = inw(ioaddr + DATA_1);    smc->stats.tx_errors++;    if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++;    if (tx_status & TS_LATCOL)  smc->stats.tx_window_errors++;    if (tx_status & TS_16COL) {	smc->stats.tx_aborted_errors++;	smc->tx_err++;    }    if (tx_status & TS_SUCCESS) {	printk(KERN_NOTICE "%s: Successful packet caused error "	       "interrupt?\n", dev->name);    }    /* re-enable transmit */    SMC_SELECT_BANK(0);    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);    SMC_SELECT_BANK(2);    outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */    /* one less packet waiting for me */    smc->packets_waiting--;    outw(saved_packet, ioaddr + PNR_ARR);    return;}/*====================================================================*/static void smc_eph_irq(struct net_device *dev){    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    u_short card_stats, ephs;    SMC_SELECT_BANK(0);    ephs = inw(ioaddr + EPH);    DEBUG(2, "%s: Ethernet protocol handler interrupt, status"	  " %4.4x.\n", dev->name, ephs);    /* Could be a counter roll-over warning: update stats. */    card_stats = inw(ioaddr + COUNTER);    /* single collisions */    smc->stats.collisions += card_stats & 0xF;    card_stats >>= 4;    /* multiple collisions */    smc->stats.collisions += card_stats & 0xF;#if 0 		/* These are for when linux supports these statistics */    card_stats >>= 4;			/* deferred */    card_stats >>= 4;			/* excess deferred */#endif    /* If we had a transmit error we must re-enable the transmitter. */    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);    /* Clear a link error interrupt. */    SMC_SELECT_BANK(1);    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,	 ioaddr + CONTROL);    SMC_SELECT_BANK(2);}/*====================================================================*/static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs){    struct net_device *dev = dev_id;    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr;    u_short saved_bank, saved_pointer, mask, status;    unsigned int handled = 1;    char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */    if (!netif_device_present(dev))	return IRQ_NONE;    ioaddr = dev->base_addr;    DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,	  irq, ioaddr);    smc->watchdog = 0;    saved_bank = inw(ioaddr + BANK_SELECT);    if ((saved_bank & 0xff00) != 0x3300) {	/* The device does not exist -- the card could be off-line, or	   maybe it has been ejected. */	DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"	      "/ejected device.\n", dev->name, irq);	handled = 0;	goto irq_done;    }    SMC_SELECT_BANK(2);    saved_pointer = inw(ioaddr + POINTER);    mask = inw(ioaddr + INTERRUPT) >> 8;    /* clear all interrupts */    outw(0, ioaddr + INTERRUPT);    do { /* read the status flag, and mask it */	status = inw(ioaddr + INTERRUPT) & 0xff;	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,	      status, mask);	if ((status & mask) == 0) {	    if (bogus_cnt == INTR_WORK)		handled = 0;	    break;	}	if (status & IM_RCV_INT) {	    /* Got a packet(s). */	    smc_rx(dev);	}	if (status & IM_TX_INT) {	    smc_tx_err(dev);	    outw(IM_TX_INT, ioaddr + INTERRUPT);	}	status &= mask;	if (status & IM_TX_EMPTY_INT) {	    outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);	    mask &= ~IM_TX_EMPTY_INT;	    smc->stats.tx_packets += smc->packets_waiting;	    smc->packets_waiting = 0;	}	if (status & IM_ALLOC_INT) {	    /* Clear this interrupt so it doesn't happen again */	    mask &= ~IM_ALLOC_INT;		    smc_hardware_send_packet(dev);		    /* enable xmit interrupts based on this */	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);		    /* and let the card send more packets to me */	    netif_wake_queue(dev);	}	if (status & IM_RX_OVRN_INT) {	    smc->stats.rx_errors++;	    smc->stats.rx_fifo_errors++;	    if (smc->duplex)		smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);	}	if (status & IM_EPH_INT)	    smc_eph_irq(dev);    } while (--bogus_cnt);    DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);    /* restore state register */    outw((mask<<8), ioaddr + INTERRUPT);    outw(saved_pointer, ioaddr + POINTER);    SMC_SELECT_BANK(saved_bank);    DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);irq_done:    if ((smc->manfid == MANFID_OSITECH) &&	(smc->cardid != PRODID_OSITECH_SEVEN)) {	/* Retrigger interrupt if needed */	mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);	set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);    }    if (smc->manfid == MANFID_MOTOROLA) {	u_char cor;	cor = readb(smc->base + MOT_UART + CISREG_COR);	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);	writeb(cor, smc->base + MOT_UART + CISREG_COR);	cor = readb(smc->base + MOT_LAN + CISREG_COR);	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);	writeb(cor, smc->base + MOT_LAN + CISREG_COR);    }#ifdef DOES_NOT_WORK    if (smc->base != NULL) { /* Megahertz MFC's */	readb(smc->base+MEGAHERTZ_ISR);	readb(smc->base+MEGAHERTZ_ISR);    }#endif    return IRQ_RETVAL(handled);}/*====================================================================*/static void smc_rx(struct net_device *dev){    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    int rx_status;    int packet_length;	/* Caution: not frame length, rather words			   to transfer from the chip. */    /* Assertion: we are in Window 2. */    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",	       dev->name);	return;    }    /*  Reset the read pointer, and read the status and packet length. */    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);    rx_status = inw(ioaddr + DATA_1);    packet_length = inw(ioaddr + DATA_1) & 0x07ff;    DEBUG(2, "%s: Receive status %4.4x length %d.\n",	  dev->name, rx_status, packet_length);    if (!(rx_status & RS_ERRORS)) {			/* do stuff to make a new packet */	struct sk_buff *skb;		/* Note: packet_length adds 5 or 6 extra bytes here! */	skb = dev_alloc_skb(packet_length+2);		if (skb == NULL) {	    DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);	    smc->stats.rx_dropped++;	    outw(MC_RELEASE, ioaddr + MMU_CMD);	    return;	}		packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);	skb_reserve(skb, 2);	insw(ioaddr+DATA_1, skb_put(skb, packet_length),	     (packet_length+1)>>1);	skb->protocol = eth_type_trans(skb, dev);		skb->dev = dev;	netif_rx(skb);	dev->last_rx = jiffies;	smc->stats.rx_packets++;	smc->stats.rx_bytes += packet_length;	if (rx_status & RS_MULTICAST)	    smc->stats.multicast++;    } else {	/* error ... */	smc->stats.rx_errors++;		if (rx_status & RS_ALGNERR)  smc->stats.rx_frame_errors++;	if (rx_status & (RS_TOOSHORT | RS_TOOLONG))	    smc->stats.rx_length_errors++;	if (rx_status & RS_BADCRC)	smc->stats.rx_crc_errors++;    }    /* Let the MMU free the memory of this packet. */    outw(MC_RELEASE, ioaddr + MMU_CMD);    return;}/*====================================================================*/static struct net_device_stats *smc_get_stats(struct net_device *dev){    struct smc_private *smc = netdev_priv(dev);    /* Nothing to update - the 91c92 is a pretty primative chip. */    return &smc->stats;}/*======================================================================    Calculate values for the hardware multicast filter hash table.======================================================================*/static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,			       u_char *multicast_table){    struct dev_mc_list	*mc_addr;    for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {	u_int position = ether_crc(6, mc_addr->dmi_addr);#ifndef final_version		/* Verify multicast address. */	if ((mc_addr->dmi_addr[0] & 1) == 0)	    continue;#endif	multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);    }}/*======================================================================    Set the receive mode.    This routine is used by both the protocol level to notify us of    promiscuous/multicast mode changes, and by the open/reset code to    initialize the Rx registers.  We always set the multicast list and    leave the receiver running.======================================================================*/static void set_rx_mode(struct net_device *dev){    kio_addr_t ioaddr = dev->base_addr;    struct smc_private *smc = netdev_priv(dev);    u_int multicast_table[ 2 ] = { 0, };    unsigned long flags;    u_short rx_cfg_setting;    if (dev->flags & IFF_PROMISC) {	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;    } else if (dev->flags & IFF_ALLMULTI)	rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;    else {	if (dev->mc_count)  {	    fill_multicast_tbl(dev->mc_count, dev->mc_list,			       (u_char *)multicast_table);	}	rx_cfg_setting = RxStripCRC | RxEnable;    }

⌨️ 快捷键说明

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