ixgb_ethtool.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 722 行 · 第 1/2 页

C
722
字号
static intixgb_ethtool_seeprom(struct ixgb_adapter *adapter,		     struct ethtool_eeprom *eeprom, void __user *user_data){	struct ixgb_hw *hw = &adapter->hw;	uint16_t eeprom_buff[256];	int i, max_len, first_word, last_word;	void *ptr;	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))		return -EFAULT;	if (eeprom->len == 0)		return -EINVAL;	max_len = ixgb_eeprom_size(hw);	if (eeprom->offset > eeprom->offset + eeprom->len)		return -EINVAL;	if ((eeprom->offset + eeprom->len) > max_len)		eeprom->len = (max_len - eeprom->offset);	first_word = eeprom->offset >> 1;	last_word = (eeprom->offset + eeprom->len - 1) >> 1;	ptr = (void *)eeprom_buff;	if (eeprom->offset & 1) {		/* need read/modify/write of first changed EEPROM word */		/* only the second byte of the word is being modified */		eeprom_buff[0] = ixgb_read_eeprom(hw, first_word);		ptr++;	}	if ((eeprom->offset + eeprom->len) & 1) {		/* need read/modify/write of last changed EEPROM word */		/* only the first byte of the word is being modified */		eeprom_buff[last_word - first_word]		    = ixgb_read_eeprom(hw, last_word);	}	if (copy_from_user(ptr, user_data, eeprom->len))		return -EFAULT;	for (i = 0; i <= (last_word - first_word); i++)		ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]);	/* Update the checksum over the first part of the EEPROM if needed */	if (first_word <= EEPROM_CHECKSUM_REG)		ixgb_update_eeprom_checksum(hw);	return 0;}/* toggle LED 4 times per second = 2 "blinks" per second */#define IXGB_ID_INTERVAL	(HZ/4)/* bit defines for adapter->led_status */#define IXGB_LED_ON		0static void ixgb_led_blink_callback(unsigned long data){	struct ixgb_adapter *adapter = (struct ixgb_adapter *)data;	if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status))		ixgb_led_off(&adapter->hw);	else		ixgb_led_on(&adapter->hw);	mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL);}static intixgb_ethtool_led_blink(struct ixgb_adapter *adapter, struct ethtool_value *id){	if (!adapter->blink_timer.function) {		init_timer(&adapter->blink_timer);		adapter->blink_timer.function = ixgb_led_blink_callback;		adapter->blink_timer.data = (unsigned long)adapter;	}	mod_timer(&adapter->blink_timer, jiffies);	set_current_state(TASK_INTERRUPTIBLE);	if (id->data)		schedule_timeout(id->data * HZ);	else		schedule_timeout(MAX_SCHEDULE_TIMEOUT);	del_timer_sync(&adapter->blink_timer);	ixgb_led_off(&adapter->hw);	clear_bit(IXGB_LED_ON, &adapter->led_status);	return 0;}int ixgb_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr){	struct ixgb_adapter *adapter = netdev->priv;	void __user *addr = ifr->ifr_data;	uint32_t cmd;	if (get_user(cmd, (uint32_t __user *) addr))		return -EFAULT;	switch (cmd) {	case ETHTOOL_GSET:{			struct ethtool_cmd ecmd = { ETHTOOL_GSET };			ixgb_ethtool_gset(adapter, &ecmd);			if (copy_to_user(addr, &ecmd, sizeof(ecmd)))				return -EFAULT;			return 0;		}	case ETHTOOL_SSET:{			struct ethtool_cmd ecmd;			if (copy_from_user(&ecmd, addr, sizeof(ecmd)))				return -EFAULT;			return ixgb_ethtool_sset(adapter, &ecmd);		}	case ETHTOOL_GDRVINFO:{			struct ethtool_drvinfo drvinfo = { ETHTOOL_GDRVINFO };			ixgb_ethtool_gdrvinfo(adapter, &drvinfo);			if (copy_to_user(addr, &drvinfo, sizeof(drvinfo)))				return -EFAULT;			return 0;		}	case ETHTOOL_GSTRINGS:{			struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };			char *strings = NULL;			int err = 0;			if (copy_from_user(&gstrings, addr, sizeof(gstrings)))				return -EFAULT;			switch (gstrings.string_set) {			case ETH_SS_STATS:{					int i;					gstrings.len = IXGB_STATS_LEN;					strings =					    kmalloc(IXGB_STATS_LEN *						    ETH_GSTRING_LEN,						    GFP_KERNEL);					if (!strings)						return -ENOMEM;					for (i = 0; i < IXGB_STATS_LEN; i++) {						memcpy(&strings						       [i * ETH_GSTRING_LEN],						       ixgb_gstrings_stats[i].						       stat_string,						       ETH_GSTRING_LEN);					}					break;				}			default:				return -EOPNOTSUPP;			}			if (copy_to_user(addr, &gstrings, sizeof(gstrings)))				err = -EFAULT;			addr += offsetof(struct ethtool_gstrings, data);			if (!err && copy_to_user(addr, strings,						 gstrings.len *						 ETH_GSTRING_LEN))				err = -EFAULT;			kfree(strings);			return err;		}	case ETHTOOL_GREGS:{			struct ethtool_regs regs = { ETHTOOL_GREGS };			uint32_t regs_buff[IXGB_REG_DUMP_LEN];			if (copy_from_user(&regs, addr, sizeof(regs)))				return -EFAULT;			ixgb_ethtool_gregs(adapter, &regs, regs_buff);			if (copy_to_user(addr, &regs, sizeof(regs)))				return -EFAULT;			addr += offsetof(struct ethtool_regs, data);			if (copy_to_user(addr, regs_buff, regs.len))				return -EFAULT;			return 0;		}	case ETHTOOL_NWAY_RST:{			if (netif_running(netdev)) {				ixgb_down(adapter, TRUE);				ixgb_up(adapter);			}			return 0;		}	case ETHTOOL_PHYS_ID:{			struct ethtool_value id;			if (copy_from_user(&id, addr, sizeof(id)))				return -EFAULT;			return ixgb_ethtool_led_blink(adapter, &id);		}	case ETHTOOL_GLINK:{			struct ethtool_value link = { ETHTOOL_GLINK };			link.data = netif_carrier_ok(netdev);			if (copy_to_user(addr, &link, sizeof(link)))				return -EFAULT;			return 0;		}	case ETHTOOL_GEEPROM:{			struct ethtool_eeprom eeprom = { ETHTOOL_GEEPROM };			uint16_t eeprom_buff[IXGB_EEPROM_SIZE];			void *ptr;			int err = 0;			if (copy_from_user(&eeprom, addr, sizeof(eeprom)))				return -EFAULT;			if ((err =			     ixgb_ethtool_geeprom(adapter, &eeprom,						  eeprom_buff)) < 0)				return err;			if (copy_to_user(addr, &eeprom, sizeof(eeprom)))				return -EFAULT;			addr += offsetof(struct ethtool_eeprom, data);			ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);			if (copy_to_user(addr, ptr, eeprom.len))				return -EFAULT;			return 0;		}	case ETHTOOL_SEEPROM:{			struct ethtool_eeprom eeprom;			if (copy_from_user(&eeprom, addr, sizeof(eeprom)))				return -EFAULT;			addr += offsetof(struct ethtool_eeprom, data);			return ixgb_ethtool_seeprom(adapter, &eeprom, addr);		}	case ETHTOOL_GPAUSEPARAM:{			struct ethtool_pauseparam epause =			    { ETHTOOL_GPAUSEPARAM };			ixgb_ethtool_gpause(adapter, &epause);			if (copy_to_user(addr, &epause, sizeof(epause)))				return -EFAULT;			return 0;		}	case ETHTOOL_SPAUSEPARAM:{			struct ethtool_pauseparam epause;			if (copy_from_user(&epause, addr, sizeof(epause)))				return -EFAULT;			return ixgb_ethtool_spause(adapter, &epause);		}	case ETHTOOL_GSTATS:{			struct {				struct ethtool_stats eth_stats;				uint64_t data[IXGB_STATS_LEN];			} stats = { {			ETHTOOL_GSTATS, IXGB_STATS_LEN}};			int i;			for (i = 0; i < IXGB_STATS_LEN; i++)				stats.data[i] =				    (ixgb_gstrings_stats[i].sizeof_stat ==				     sizeof(uint64_t)) ? *(uint64_t *) ((char *)									adapter									+									ixgb_gstrings_stats									[i].									stat_offset)				    : *(uint32_t *) ((char *)adapter +						     ixgb_gstrings_stats[i].						     stat_offset);			if (copy_to_user(addr, &stats, sizeof(stats)))				return -EFAULT;			return 0;		}	case ETHTOOL_GRXCSUM:{			struct ethtool_value edata = { ETHTOOL_GRXCSUM };			edata.data = adapter->rx_csum;			if (copy_to_user(addr, &edata, sizeof(edata)))				return -EFAULT;			return 0;		}	case ETHTOOL_SRXCSUM:{			struct ethtool_value edata;			if (copy_from_user(&edata, addr, sizeof(edata)))				return -EFAULT;			adapter->rx_csum = edata.data;			ixgb_down(adapter, TRUE);			ixgb_up(adapter);			return 0;		}	case ETHTOOL_GTXCSUM:{			struct ethtool_value edata = { ETHTOOL_GTXCSUM };			edata.data = (netdev->features & NETIF_F_HW_CSUM) != 0;			if (copy_to_user(addr, &edata, sizeof(edata)))				return -EFAULT;			return 0;		}	case ETHTOOL_STXCSUM:{			struct ethtool_value edata;			if (copy_from_user(&edata, addr, sizeof(edata)))				return -EFAULT;			if (edata.data)				netdev->features |= NETIF_F_HW_CSUM;			else				netdev->features &= ~NETIF_F_HW_CSUM;			return 0;		}	case ETHTOOL_GSG:{			struct ethtool_value edata = { ETHTOOL_GSG };			edata.data = (netdev->features & NETIF_F_SG) != 0;			if (copy_to_user(addr, &edata, sizeof(edata)))				return -EFAULT;			return 0;		}	case ETHTOOL_SSG:{			struct ethtool_value edata;			if (copy_from_user(&edata, addr, sizeof(edata)))				return -EFAULT;			if (edata.data)				netdev->features |= NETIF_F_SG;			else				netdev->features &= ~NETIF_F_SG;			return 0;		}#ifdef NETIF_F_TSO	case ETHTOOL_GTSO:{			struct ethtool_value edata = { ETHTOOL_GTSO };			edata.data = (netdev->features & NETIF_F_TSO) != 0;			if (copy_to_user(addr, &edata, sizeof(edata)))				return -EFAULT;			return 0;		}	case ETHTOOL_STSO:{			struct ethtool_value edata;			if (copy_from_user(&edata, addr, sizeof(edata)))				return -EFAULT;			if (edata.data)				netdev->features |= NETIF_F_TSO;			else				netdev->features &= ~NETIF_F_TSO;			return 0;		}#endif	default:		return -EOPNOTSUPP;	}}

⌨️ 快捷键说明

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