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

📄 tulip_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	iowrite32(0, ioaddr + CSR2);		/* Rx poll demand */	if (tulip_debug > 2) {		printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",			   dev->name, ioread32(ioaddr + CSR0), ioread32(ioaddr + CSR5),			   ioread32(ioaddr + CSR6));	}	/* Set the timer to switch to check for link beat and perhaps switch	   to an alternate media type. */	tp->timer.expires = RUN_AT(next_tick);	add_timer(&tp->timer);#ifdef CONFIG_TULIP_NAPI	init_timer(&tp->oom_timer);        tp->oom_timer.data = (unsigned long)dev;        tp->oom_timer.function = oom_timer;#endif}static inttulip_open(struct net_device *dev){	int retval;	if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)))		return retval;	tulip_init_ring (dev);	tulip_up (dev);	netif_start_queue (dev);	return 0;}static void tulip_tx_timeout(struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->base_addr;	unsigned long flags;	spin_lock_irqsave (&tp->lock, flags);	if (tulip_media_cap[dev->if_port] & MediaIsMII) {		/* Do nothing -- the media monitor should handle this. */		if (tulip_debug > 1)			printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",				   dev->name);	} else if (tp->chip_id == DC21140 || tp->chip_id == DC21142			   || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881			   || tp->chip_id == DM910X) {		printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "			   "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",			   dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),			   ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));		if ( ! tp->medialock  &&  tp->mtable) {			do				--tp->cur_index;			while (tp->cur_index >= 0				   && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media]					   & MediaIsFD));			if (--tp->cur_index < 0) {				/* We start again, but should instead look for default. */				tp->cur_index = tp->mtable->leafcount - 1;			}			tulip_select_media(dev, 0);			printk(KERN_WARNING "%s: transmit timed out, switching to %s "				   "media.\n", dev->name, medianame[dev->if_port]);		}	} else if (tp->chip_id == PNIC2) {		printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "		       "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",		       dev->name, (int)ioread32(ioaddr + CSR5), (int)ioread32(ioaddr + CSR6),		       (int)ioread32(ioaddr + CSR7), (int)ioread32(ioaddr + CSR12));	} else {		printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "			   "%8.8x, resetting...\n",			   dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12));		dev->if_port = 0;	}#if defined(way_too_many_messages)	if (tulip_debug > 3) {		int i;		for (i = 0; i < RX_RING_SIZE; i++) {			u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);			int j;			printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "				   "%2.2x %2.2x %2.2x.\n",				   i, (unsigned int)tp->rx_ring[i].status,				   (unsigned int)tp->rx_ring[i].length,				   (unsigned int)tp->rx_ring[i].buffer1,				   (unsigned int)tp->rx_ring[i].buffer2,				   buf[0], buf[1], buf[2]);			for (j = 0; buf[j] != 0xee && j < 1600; j++)				if (j < 100) printk(" %2.2x", buf[j]);			printk(" j=%d.\n", j);		}		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);		for (i = 0; i < RX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);		for (i = 0; i < TX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);		printk("\n");	}#endif	/* Stop and restart the chip's Tx processes . */	tulip_restart_rxtx(tp);	/* Trigger an immediate transmit demand. */	iowrite32(0, ioaddr + CSR1);	tp->stats.tx_errors++;	spin_unlock_irqrestore (&tp->lock, flags);	dev->trans_start = jiffies;	netif_wake_queue (dev);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void tulip_init_ring(struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	int i;	tp->susp_rx = 0;	tp->ttimer = 0;	tp->nir = 0;	for (i = 0; i < RX_RING_SIZE; i++) {		tp->rx_ring[i].status = 0x00000000;		tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);		tp->rx_ring[i].buffer2 = cpu_to_le32(tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * (i + 1));		tp->rx_buffers[i].skb = NULL;		tp->rx_buffers[i].mapping = 0;	}	/* Mark the last entry as wrapping the ring. */	tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);	tp->rx_ring[i-1].buffer2 = cpu_to_le32(tp->rx_ring_dma);	for (i = 0; i < RX_RING_SIZE; i++) {		dma_addr_t mapping;		/* Note the receive buffer must be longword aligned.		   dev_alloc_skb() provides 16 byte alignment.  But do *not*		   use skb_reserve() to align the IP header! */		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);		tp->rx_buffers[i].skb = skb;		if (skb == NULL)			break;		mapping = pci_map_single(tp->pdev, skb->data,					 PKT_BUF_SZ, PCI_DMA_FROMDEVICE);		tp->rx_buffers[i].mapping = mapping;		skb->dev = dev;			/* Mark as being used by this device. */		tp->rx_ring[i].status = cpu_to_le32(DescOwned);	/* Owned by Tulip chip */		tp->rx_ring[i].buffer1 = cpu_to_le32(mapping);	}	tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);	/* The Tx buffer descriptor is filled in as needed, but we	   do need to clear the ownership bit. */	for (i = 0; i < TX_RING_SIZE; i++) {		tp->tx_buffers[i].skb = NULL;		tp->tx_buffers[i].mapping = 0;		tp->tx_ring[i].status = 0x00000000;		tp->tx_ring[i].buffer2 = cpu_to_le32(tp->tx_ring_dma + sizeof(struct tulip_tx_desc) * (i + 1));	}	tp->tx_ring[i-1].buffer2 = cpu_to_le32(tp->tx_ring_dma);}static inttulip_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	int entry;	u32 flag;	dma_addr_t mapping;	spin_lock_irq(&tp->lock);	/* Calculate the next Tx descriptor entry. */	entry = tp->cur_tx % TX_RING_SIZE;	tp->tx_buffers[entry].skb = skb;	mapping = pci_map_single(tp->pdev, skb->data,				 skb->len, PCI_DMA_TODEVICE);	tp->tx_buffers[entry].mapping = mapping;	tp->tx_ring[entry].buffer1 = cpu_to_le32(mapping);	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */		flag = 0x60000000; /* No interrupt */	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {		flag = 0xe0000000; /* Tx-done intr. */	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {		flag = 0x60000000; /* No Tx-done intr. */	} else {		/* Leave room for set_rx_mode() to fill entries. */		flag = 0xe0000000; /* Tx-done intr. */		netif_stop_queue(dev);	}	if (entry == TX_RING_SIZE-1)		flag = 0xe0000000 | DESC_RING_WRAP;	tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);	/* if we were using Transmit Automatic Polling, we would need a	 * wmb() here. */	tp->tx_ring[entry].status = cpu_to_le32(DescOwned);	wmb();	tp->cur_tx++;	/* Trigger an immediate transmit demand. */	iowrite32(0, tp->base_addr + CSR1);	spin_unlock_irq(&tp->lock);	dev->trans_start = jiffies;	return 0;}static void tulip_clean_tx_ring(struct tulip_private *tp){	unsigned int dirty_tx;	for (dirty_tx = tp->dirty_tx ; tp->cur_tx - dirty_tx > 0;		dirty_tx++) {		int entry = dirty_tx % TX_RING_SIZE;		int status = le32_to_cpu(tp->tx_ring[entry].status);		if (status < 0) {			tp->stats.tx_errors++;	/* It wasn't Txed */			tp->tx_ring[entry].status = 0;		}		/* Check for Tx filter setup frames. */		if (tp->tx_buffers[entry].skb == NULL) {			/* test because dummy frames not mapped */			if (tp->tx_buffers[entry].mapping)				pci_unmap_single(tp->pdev,					tp->tx_buffers[entry].mapping,					sizeof(tp->setup_frame),					PCI_DMA_TODEVICE);			continue;		}		pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,				tp->tx_buffers[entry].skb->len,				PCI_DMA_TODEVICE);		/* Free the original skb. */		dev_kfree_skb_irq(tp->tx_buffers[entry].skb);		tp->tx_buffers[entry].skb = NULL;		tp->tx_buffers[entry].mapping = 0;	}}static void tulip_down (struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->base_addr;	unsigned long flags;	del_timer_sync (&tp->timer);#ifdef CONFIG_TULIP_NAPI	del_timer_sync (&tp->oom_timer);#endif	spin_lock_irqsave (&tp->lock, flags);	/* Disable interrupts by clearing the interrupt mask. */	iowrite32 (0x00000000, ioaddr + CSR7);	/* Stop the Tx and Rx processes. */	tulip_stop_rxtx(tp);	/* prepare receive buffers */	tulip_refill_rx(dev);	/* release any unconsumed transmit buffers */	tulip_clean_tx_ring(tp);	if (ioread32 (ioaddr + CSR6) != 0xffffffff)		tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff;	spin_unlock_irqrestore (&tp->lock, flags);	init_timer(&tp->timer);	tp->timer.data = (unsigned long)dev;	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;	dev->if_port = tp->saved_if_port;	/* Leave the driver in snooze, not sleep, mode. */	tulip_set_power_state (tp, 0, 1);}static int tulip_close (struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->base_addr;	int i;	netif_stop_queue (dev);	tulip_down (dev);	if (tulip_debug > 1)		printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",			dev->name, ioread32 (ioaddr + CSR5));	free_irq (dev->irq, dev);	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = tp->rx_buffers[i].skb;		dma_addr_t mapping = tp->rx_buffers[i].mapping;		tp->rx_buffers[i].skb = NULL;		tp->rx_buffers[i].mapping = 0;		tp->rx_ring[i].status = 0;	/* Not owned by Tulip chip. */		tp->rx_ring[i].length = 0;		tp->rx_ring[i].buffer1 = 0xBADF00D0;	/* An invalid address. */		if (skb) {			pci_unmap_single(tp->pdev, mapping, PKT_BUF_SZ,					 PCI_DMA_FROMDEVICE);			dev_kfree_skb (skb);		}	}	for (i = 0; i < TX_RING_SIZE; i++) {		struct sk_buff *skb = tp->tx_buffers[i].skb;		if (skb != NULL) {			pci_unmap_single(tp->pdev, tp->tx_buffers[i].mapping,					 skb->len, PCI_DMA_TODEVICE);			dev_kfree_skb (skb);		}		tp->tx_buffers[i].skb = NULL;		tp->tx_buffers[i].mapping = 0;	}	return 0;}static struct net_device_stats *tulip_get_stats(struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->base_addr;	if (netif_running(dev)) {		unsigned long flags;		spin_lock_irqsave (&tp->lock, flags);		tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;		spin_unlock_irqrestore(&tp->lock, flags);	}	return &tp->stats;}static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	struct tulip_private *np = netdev_priv(dev);	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);	strcpy(info->bus_info, pci_name(np->pdev));}static struct ethtool_ops ops = {	.get_drvinfo = tulip_get_drvinfo};/* Provide ioctl() calls to examine the MII xcvr state. */static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){	struct tulip_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->base_addr;	struct mii_ioctl_data *data = if_mii(rq);	const unsigned int phy_idx = 0;	int phy = tp->phys[phy_idx] & 0x1f;	unsigned int regnum = data->reg_num;	switch (cmd) {	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */		if (tp->mii_cnt)			data->phy_id = phy;		else if (tp->flags & HAS_NWAY)			data->phy_id = 32;		else if (tp->chip_id == COMET)			data->phy_id = 1;		else			return -ENODEV;	case SIOCGMIIREG:		/* Read MII PHY register. */		if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) {			int csr12 = ioread32 (ioaddr + CSR12);			int csr14 = ioread32 (ioaddr + CSR14);			switch (regnum) {			case 0:                                if (((csr14<<5) & 0x1000) ||                                        (dev->if_port == 5 && tp->nwayset))                                        data->val_out = 0x1000;                                else                                        data->val_out = (tulip_media_cap[dev->if_port]&MediaIs100 ? 0x2000 : 0)                                                | (tulip_media_cap[dev->if_port]&MediaIsFD ? 0x0100 : 0);				break;			case 1:                                data->val_out =					0x1848 +					((csr12&0x7000) == 0x5000 ? 0x20 : 0) +					((csr12&0x06) == 6 ? 0 : 4);                                data->val_out |= 0x6048;				break;			case 4:                                /* Advertised value, bogus 10baseTx-FD value from CSR6. */                                data->val_out =					((ioread32(ioaddr + CSR6) >> 3) & 0x0040) +					((csr14 >> 1) & 0x20) + 1;                                data->val_out |= ((csr14 >> 9) & 0x03C0);				break;			case 5: data->val_out = tp->lpar; break;			default: data->val_out = 0; break;			}		} else {			data->val_out = tulip_mdio_read (dev, data->phy_id & 0x1f, regnum);		}		return 0;	case SIOCSMIIREG:		/* Write MII PHY register. */		if (!capable (CAP_NET_ADMIN))			return -EPERM;		if (regnum & ~0x1f)			return -EINVAL;		if (data->phy_id == phy) {			u16 value = data->val_in;			switch (regnum) {			case 0:	/* Check for autonegotiation on or reset. */				tp->full_duplex_lock = (value & 0x9000) ? 0 : 1;				if (tp->full_duplex_lock)					tp->full_duplex = (value & 0x0100) ? 1 : 0;				break;			case 4:				tp->advertising[phy_idx] =				tp->mii_advertise = data->val_in;				break;			}		}		if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) {			u16 value = data->val_in;			if (regnum == 0) {			  if ((value & 0x1200) == 0x1200) {			    if (tp->chip_id == PNIC2) {                                   pnic2_start_nway (dev);                            } else {				   t21142_start_nway (dev);                            }			  }			} else if (regnum == 4)				tp->sym_advertise = value;		} else {

⌨️ 快捷键说明

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