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

📄 ncr885e.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	spin_unlock_irqrestore( &sp->lock, flags );	/* the order seems important here for some reason.  If the MPIC isn't	   enabled before the ethernet chip is enabled, shrapnel from the	   bootloader causes us to receive interrupts even though we've not 	   yet enabled the tx channel.  Go figure.  It'd be better to configure	   the chip in the probe1() routine, but then we don't see interrupts	   at all.  Everything looks all right on the logic analyzer, but... */	ncr885e_config( dev );	/* enable ethernet interrupts */	if ( request_irq( dev->irq, &ncr885e_interrupt, SA_SHIRQ, chipname, dev )) {		printk( KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq );		return -EAGAIN;	}	(void) inw( ioaddr + INTERRUPT_CLEAR );	ncr885e_enable( dev );	/* start rx DBDMA */	outl( virt_to_bus( sp->rx_cmds ), ioaddr + RX_CMD_PTR_LO );	outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,	      ioaddr + RX_CHANNEL_CONTROL );	netif_start_queue(dev);	return 0;}static intncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev ){	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;	volatile struct dbdma_cmd *cp, *dp;	unsigned long flags, ioaddr = dev->base_addr;	int len, next, fill, entry;	if ( ncr885e_debug > 3)		printk( KERN_INFO "%s: xmit_start len=%d, dirty=%d, current=%d, active=%d\n",			dev->name, skb->len, sp->tx_dirty, sp->tx_current, sp->tx_active );	spin_lock_irqsave( &sp->lock, flags );	/* find the free slot in the ring buffer */	fill = sp->tx_current;	next = fill + 1;	if ( next >= NR_TX_RING )		next = 0;#if 0	/* mark ourselves as busy, even if we have too many packets waiting */	netif_stop_queue(dev);#endif	/* see if it's necessary to defer this packet */	if ( sp->tx_active >= MAX_TX_ACTIVE ) {		spin_unlock_irqrestore( &sp->lock, flags );		return -1;	}	sp->tx_active++;  /* bump "active tx" count */	sp->tx_current = next;  /* and show that we've used this buffer */	sp->tx_dirty = fill;     /* and mark this one to get picked up */	len = skb->len;	if ( len > ETH_FRAME_LEN ) {		printk( KERN_DEBUG "%s: xmit frame too long (%d)\n", dev->name, len );		len = ETH_FRAME_LEN;	}  	/* get index into the tx DBDMA chain */	entry = fill * 3;	sp->tx_skbufs[fill] = skb;	cp = sp->tx_cmds + entry;	dp = cp + 1;	/* update the rest of the OUTPUT_MORE descriptor */	outw( len, &cp->req_count );	outl( virt_to_bus( skb->data ), &cp->phy_addr );	outw( 0, &cp->xfer_status );	outw( 0, &cp->res_count );	/* and finish off the INPUT_MORE */	outw( 0, &dp->xfer_status );	outw( 0, &dp->res_count );	sp->tx_status[fill] = 0;	outl( virt_to_bus( &sp->tx_status[fill] ), &dp->phy_addr );	if ( ncr885e_debug > 2 )		printk(KERN_INFO "%s: xmit_start: active %d, tx_current %d, tx_dirty %d\n",		       dev->name, sp->tx_active, sp->tx_current, sp->tx_dirty );	if ( ncr885e_debug > 4 ) {		show_dbdma_cmd( cp );		show_dbdma_cmd( dp );	}	/* restart the tx DMA engine */	outl( virt_to_bus( cp ), ioaddr + TX_CMD_PTR_LO );	outl( (TX_DBDMA_ENABLE << 16)|TX_CHANNEL_RUN, 	      ioaddr + TX_CHANNEL_CONTROL );	ncr885e_set_timeout( dev );	spin_unlock_irqrestore( &sp->lock, flags );	dev->trans_start = jiffies;	return 0;      }static intncr885e_close(struct net_device *dev){	int i;	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;	unsigned long ioaddr = dev->base_addr;	netif_stop_queue(dev);	spin_lock( &np->lock );	printk(KERN_INFO "%s: NCR885E Ethernet closing...\n", dev->name );	if (ncr885e_debug > 1)		printk(KERN_DEBUG "%s: Shutting down Ethernet chip\n", dev->name);	ncr885e_disable(dev);	del_timer(&np->tx_timeout);	/* flip off rx and tx */	outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );	outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );  	/* free up the IRQ */	free_irq( dev->irq, dev );	for( i = 0; i < NR_RX_RING; i++ ) {		if (np->rx_skbufs[i])			dev_kfree_skb( np->rx_skbufs[i] );		np->rx_skbufs[i] = 0;	}#if 0	for (i = 0; i < NR_TX_RING; i++) {		if (np->tx_skbufs[i])			dev_kfree_skb(np->tx_skbufs[i]);		np->tx_skbufs[i] = 0;	}#endif	spin_unlock( &np->lock );	kfree( np->head );	return 0;}/* *  multicast promiscuous mode isn't used here.  Allow code in the *  IP stack to determine which multicast packets are good or bad.... *  (this avoids having to use the hash table registers) */static voidncr885e_set_multicast( struct net_device *dev ){	int ioaddr = dev->base_addr;	if ( ncr885e_debug > 3 )		printk("%s: set_multicast: dev->flags = %x, AF=%04x\n", 		       dev->name, dev->flags, inw( ioaddr + ADDRESS_FILTER ));	if ( dev->flags & IFF_PROMISC ) {		printk( KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name );		outw( ADDRESS_RPPRO, ioaddr + ADDRESS_FILTER );	}	/* accept all multicast packets without checking the mc_list.  */	else if ( dev->flags & IFF_ALLMULTI ) {		printk( KERN_INFO "%s: Enabling all multicast packets.\n", 			dev->name );		outw( ADDRESS_RPPRM, ioaddr + ADDRESS_FILTER );	}	/* enable broadcast rx */	else {		outw( ADDRESS_RPABC, ioaddr + ADDRESS_FILTER );	}  }static struct net_device_stats *ncr885e_stats( struct net_device *dev ){	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;	return &np->stats;}/*  By this function, we're certain that we have a 885 Ethernet controller *  so we finish setting it up and wrap up all the required Linux ethernet *  configuration. */static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq ){	struct net_device *dev;	struct ncr885e_private *sp;	unsigned short station_addr[3], val;	unsigned char *p;	int  i;	dev = init_etherdev( NULL, sizeof( struct ncr885e_private ) );	if (!dev)		return -ENOMEM;	SET_MODULE_OWNER(dev);	sp = dev->priv;	/* snag the station address and display it */	for( i = 0; i < 3; i++ ) {		val = inw( ioaddr + STATION_ADDRESS_0 + (i*2));		station_addr[i] = ((val >> 8) & 0xff) | ((val << 8) & 0xff00);	}	printk( KERN_INFO "%s: %s at %08lx,", dev->name, chipname, ioaddr );	p = (unsigned char *) &station_addr;	for( i=0; i < 6; i++ ) {		dev->dev_addr[i] = *p;		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i] );		p++;	}	printk(", IRQ %d.\n", irq );	/* set up a timer */	init_timer( &sp->tx_timeout );	sp->timeout_active = 0;	dev->base_addr = ioaddr;	dev->irq = irq;	ether_setup( dev );	/* everything else */	dev->open = ncr885e_open;	dev->stop = ncr885e_close;	dev->get_stats = ncr885e_stats;	dev->hard_start_xmit = ncr885e_xmit_start;	dev->set_multicast_list = ncr885e_set_multicast;	dev->set_mac_address = ncr885e_set_address;		root_dev = dev;	return 0;}/*  Since the NCR 53C885 is a multi-function chip, I'm not worrying about *  trying to get the the device(s) in slot order.  For our (Synergy's) *  purpose, there's just a single 53C885 on the board and we don't  *  worry about the rest. */static int __init ncr885e_probe(void){	struct pci_dev *pdev = NULL;	unsigned int ioaddr, ret;	unsigned char irq;	/* use 'if' not 'while' where because driver only supports one device */	if (( pdev = pci_find_device( PCI_VENDOR_ID_NCR, 					PCI_DEVICE_ID_NCR_53C885_ETHERNET,					pdev )) != NULL ) {		if ( !print_version ) {			print_version++;			printk( KERN_INFO "%s", version );		}		if (pci_enable_device(pdev))			return -ENODEV;		/* Use I/O space */		ioaddr = pci_resource_start (pdev, 0);		irq = pdev->irq;		if ( !request_region( ioaddr, NCR885E_TOTAL_SIZE, "ncr885e" ))			return -ENOMEM;		/* finish off the probe */		ret = ncr885e_probe1(ioaddr, irq);		if (ret)			release_region(ioaddr, NCR885E_TOTAL_SIZE);		else			pci_set_master(pdev);	}	return ret;}/* debugging to peek at dma descriptors */static voidshow_dbdma_cmd( volatile struct dbdma_cmd *cmd ){	printk( KERN_INFO " cmd %04x, physaddr %08x, req_count %04x\n",		inw( &cmd->command ), inl( &cmd->phy_addr ), inw( &cmd->req_count ));	printk( KERN_INFO " res_count %04x, xfer_status %04x, branch %08x\n", 		inw( &cmd->res_count ), inw( &cmd->xfer_status ),inl( &cmd->cmd_dep ));}#if 0static intread_eeprom( unsigned int ioaddr, int location ){	int loop;	unsigned char val;	outb( (location & 0xff), ioaddr + EE_WORD_ADDR );	/* take spillover from location in control reg */	outb(EE_CONTROL_RND_READB | (location & (0x7<<8)), ioaddr + EE_CONTROL);	loop = 1000;	while( (inb( ioaddr + EE_STATUS) & EE_SEB) &&	       (loop > 0) ) {		udelay( 10 );		loop--;	}	if ( inb( ioaddr + EE_STATUS ) & EE_SEE ) {		printk("%s: Serial EEPROM read error\n", chipname);		val = 0xff;	}	else 		val = inb( ioaddr + EE_READ_DATA );	return (int) val;}#endif#ifdef NCR885E_DEBUG_MIIstatic voidshow_mii( unsigned long ioaddr ){	int   phyctrl, phystat, phyadvert, phypartner, phyexpan;	phyctrl = read_mii( ioaddr, MII_AUTO_NEGOTIATION_CONTROL );	phystat = read_mii( ioaddr, MII_AUTO_NEGOTIATION_STATUS );	phyadvert = read_mii( ioaddr, MII_AUTO_NEGOTIATION_ADVERTISEMENT );	phypartner = read_mii( ioaddr, MII_AUTO_NEGOTIATION_LINK_PARTNER );	phyexpan = read_mii( ioaddr, MII_AUTO_NEGOTIATION_EXPANSION );	printk( KERN_INFO "PHY: advert=%d %s, partner=%s %s, link=%d, %s%s\n",		(phyadvert & MANATECH_100BASETX_FULL_DUPLEX ? 100 : 10),		(phyctrl & MANC_AUTO_NEGOTIATION_ENABLE ? "auto" : "fixed"),		(phypartner & MANLP_ACKNOWLEDGE ?		 (phypartner & MANATECH_100BASETX_FULL_DUPLEX ? "100" : "10") :		 "?"),		(phyexpan & MANE_LINK_PARTNER_AUTO_ABLE ? "auto" : "fixed"),		(phyctrl & MANC_PHY_SPEED_100 ? 100 : 10),		(phystat & MANS_LINK_STATUS ? "up" : "down"),		(phyexpan & MANE_PARALLEL_DETECTION_FAULT ? " PD-fault" : "" ));	return;}static intread_mii( unsigned long ioaddr, int reg ){	int    timeout;	timeout = 100000;	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {		if ( timeout-- < 0 ) {			printk( KERN_INFO "Timed out waiting for MII\n" );			return -1;		}	}	outw( (1<<8) + reg, ioaddr + MII_ADDRESS );	outw( MIIM_RSTAT, ioaddr + MIIM_COMMAND );	timeout = 100000;	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {		if ( timeout-- < 0 ) {			printk( KERN_INFO "Timed out waiting for MII\n" );			return -1;		}	}	return( inw( ioaddr + MII_READ_DATA ));}static voidwrite_mii( unsigned long ioaddr, int reg, int data ){	int timeout=100000;	printk( KERN_INFO "MII indicator: %02x\n", inw( ioaddr + MII_INDICATOR ));	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {		if ( timeout-- <= 0 ) {			printk( KERN_INFO "Timeout waiting to write to MII\n" );			return;		}		udelay( 10 );	}	outw( (1<<8) + reg, ioaddr + MII_ADDRESS );	outw( data, ioaddr + MII_WRITE_DATA );	return;}#endif /* NCR885E_DEBUG_MII */static void __exit ncr885e_cleanup(void){	if ( root_dev ) {		unregister_netdev( root_dev );		release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE );		kfree( root_dev );		root_dev = NULL;	}  }module_init(ncr885e_probe);module_exit(ncr885e_cleanup);/* * Local variables: *  c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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