diff options
Diffstat (limited to 'drivers/net/via-velocity.c')
| -rw-r--r-- | drivers/net/via-velocity.c | 86 | 
1 files changed, 78 insertions, 8 deletions
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index f53412368ce..cab96ad49e6 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -312,13 +312,14 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");  #define MED_LNK_DEF 0  #define MED_LNK_MIN 0 -#define MED_LNK_MAX 4 +#define MED_LNK_MAX 5  /* speed_duplex[] is used for setting the speed and duplex mode of NIC.     0: indicate autonegotiation for both speed and duplex mode     1: indicate 100Mbps half duplex mode     2: indicate 100Mbps full duplex mode     3: indicate 10Mbps half duplex mode     4: indicate 10Mbps full duplex mode +   5: indicate 1000Mbps full duplex mode     Note:     if EEPROM have been set to the force mode, this option is ignored @@ -617,6 +618,9 @@ static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)  	case SPD_DPX_10_HALF:  		status = VELOCITY_SPEED_10;  		break; +	case SPD_DPX_1000_FULL: +		status = VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; +		break;  	}  	vptr->mii_status = status;  	return status; @@ -922,6 +926,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)  		/* enable AUTO-NEGO mode */  		mii_set_auto_on(vptr);  	} else { +		u16 CTRL1000;  		u16 ANAR;  		u8 CHIPGCR; @@ -936,7 +941,11 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)  		BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR);  		CHIPGCR = readb(®s->CHIPGCR); -		CHIPGCR &= ~CHIPGCR_FCGMII; + +		if (mii_status & VELOCITY_SPEED_1000) +			CHIPGCR |= CHIPGCR_FCGMII; +		else +			CHIPGCR &= ~CHIPGCR_FCGMII;  		if (mii_status & VELOCITY_DUPLEX_FULL) {  			CHIPGCR |= CHIPGCR_FCFDX; @@ -952,7 +961,13 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)  				BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR);  		} -		MII_REG_BITS_OFF(ADVERTISE_1000FULL | ADVERTISE_1000HALF, MII_CTRL1000, vptr->mac_regs); +		velocity_mii_read(vptr->mac_regs, MII_CTRL1000, &CTRL1000); +		CTRL1000 &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); +		if ((mii_status & VELOCITY_SPEED_1000) && +		    (mii_status & VELOCITY_DUPLEX_FULL)) { +			CTRL1000 |= ADVERTISE_1000FULL; +		} +		velocity_mii_write(vptr->mac_regs, MII_CTRL1000, CTRL1000);  		if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))  			BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); @@ -967,7 +982,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)  				ANAR |= ADVERTISE_100FULL;  			else  				ANAR |= ADVERTISE_100HALF; -		} else { +		} else if (mii_status & VELOCITY_SPEED_10) {  			if (mii_status & VELOCITY_DUPLEX_FULL)  				ANAR |= ADVERTISE_10FULL;  			else @@ -1013,6 +1028,9 @@ static void velocity_print_link_status(struct velocity_info *vptr)  	} else {  		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);  		switch (vptr->options.spd_dpx) { +		case SPD_DPX_1000_FULL: +			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps full duplex\n"); +			break;  		case SPD_DPX_100_HALF:  			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");  			break; @@ -1954,7 +1972,7 @@ static int velocity_tx_srv(struct velocity_info *vptr)   */  static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)  { -	skb->ip_summed = CHECKSUM_NONE; +	skb_checksum_none_assert(skb);  	if (rd->rdesc1.CSM & CSM_IPKT) {  		if (rd->rdesc1.CSM & CSM_IPOK) { @@ -2574,7 +2592,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,  	td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; -	if (vptr->vlgrp && vlan_tx_tag_present(skb)) { +	if (vlan_tx_tag_present(skb)) {  		td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));  		td_ptr->tdesc1.TCR |= TCR0_VETAG;  	} @@ -3170,6 +3188,37 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd  			SUPPORTED_100baseT_Full |  			SUPPORTED_1000baseT_Half |  			SUPPORTED_1000baseT_Full; + +	cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; +	if (vptr->options.spd_dpx == SPD_DPX_AUTO) { +		cmd->advertising |= +			ADVERTISED_10baseT_Half | +			ADVERTISED_10baseT_Full | +			ADVERTISED_100baseT_Half | +			ADVERTISED_100baseT_Full | +			ADVERTISED_1000baseT_Half | +			ADVERTISED_1000baseT_Full; +	} else { +		switch (vptr->options.spd_dpx) { +		case SPD_DPX_1000_FULL: +			cmd->advertising |= ADVERTISED_1000baseT_Full; +			break; +		case SPD_DPX_100_HALF: +			cmd->advertising |= ADVERTISED_100baseT_Half; +			break; +		case SPD_DPX_100_FULL: +			cmd->advertising |= ADVERTISED_100baseT_Full; +			break; +		case SPD_DPX_10_HALF: +			cmd->advertising |= ADVERTISED_10baseT_Half; +			break; +		case SPD_DPX_10_FULL: +			cmd->advertising |= ADVERTISED_10baseT_Full; +			break; +		default: +			break; +		} +	}  	if (status & VELOCITY_SPEED_1000)  		cmd->speed = SPEED_1000;  	else if (status & VELOCITY_SPEED_100) @@ -3200,14 +3249,35 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd  	curr_status &= (~VELOCITY_LINK_FAIL);  	new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); +	new_status |= ((cmd->speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0);  	new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);  	new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);  	new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); -	if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) +	if ((new_status & VELOCITY_AUTONEG_ENABLE) && +	    (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) {  		ret = -EINVAL; -	else +	} else { +		enum speed_opt spd_dpx; + +		if (new_status & VELOCITY_AUTONEG_ENABLE) +			spd_dpx = SPD_DPX_AUTO; +		else if ((new_status & VELOCITY_SPEED_1000) && +			 (new_status & VELOCITY_DUPLEX_FULL)) { +			spd_dpx = SPD_DPX_1000_FULL; +		} else if (new_status & VELOCITY_SPEED_100) +			spd_dpx = (new_status & VELOCITY_DUPLEX_FULL) ? +				SPD_DPX_100_FULL : SPD_DPX_100_HALF; +		else if (new_status & VELOCITY_SPEED_10) +			spd_dpx = (new_status & VELOCITY_DUPLEX_FULL) ? +				SPD_DPX_10_FULL : SPD_DPX_10_HALF; +		else +			return -EOPNOTSUPP; + +		vptr->options.spd_dpx = spd_dpx; +  		velocity_set_media_mode(vptr, new_status); +	}  	return ret;  }  |