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

📄 xircom_tulip_cb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (inl(ioaddr + CSR6) != 0xffffffff)		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;	dev->if_port = tp->saved_if_port;}static intxircom_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct xircom_private *tp = netdev_priv(dev);	int i;	if (xircom_debug > 1)		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",			   dev->name, inl(ioaddr + CSR5));	netif_stop_queue(dev);	if (netif_device_present(dev))		xircom_down(dev);	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_skbuff[i];		tp->rx_skbuff[i] = NULL;		tp->rx_ring[i].status = 0;		/* Not owned by Xircom chip. */		tp->rx_ring[i].length = 0;		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */		if (skb) {			dev_kfree_skb(skb);		}	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (tp->tx_skbuff[i])			dev_kfree_skb(tp->tx_skbuff[i]);		tp->tx_skbuff[i] = NULL;	}	tp->open = 0;	return 0;}static struct net_device_stats *xircom_get_stats(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	long ioaddr = dev->base_addr;	if (netif_device_present(dev))		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;	return &tp->stats;}static int xircom_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd){	struct xircom_private *tp = netdev_priv(dev);	ecmd->supported =			SUPPORTED_10baseT_Half |			SUPPORTED_10baseT_Full |			SUPPORTED_100baseT_Half |			SUPPORTED_100baseT_Full |			SUPPORTED_Autoneg |			SUPPORTED_MII;	ecmd->advertising = ADVERTISED_MII;	if (tp->advertising[0] & ADVERTISE_10HALF)		ecmd->advertising |= ADVERTISED_10baseT_Half;	if (tp->advertising[0] & ADVERTISE_10FULL)		ecmd->advertising |= ADVERTISED_10baseT_Full;	if (tp->advertising[0] & ADVERTISE_100HALF)		ecmd->advertising |= ADVERTISED_100baseT_Half;	if (tp->advertising[0] & ADVERTISE_100FULL)		ecmd->advertising |= ADVERTISED_100baseT_Full;	if (tp->autoneg) {		ecmd->advertising |= ADVERTISED_Autoneg;		ecmd->autoneg = AUTONEG_ENABLE;	} else		ecmd->autoneg = AUTONEG_DISABLE;	ecmd->port = PORT_MII;	ecmd->transceiver = XCVR_INTERNAL;	ecmd->phy_address = tp->phys[0];	ecmd->speed = tp->speed100 ? SPEED_100 : SPEED_10;	ecmd->duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;	ecmd->maxtxpkt = TX_RING_SIZE / 2;	ecmd->maxrxpkt = 0;	return 0;}static int xircom_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){	struct xircom_private *tp = netdev_priv(dev);	u16 autoneg, speed100, full_duplex;	autoneg = (ecmd->autoneg == AUTONEG_ENABLE);	speed100 = (ecmd->speed == SPEED_100);	full_duplex = (ecmd->duplex == DUPLEX_FULL);	tp->autoneg = autoneg;	if (speed100 != tp->speed100 ||	    full_duplex != tp->full_duplex) {		tp->speed100 = speed100;		tp->full_duplex = full_duplex;		/* change advertising bits */		tp->advertising[0] &= ~(ADVERTISE_10HALF |				     ADVERTISE_10FULL |				     ADVERTISE_100HALF |				     ADVERTISE_100FULL |				     ADVERTISE_100BASE4);		if (speed100) {			if (full_duplex)				tp->advertising[0] |= ADVERTISE_100FULL;			else				tp->advertising[0] |= ADVERTISE_100HALF;		} else {			if (full_duplex)				tp->advertising[0] |= ADVERTISE_10FULL;			else				tp->advertising[0] |= ADVERTISE_10HALF;		}	}	check_duplex(dev);	return 0;}static void xircom_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	struct xircom_private *tp = netdev_priv(dev);	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);	strcpy(info->bus_info, pci_name(tp->pdev));}static struct ethtool_ops ops = {	.get_settings = xircom_get_settings,	.set_settings = xircom_set_settings,	.get_drvinfo = xircom_get_drvinfo,};/* Provide ioctl() calls to examine the MII xcvr state. */static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct xircom_private *tp = netdev_priv(dev);	u16 *data = (u16 *)&rq->ifr_ifru;	int phy = tp->phys[0] & 0x1f;	unsigned long flags;	switch(cmd) {	/* Legacy mii-diag interface */	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */		if (tp->mii_cnt)			data[0] = phy;		else			return -ENODEV;		return 0;	case SIOCGMIIREG:		/* Read MII PHY register. */		save_flags(flags);		cli();		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);		restore_flags(flags);		return 0;	case SIOCSMIIREG:		/* Write MII PHY register. */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		save_flags(flags);		cli();		if (data[0] == tp->phys[0]) {			u16 value = data[2];			switch (data[1]) {			case 0:				if (value & (BMCR_RESET | BMCR_ANENABLE))					/* Autonegotiation. */					tp->autoneg = 1;				else {					tp->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;					tp->autoneg = 0;				}				break;			case 4:				tp->advertising[0] = value;				break;			}			check_duplex(dev);		}		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);		restore_flags(flags);		return 0;	default:		return -EOPNOTSUPP;	}	return -EOPNOTSUPP;}/* Set or clear the multicast filter for this adaptor.   Note that we only use exclusion around actually queueing the   new frame, not around filling tp->setup_frame.  This is non-deterministic   when re-entered but still correct. */static void set_rx_mode(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	struct dev_mc_list *mclist;	long ioaddr = dev->base_addr;	int csr6 = inl(ioaddr + CSR6);	u16 *eaddrs, *setup_frm;	u32 tx_flags;	int i;	tp->csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);	csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		tp->csr6 |= PromiscBit;		csr6 |= PromiscBit;		goto out;	}	if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter well -- accept all multicasts. */		tp->csr6 |= AllMultiBit;		csr6 |= AllMultiBit;		goto out;	}	tx_flags = Tx1WholePkt | Tx1SetupPkt | PKT_SETUP_SZ;	/* Note that only the low-address shortword of setup_frame is valid! */	setup_frm = tp->setup_frame;	mclist = dev->mc_list;	/* Fill the first entry with our physical address. */	eaddrs = (u16 *)dev->dev_addr;	*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;	*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;	*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;	if (dev->mc_count > 14) { /* Must use a multicast hash table. */		u32 *hash_table = (u32 *)(tp->setup_frame + 4 * 12);		u32 hash, hash2;		tx_flags |= Tx1HashSetup;		tp->csr6 |= HashFilterBit;		csr6 |= HashFilterBit;		/* Fill the unused 3 entries with the broadcast address.		   At least one entry *must* contain the broadcast address!!!*/		for (i = 0; i < 3; i++) {			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;		}		/* Truly brain-damaged hash filter layout */		/* XXX: not sure if I should take the last or the first 9 bits */		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {			u32 *hptr;			hash = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff;			if (hash < 384) {				hash2 = hash + ((hash >> 4) << 4) +					((hash >> 5) << 5);			} else {				hash -= 384;				hash2 = 64 + hash + (hash >> 4) * 80;			}			hptr = &hash_table[hash2 & ~0x1f];			*hptr |= cpu_to_le32(1 << (hash2 & 0x1f));		}	} else {		/* We have <= 14 mcast addresses so we can use Xircom's		   wonderful 16-address perfect filter. */		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {			eaddrs = (u16 *)mclist->dmi_addr;			*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;			*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;			*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;		}		/* Fill the unused entries with the broadcast address.		   At least one entry *must* contain the broadcast address!!!*/		for (; i < 15; i++) {			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;		}	}	/* Now add this frame to the Tx list. */	if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {		/* Same setup recently queued, we need not add it. */		/* XXX: Huh? All it means is that the Tx list is full...*/	} else {		unsigned long flags;		unsigned int entry;		int dummy = -1;		save_flags(flags); cli();		entry = tp->cur_tx++ % TX_RING_SIZE;		if (entry != 0) {			/* Avoid a chip errata by prefixing a dummy entry. */			tp->tx_skbuff[entry] = NULL;			tp->tx_ring[entry].length =				(entry == TX_RING_SIZE - 1) ? Tx1RingWrap : 0;			tp->tx_ring[entry].buffer1 = 0;			/* race with chip, set Tx0DescOwned later */			dummy = entry;			entry = tp->cur_tx++ % TX_RING_SIZE;		}		tp->tx_skbuff[entry] = NULL;		/* Put the setup frame on the Tx list. */		if (entry == TX_RING_SIZE - 1)			tx_flags |= Tx1RingWrap;		/* Wrap ring. */		tp->tx_ring[entry].length = tx_flags;		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);		tp->tx_ring[entry].status = Tx0DescOwned;		if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {			tp->tx_full = 1;			netif_stop_queue (dev);		}		if (dummy >= 0)			tp->tx_ring[dummy].status = Tx0DescOwned;		restore_flags(flags);		/* Trigger an immediate transmit demand. */		outl(0, ioaddr + CSR1);	}out:	outl_CSR6(csr6, ioaddr);}static struct pci_device_id xircom_pci_table[] = {  { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },  {0},};MODULE_DEVICE_TABLE(pci, xircom_pci_table);#ifdef CONFIG_PMstatic int xircom_suspend(struct pci_dev *pdev, pm_message_t state){	struct net_device *dev = pci_get_drvdata(pdev);	struct xircom_private *tp = netdev_priv(dev);	printk(KERN_INFO "xircom_suspend(%s)\n", dev->name);	if (tp->open)		xircom_down(dev);	pci_save_state(pdev);	pci_disable_device(pdev);	pci_set_power_state(pdev, 3);	return 0;}static int xircom_resume(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	struct xircom_private *tp = netdev_priv(dev);	printk(KERN_INFO "xircom_resume(%s)\n", dev->name);	pci_set_power_state(pdev,0);	pci_enable_device(pdev);	pci_restore_state(pdev);	/* Bring the chip out of sleep mode.	   Caution: Snooze mode does not work with some boards! */	if (xircom_tbl[tp->chip_id].flags & HAS_ACPI)		pci_write_config_dword(tp->pdev, PCI_POWERMGMT, 0);	transceiver_voodoo(dev);	if (xircom_tbl[tp->chip_id].flags & HAS_MII)		check_duplex(dev);	if (tp->open)		xircom_up(dev);	return 0;}#endif /* CONFIG_PM */static void __devexit xircom_remove_one(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name);	unregister_netdev(dev);	pci_release_regions(pdev);	free_netdev(dev);	pci_set_drvdata(pdev, NULL);}static struct pci_driver xircom_driver = {	.name		= DRV_NAME,	.id_table	= xircom_pci_table,	.probe		= xircom_init_one,	.remove		= __devexit_p(xircom_remove_one),#ifdef CONFIG_PM	.suspend	= xircom_suspend,	.resume		= xircom_resume#endif /* CONFIG_PM */};static int __init xircom_init(void){/* when a module, this is printed whether or not devices are found in probe */#ifdef MODULE	printk(version);#endif	return pci_module_init(&xircom_driver);}static void __exit xircom_exit(void){	pci_unregister_driver(&xircom_driver);}module_init(xircom_init)module_exit(xircom_exit)/* * Local variables: *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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