[CASSINI]: Convert to ethtool_ops
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									325ed82393
								
							
						
					
					
						commit
						a232f76732
					
				| @ -4423,18 +4423,14 @@ static struct { | ||||
| #define CAS_REG_LEN 	(sizeof(ethtool_register_table)/sizeof(int)) | ||||
| #define CAS_MAX_REGS 	(sizeof (u32)*CAS_REG_LEN) | ||||
| 
 | ||||
| static u8 *cas_get_regs(struct cas *cp) | ||||
| static void cas_read_regs(struct cas *cp, u8 *ptr, int len) | ||||
| { | ||||
| 	u8 *ptr = kmalloc(CAS_MAX_REGS, GFP_KERNEL); | ||||
| 	u8 *p; | ||||
| 	int i; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if (!ptr) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&cp->lock, flags); | ||||
| 	for (i = 0, p = ptr; i < CAS_REG_LEN ; i ++, p += sizeof(u32)) { | ||||
| 	for (i = 0, p = ptr; i < len ; i ++, p += sizeof(u32)) { | ||||
| 		u16 hval; | ||||
| 		u32 val; | ||||
| 		if (ethtool_register_table[i].offsets < 0) { | ||||
| @ -4447,8 +4443,6 @@ static u8 *cas_get_regs(struct cas *cp) | ||||
| 		memcpy(p, (u8 *)&val, sizeof(u32)); | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 
 | ||||
| 	return ptr; | ||||
| } | ||||
| 
 | ||||
| static struct net_device_stats *cas_get_stats(struct net_device *dev) | ||||
| @ -4561,316 +4555,251 @@ static void cas_set_multicast(struct net_device *dev) | ||||
| 	spin_unlock_irqrestore(&cp->lock, flags); | ||||
| } | ||||
| 
 | ||||
| /* Eventually add support for changing the advertisement
 | ||||
|  * on autoneg. | ||||
|  */ | ||||
| static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) | ||||
| static void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	strncpy(info->driver, DRV_MODULE_NAME, ETHTOOL_BUSINFO_LEN); | ||||
| 	strncpy(info->version, DRV_MODULE_VERSION, ETHTOOL_BUSINFO_LEN); | ||||
| 	info->fw_version[0] = '\0'; | ||||
| 	strncpy(info->bus_info, pci_name(cp->pdev), ETHTOOL_BUSINFO_LEN); | ||||
| 	info->regdump_len = cp->casreg_len < CAS_MAX_REGS ? | ||||
| 		cp->casreg_len : CAS_MAX_REGS; | ||||
| 	info->n_stats = CAS_NUM_STAT_KEYS; | ||||
| } | ||||
| 
 | ||||
| static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	u16 bmcr; | ||||
| 	int full_duplex, speed, pause; | ||||
| 	struct ethtool_cmd ecmd; | ||||
| 	unsigned long flags; | ||||
| 	enum link_state linkstate = link_up; | ||||
| 
 | ||||
| 	if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) | ||||
| 		return -EFAULT; | ||||
| 		 | ||||
| 	switch(ecmd.cmd) { | ||||
|         case ETHTOOL_GDRVINFO: { | ||||
| 		struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO }; | ||||
| 
 | ||||
| 		strncpy(info.driver, DRV_MODULE_NAME, | ||||
| 			ETHTOOL_BUSINFO_LEN); | ||||
| 		strncpy(info.version, DRV_MODULE_VERSION, | ||||
| 			ETHTOOL_BUSINFO_LEN); | ||||
| 		info.fw_version[0] = '\0'; | ||||
| 		strncpy(info.bus_info, pci_name(cp->pdev), | ||||
| 			ETHTOOL_BUSINFO_LEN); | ||||
| 		info.regdump_len = cp->casreg_len < CAS_MAX_REGS ? | ||||
| 			cp->casreg_len : CAS_MAX_REGS; | ||||
| 		info.n_stats = CAS_NUM_STAT_KEYS; | ||||
| 		if (copy_to_user(ep_user, &info, sizeof(info))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		return 0; | ||||
| 	cmd->advertising = 0; | ||||
| 	cmd->supported = SUPPORTED_Autoneg; | ||||
| 	if (cp->cas_flags & CAS_FLAG_1000MB_CAP) { | ||||
| 		cmd->supported |= SUPPORTED_1000baseT_Full; | ||||
| 		cmd->advertising |= ADVERTISED_1000baseT_Full; | ||||
| 	} | ||||
| 
 | ||||
| 	case ETHTOOL_GSET: | ||||
| 		ecmd.advertising = 0; | ||||
| 		ecmd.supported = SUPPORTED_Autoneg; | ||||
| 		if (cp->cas_flags & CAS_FLAG_1000MB_CAP) { | ||||
| 			ecmd.supported |= SUPPORTED_1000baseT_Full; | ||||
| 			ecmd.advertising |= ADVERTISED_1000baseT_Full; | ||||
| 	/* Record PHY settings if HW is on. */ | ||||
| 	spin_lock_irqsave(&cp->lock, flags); | ||||
| 	bmcr = 0; | ||||
| 	linkstate = cp->lstate; | ||||
| 	if (CAS_PHY_MII(cp->phy_type)) { | ||||
| 		cmd->port = PORT_MII; | ||||
| 		cmd->transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ? | ||||
| 			XCVR_INTERNAL : XCVR_EXTERNAL; | ||||
| 		cmd->phy_address = cp->phy_addr; | ||||
| 		cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII | | ||||
| 			ADVERTISED_10baseT_Half |  | ||||
| 			ADVERTISED_10baseT_Full |  | ||||
| 			ADVERTISED_100baseT_Half |  | ||||
| 			ADVERTISED_100baseT_Full; | ||||
| 
 | ||||
| 		cmd->supported |= | ||||
| 			(SUPPORTED_10baseT_Half |  | ||||
| 			 SUPPORTED_10baseT_Full | | ||||
| 			 SUPPORTED_100baseT_Half |  | ||||
| 			 SUPPORTED_100baseT_Full | | ||||
| 			 SUPPORTED_TP | SUPPORTED_MII); | ||||
| 
 | ||||
| 		if (cp->hw_running) { | ||||
| 			cas_mif_poll(cp, 0); | ||||
| 			bmcr = cas_phy_read(cp, MII_BMCR); | ||||
| 			cas_read_mii_link_mode(cp, &full_duplex,  | ||||
| 					       &speed, &pause); | ||||
| 			cas_mif_poll(cp, 1); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Record PHY settings if HW is on. */ | ||||
| 		spin_lock_irqsave(&cp->lock, flags); | ||||
| 		bmcr = 0; | ||||
| 		linkstate = cp->lstate; | ||||
| 		if (CAS_PHY_MII(cp->phy_type)) { | ||||
| 			ecmd.port = PORT_MII; | ||||
| 			ecmd.transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ? | ||||
| 				XCVR_INTERNAL : XCVR_EXTERNAL; | ||||
| 			ecmd.phy_address = cp->phy_addr; | ||||
| 			ecmd.advertising |= ADVERTISED_TP | ADVERTISED_MII | | ||||
| 				ADVERTISED_10baseT_Half |  | ||||
| 				ADVERTISED_10baseT_Full |  | ||||
| 				ADVERTISED_100baseT_Half |  | ||||
| 				ADVERTISED_100baseT_Full; | ||||
| 	} else { | ||||
| 		cmd->port = PORT_FIBRE; | ||||
| 		cmd->transceiver = XCVR_INTERNAL; | ||||
| 		cmd->phy_address = 0; | ||||
| 		cmd->supported   |= SUPPORTED_FIBRE; | ||||
| 		cmd->advertising |= ADVERTISED_FIBRE; | ||||
| 
 | ||||
| 			ecmd.supported |= | ||||
| 				(SUPPORTED_10baseT_Half |  | ||||
| 				 SUPPORTED_10baseT_Full | | ||||
| 				 SUPPORTED_100baseT_Half |  | ||||
| 				 SUPPORTED_100baseT_Full | | ||||
| 				 SUPPORTED_TP | SUPPORTED_MII); | ||||
| 
 | ||||
| 			if (cp->hw_running) { | ||||
| 				cas_mif_poll(cp, 0); | ||||
| 				bmcr = cas_phy_read(cp, MII_BMCR); | ||||
| 				cas_read_mii_link_mode(cp, &full_duplex,  | ||||
| 						       &speed, &pause); | ||||
| 				cas_mif_poll(cp, 1); | ||||
| 			} | ||||
| 
 | ||||
| 		} else { | ||||
| 			ecmd.port = PORT_FIBRE; | ||||
| 			ecmd.transceiver = XCVR_INTERNAL; | ||||
| 			ecmd.phy_address = 0; | ||||
| 			ecmd.supported   |= SUPPORTED_FIBRE; | ||||
| 			ecmd.advertising |= ADVERTISED_FIBRE; | ||||
| 
 | ||||
| 			if (cp->hw_running) { | ||||
| 				/* pcs uses the same bits as mii */  | ||||
| 				bmcr = readl(cp->regs + REG_PCS_MII_CTRL); | ||||
| 				cas_read_pcs_link_mode(cp, &full_duplex,  | ||||
| 						       &speed, &pause); | ||||
| 			} | ||||
| 		if (cp->hw_running) { | ||||
| 			/* pcs uses the same bits as mii */  | ||||
| 			bmcr = readl(cp->regs + REG_PCS_MII_CTRL); | ||||
| 			cas_read_pcs_link_mode(cp, &full_duplex,  | ||||
| 					       &speed, &pause); | ||||
| 		} | ||||
| 		spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 
 | ||||
| 		if (bmcr & BMCR_ANENABLE) { | ||||
| 			ecmd.advertising |= ADVERTISED_Autoneg; | ||||
| 			ecmd.autoneg = AUTONEG_ENABLE; | ||||
| 			ecmd.speed = ((speed == 10) ? | ||||
| 				      SPEED_10 : | ||||
| 				      ((speed == 1000) ? | ||||
| 				       SPEED_1000 : SPEED_100)); | ||||
| 			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; | ||||
| 	if (bmcr & BMCR_ANENABLE) { | ||||
| 		cmd->advertising |= ADVERTISED_Autoneg; | ||||
| 		cmd->autoneg = AUTONEG_ENABLE; | ||||
| 		cmd->speed = ((speed == 10) ? | ||||
| 			      SPEED_10 : | ||||
| 			      ((speed == 1000) ? | ||||
| 			       SPEED_1000 : SPEED_100)); | ||||
| 		cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; | ||||
| 	} else { | ||||
| 		cmd->autoneg = AUTONEG_DISABLE; | ||||
| 		cmd->speed = | ||||
| 			(bmcr & CAS_BMCR_SPEED1000) ? | ||||
| 			SPEED_1000 :  | ||||
| 			((bmcr & BMCR_SPEED100) ? SPEED_100:  | ||||
| 			 SPEED_10); | ||||
| 		cmd->duplex = | ||||
| 			(bmcr & BMCR_FULLDPLX) ? | ||||
| 			DUPLEX_FULL : DUPLEX_HALF; | ||||
| 	} | ||||
| 	if (linkstate != link_up) { | ||||
| 		/* Force these to "unknown" if the link is not up and
 | ||||
| 		 * autonogotiation in enabled. We can set the link  | ||||
| 		 * speed to 0, but not cmd->duplex, | ||||
| 		 * because its legal values are 0 and 1.  Ethtool will | ||||
| 		 * print the value reported in parentheses after the | ||||
| 		 * word "Unknown" for unrecognized values. | ||||
| 		 * | ||||
| 		 * If in forced mode, we report the speed and duplex | ||||
| 		 * settings that we configured. | ||||
| 		 */ | ||||
| 		if (cp->link_cntl & BMCR_ANENABLE) { | ||||
| 			cmd->speed = 0; | ||||
| 			cmd->duplex = 0xff; | ||||
| 		} else { | ||||
| 			ecmd.autoneg = AUTONEG_DISABLE; | ||||
| 			ecmd.speed = | ||||
| 				(bmcr & CAS_BMCR_SPEED1000) ? | ||||
| 				SPEED_1000 :  | ||||
| 				((bmcr & BMCR_SPEED100) ? SPEED_100:  | ||||
| 				 SPEED_10); | ||||
| 			ecmd.duplex = | ||||
| 				(bmcr & BMCR_FULLDPLX) ? | ||||
| 			cmd->speed = SPEED_10; | ||||
| 			if (cp->link_cntl & BMCR_SPEED100) { | ||||
| 				cmd->speed = SPEED_100; | ||||
| 			} else if (cp->link_cntl & CAS_BMCR_SPEED1000) { | ||||
| 				cmd->speed = SPEED_1000; | ||||
| 			} | ||||
| 			cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)? | ||||
| 				DUPLEX_FULL : DUPLEX_HALF; | ||||
| 		} | ||||
| 		if (linkstate != link_up) { | ||||
| 			/* Force these to "unknown" if the link is not up and
 | ||||
| 			 * autonogotiation in enabled. We can set the link  | ||||
| 			 * speed to 0, but not ecmd.duplex, | ||||
| 			 * because its legal values are 0 and 1.  Ethtool will | ||||
| 			 * print the value reported in parentheses after the | ||||
| 			 * word "Unknown" for unrecognized values. | ||||
| 			 * | ||||
| 			 * If in forced mode, we report the speed and duplex | ||||
| 			 * settings that we configured. | ||||
| 			 */ | ||||
| 			if (cp->link_cntl & BMCR_ANENABLE) { | ||||
| 				ecmd.speed = 0; | ||||
| 				ecmd.duplex = 0xff; | ||||
| 			} else { | ||||
| 				ecmd.speed = SPEED_10; | ||||
| 				if (cp->link_cntl & BMCR_SPEED100) { | ||||
| 					ecmd.speed = SPEED_100; | ||||
| 				} else if (cp->link_cntl & CAS_BMCR_SPEED1000) { | ||||
| 					ecmd.speed = SPEED_1000; | ||||
| 				} | ||||
| 				ecmd.duplex = (cp->link_cntl & BMCR_FULLDPLX)? | ||||
| 					DUPLEX_FULL : DUPLEX_HALF; | ||||
| 			} | ||||
| 		} | ||||
| 		if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) | ||||
| 			return -EFAULT; | ||||
| 		return 0; | ||||
| 
 | ||||
| 	case ETHTOOL_SSET: | ||||
| 		if (!capable(CAP_NET_ADMIN)) | ||||
| 			return -EPERM; | ||||
| 
 | ||||
| 		/* Verify the settings we care about. */ | ||||
| 		if (ecmd.autoneg != AUTONEG_ENABLE && | ||||
| 		    ecmd.autoneg != AUTONEG_DISABLE) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		if (ecmd.autoneg == AUTONEG_DISABLE && | ||||
| 		    ((ecmd.speed != SPEED_1000 && | ||||
| 		      ecmd.speed != SPEED_100 && | ||||
| 		      ecmd.speed != SPEED_10) || | ||||
| 		     (ecmd.duplex != DUPLEX_HALF && | ||||
| 		      ecmd.duplex != DUPLEX_FULL))) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		/* Apply settings and restart link process. */ | ||||
| 		spin_lock_irqsave(&cp->lock, flags); | ||||
| 		cas_begin_auto_negotiation(cp, &ecmd); | ||||
| 		spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 		return 0; | ||||
| 
 | ||||
| 	case ETHTOOL_NWAY_RST: | ||||
| 		if ((cp->link_cntl & BMCR_ANENABLE) == 0) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		/* Restart link process. */ | ||||
| 		spin_lock_irqsave(&cp->lock, flags); | ||||
| 		cas_begin_auto_negotiation(cp, NULL); | ||||
| 		spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 
 | ||||
| 		return 0; | ||||
| 
 | ||||
| 	case ETHTOOL_GWOL: | ||||
| 	case ETHTOOL_SWOL: | ||||
| 		break; /* doesn't exist */ | ||||
| 
 | ||||
| 	/* get link status */ | ||||
| 	case ETHTOOL_GLINK: { | ||||
| 		struct ethtool_value edata = { .cmd = ETHTOOL_GLINK }; | ||||
| 
 | ||||
| 		edata.data = (cp->lstate == link_up); | ||||
| 		if (copy_to_user(ep_user, &edata, sizeof(edata))) | ||||
| 			return -EFAULT; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* get message-level */ | ||||
| 	case ETHTOOL_GMSGLVL: { | ||||
| 		struct ethtool_value edata = { .cmd = ETHTOOL_GMSGLVL }; | ||||
| 
 | ||||
| 		edata.data = cp->msg_enable; | ||||
| 		if (copy_to_user(ep_user, &edata, sizeof(edata))) | ||||
| 			return -EFAULT; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* set message-level */ | ||||
| 	case ETHTOOL_SMSGLVL: { | ||||
| 		struct ethtool_value edata; | ||||
| 
 | ||||
| 		if (!capable(CAP_NET_ADMIN)) { | ||||
| 			return (-EPERM); | ||||
| 		} | ||||
| 		if (copy_from_user(&edata, ep_user, sizeof(edata))) | ||||
| 			return -EFAULT; | ||||
| 		cp->msg_enable = edata.data; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	case ETHTOOL_GREGS: { | ||||
| 		struct ethtool_regs edata; | ||||
| 		u8 *ptr; | ||||
| 		int len = cp->casreg_len < CAS_MAX_REGS ? | ||||
| 			cp->casreg_len: CAS_MAX_REGS; | ||||
| 
 | ||||
| 		if (copy_from_user(&edata, ep_user, sizeof (edata))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		if (edata.len > len) | ||||
| 			edata.len = len; | ||||
| 		edata.version = 0; | ||||
| 		if (copy_to_user (ep_user, &edata, sizeof(edata))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		/* cas_get_regs handles locks (cp->lock).  */ | ||||
| 		ptr = cas_get_regs(cp); | ||||
| 		if (ptr == NULL) | ||||
| 			return -ENOMEM; | ||||
| 		if (copy_to_user(ep_user + sizeof (edata), ptr, edata.len)) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		kfree(ptr); | ||||
| 		return (0); | ||||
| 	} | ||||
| 	case ETHTOOL_GSTRINGS: { | ||||
| 		struct ethtool_gstrings edata; | ||||
| 		int len; | ||||
| 
 | ||||
| 		if (copy_from_user(&edata, ep_user, sizeof(edata))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		len = edata.len; | ||||
| 		switch(edata.string_set) { | ||||
| 		case ETH_SS_STATS: | ||||
| 			edata.len = (len < CAS_NUM_STAT_KEYS) ? | ||||
| 				len : CAS_NUM_STAT_KEYS; | ||||
| 			if (copy_to_user(ep_user, &edata, sizeof(edata))) | ||||
| 				return -EFAULT; | ||||
| 
 | ||||
| 			if (copy_to_user(ep_user + sizeof(edata), | ||||
| 					 ðtool_cassini_statnames,  | ||||
| 					 (edata.len * ETH_GSTRING_LEN))) | ||||
| 				return -EFAULT; | ||||
| 			return 0; | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
| 	case ETHTOOL_GSTATS: { | ||||
| 		int i = 0; | ||||
| 		u64 *tmp; | ||||
| 		struct ethtool_stats edata; | ||||
| 		struct net_device_stats *stats; | ||||
| 		int len; | ||||
| 
 | ||||
| 		if (copy_from_user(&edata, ep_user, sizeof(edata))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		len = edata.n_stats; | ||||
| 		stats = cas_get_stats(cp->dev); | ||||
| 		edata.cmd = ETHTOOL_GSTATS; | ||||
| 		edata.n_stats = (len < CAS_NUM_STAT_KEYS) ? | ||||
| 			len : CAS_NUM_STAT_KEYS; | ||||
| 		if (copy_to_user(ep_user, &edata, sizeof (edata))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		tmp = kmalloc(sizeof(u64)*CAS_NUM_STAT_KEYS, GFP_KERNEL); | ||||
| 		if (tmp) { | ||||
| 			tmp[i++] = stats->collisions; | ||||
| 			tmp[i++] = stats->rx_bytes; | ||||
| 			tmp[i++] = stats->rx_crc_errors; | ||||
| 			tmp[i++] = stats->rx_dropped; | ||||
| 			tmp[i++] = stats->rx_errors; | ||||
| 			tmp[i++] = stats->rx_fifo_errors; | ||||
| 			tmp[i++] = stats->rx_frame_errors; | ||||
| 			tmp[i++] = stats->rx_length_errors; | ||||
| 			tmp[i++] = stats->rx_over_errors; | ||||
| 			tmp[i++] = stats->rx_packets; | ||||
| 			tmp[i++] = stats->tx_aborted_errors; | ||||
| 			tmp[i++] = stats->tx_bytes; | ||||
| 			tmp[i++] = stats->tx_dropped; | ||||
| 			tmp[i++] = stats->tx_errors; | ||||
| 			tmp[i++] = stats->tx_fifo_errors; | ||||
| 			tmp[i++] = stats->tx_packets; | ||||
| 			BUG_ON(i != CAS_NUM_STAT_KEYS); | ||||
| 
 | ||||
| 			i = copy_to_user(ep_user + sizeof(edata), | ||||
| 					 tmp, sizeof(u64)*edata.n_stats); | ||||
| 			kfree(tmp); | ||||
| 		} else { | ||||
| 			return -ENOMEM; | ||||
| 		} | ||||
| 		if (i) | ||||
| 			return -EFAULT; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	} | ||||
| 
 | ||||
| 	return -EOPNOTSUPP; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	/* Verify the settings we care about. */ | ||||
| 	if (cmd->autoneg != AUTONEG_ENABLE && | ||||
| 	    cmd->autoneg != AUTONEG_DISABLE) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (cmd->autoneg == AUTONEG_DISABLE && | ||||
| 	    ((cmd->speed != SPEED_1000 && | ||||
| 	      cmd->speed != SPEED_100 && | ||||
| 	      cmd->speed != SPEED_10) || | ||||
| 	     (cmd->duplex != DUPLEX_HALF && | ||||
| 	      cmd->duplex != DUPLEX_FULL))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Apply settings and restart link process. */ | ||||
| 	spin_lock_irqsave(&cp->lock, flags); | ||||
| 	cas_begin_auto_negotiation(cp, cmd); | ||||
| 	spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cas_nway_reset(struct net_device *dev) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if ((cp->link_cntl & BMCR_ANENABLE) == 0) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Restart link process. */ | ||||
| 	spin_lock_irqsave(&cp->lock, flags); | ||||
| 	cas_begin_auto_negotiation(cp, NULL); | ||||
| 	spin_unlock_irqrestore(&cp->lock, flags); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static u32 cas_get_link(struct net_device *dev) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	return cp->lstate == link_up; | ||||
| } | ||||
| 
 | ||||
| static u32 cas_get_msglevel(struct net_device *dev) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	return cp->msg_enable; | ||||
| } | ||||
| 
 | ||||
| static void cas_set_msglevel(struct net_device *dev, u32 value) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	cp->msg_enable = value; | ||||
| } | ||||
| 
 | ||||
| static int cas_get_regs_len(struct net_device *dev) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	return cp->casreg_len < CAS_MAX_REGS ? cp->casreg_len: CAS_MAX_REGS; | ||||
| } | ||||
| 
 | ||||
| static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs, | ||||
| 			     void *p) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	regs->version = 0; | ||||
| 	/* cas_read_regs handles locks (cp->lock).  */ | ||||
| 	cas_read_regs(cp, p, regs->len / sizeof(u32)); | ||||
| } | ||||
| 
 | ||||
| static int cas_get_stats_count(struct net_device *dev) | ||||
| { | ||||
| 	return CAS_NUM_STAT_KEYS; | ||||
| } | ||||
| 
 | ||||
| static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data) | ||||
| { | ||||
| 	 memcpy(data, ðtool_cassini_statnames,  | ||||
| 					 CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN); | ||||
| } | ||||
| 
 | ||||
| static void cas_get_ethtool_stats(struct net_device *dev, | ||||
| 				      struct ethtool_stats *estats, u64 *data) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| 	struct net_device_stats *stats = cas_get_stats(cp->dev); | ||||
| 	int i = 0; | ||||
| 	data[i++] = stats->collisions; | ||||
| 	data[i++] = stats->rx_bytes; | ||||
| 	data[i++] = stats->rx_crc_errors; | ||||
| 	data[i++] = stats->rx_dropped; | ||||
| 	data[i++] = stats->rx_errors; | ||||
| 	data[i++] = stats->rx_fifo_errors; | ||||
| 	data[i++] = stats->rx_frame_errors; | ||||
| 	data[i++] = stats->rx_length_errors; | ||||
| 	data[i++] = stats->rx_over_errors; | ||||
| 	data[i++] = stats->rx_packets; | ||||
| 	data[i++] = stats->tx_aborted_errors; | ||||
| 	data[i++] = stats->tx_bytes; | ||||
| 	data[i++] = stats->tx_dropped; | ||||
| 	data[i++] = stats->tx_errors; | ||||
| 	data[i++] = stats->tx_fifo_errors; | ||||
| 	data[i++] = stats->tx_packets; | ||||
| 	BUG_ON(i != CAS_NUM_STAT_KEYS); | ||||
| } | ||||
| 
 | ||||
| static struct ethtool_ops cas_ethtool_ops = { | ||||
| 	.get_drvinfo		= cas_get_drvinfo, | ||||
| 	.get_settings		= cas_get_settings, | ||||
| 	.set_settings		= cas_set_settings, | ||||
| 	.nway_reset		= cas_nway_reset, | ||||
| 	.get_link		= cas_get_link, | ||||
| 	.get_msglevel		= cas_get_msglevel, | ||||
| 	.set_msglevel		= cas_set_msglevel, | ||||
| 	.get_regs_len		= cas_get_regs_len, | ||||
| 	.get_regs		= cas_get_regs, | ||||
| 	.get_stats_count	= cas_get_stats_count, | ||||
| 	.get_strings		= cas_get_strings, | ||||
| 	.get_ethtool_stats	= cas_get_ethtool_stats, | ||||
| }; | ||||
| 
 | ||||
| static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||
| { | ||||
| 	struct cas *cp = netdev_priv(dev); | ||||
| @ -4883,10 +4812,6 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||
| 	 */ | ||||
| 	down(&cp->pm_sem); | ||||
| 	switch (cmd) { | ||||
| 	case SIOCETHTOOL: | ||||
| 		rc = cas_ethtool_ioctl(dev, ifr->ifr_data); | ||||
| 		break; | ||||
| 
 | ||||
| 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */ | ||||
| 		data->phy_id = cp->phy_addr; | ||||
| 		/* Fallthrough... */ | ||||
| @ -5112,6 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, | ||||
| 	dev->get_stats = cas_get_stats; | ||||
| 	dev->set_multicast_list = cas_set_multicast; | ||||
| 	dev->do_ioctl = cas_ioctl; | ||||
| 	dev->ethtool_ops = &cas_ethtool_ops; | ||||
| 	dev->tx_timeout = cas_tx_timeout; | ||||
| 	dev->watchdog_timeo = CAS_TX_TIMEOUT; | ||||
| 	dev->change_mtu = cas_change_mtu; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user