Commit 771efeda authored by Hayes Wang's avatar Hayes Wang Committed by David S. Miller
Browse files

r8152: modify rtl8152_set_speed function



First, for AUTONEG_DISABLE, we only need to modify MII_BMCR.

Second, add advertising parameter for rtl8152_set_speed(). Add
RTL_ADVERTISED_xxx for advertising parameter of rtl8152_set_speed().
Then, the advertising settings from ethtool could be saved.

Signed-off-by: default avatarHayes Wang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 472e12e7
Loading
Loading
Loading
Loading
+132 −64
Original line number Original line Diff line number Diff line
@@ -757,6 +757,7 @@ struct r8152 {
	u32 msg_enable;
	u32 msg_enable;
	u32 tx_qlen;
	u32 tx_qlen;
	u32 coalesce;
	u32 coalesce;
	u32 advertising;
	u32 rx_buf_sz;
	u32 rx_buf_sz;
	u32 rx_copybreak;
	u32 rx_copybreak;
	u32 rx_pending;
	u32 rx_pending;
@@ -790,6 +791,13 @@ enum tx_csum_stat {
	TX_CSUM_NONE
	TX_CSUM_NONE
};
};


#define RTL_ADVERTISED_10_HALF			BIT(0)
#define RTL_ADVERTISED_10_FULL			BIT(1)
#define RTL_ADVERTISED_100_HALF			BIT(2)
#define RTL_ADVERTISED_100_FULL			BIT(3)
#define RTL_ADVERTISED_1000_HALF		BIT(4)
#define RTL_ADVERTISED_1000_FULL		BIT(5)

/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
 * The RTL chips use a 64 element hash table based on the Ethernet CRC.
 * The RTL chips use a 64 element hash table based on the Ethernet CRC.
 */
 */
@@ -3801,90 +3809,117 @@ static void rtl8153b_disable(struct r8152 *tp)
	r8153b_aldps_en(tp, true);
	r8153b_aldps_en(tp, true);
}
}


static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
			     u32 advertising)
{
{
	u16 bmcr, anar, gbcr;
	enum spd_duplex speed_duplex;
	enum spd_duplex speed_duplex;
	u16 bmcr;
	int ret = 0;
	int ret = 0;


	anar = r8152_mdio_read(tp, MII_ADVERTISE);
	anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
		  ADVERTISE_100HALF | ADVERTISE_100FULL);
	if (tp->mii.supports_gmii) {
		gbcr = r8152_mdio_read(tp, MII_CTRL1000);
		gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
	} else {
		gbcr = 0;
	}

	if (autoneg == AUTONEG_DISABLE) {
	if (autoneg == AUTONEG_DISABLE) {
		if (speed == SPEED_10) {
		if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL)
			bmcr = 0;
			return -EINVAL;
			anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;

		switch (speed) {
		case SPEED_10:
			bmcr = BMCR_SPEED10;
			if (duplex == DUPLEX_FULL) {
				bmcr |= BMCR_FULLDPLX;
				speed_duplex = FORCE_10M_FULL;
			} else {
				speed_duplex = FORCE_10M_HALF;
				speed_duplex = FORCE_10M_HALF;
		} else if (speed == SPEED_100) {
			}
			break;
		case SPEED_100:
			bmcr = BMCR_SPEED100;
			bmcr = BMCR_SPEED100;
			anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
			if (duplex == DUPLEX_FULL) {
				bmcr |= BMCR_FULLDPLX;
				speed_duplex = FORCE_100M_FULL;
			} else {
				speed_duplex = FORCE_100M_HALF;
				speed_duplex = FORCE_100M_HALF;
		} else if (speed == SPEED_1000 && tp->mii.supports_gmii) {
			}
			bmcr = BMCR_SPEED1000;
			break;
			gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
		case SPEED_1000:
			if (tp->mii.supports_gmii) {
				bmcr = BMCR_SPEED1000 | BMCR_FULLDPLX;
				speed_duplex = NWAY_1000M_FULL;
				speed_duplex = NWAY_1000M_FULL;
		} else {
				break;
			}
			/* fall through */
		default:
			ret = -EINVAL;
			ret = -EINVAL;
			goto out;
			goto out;
		}
		}


		if (duplex == DUPLEX_FULL) {
		if (duplex == DUPLEX_FULL)
			bmcr |= BMCR_FULLDPLX;
			tp->mii.full_duplex = 1;
			if (speed != SPEED_1000)
		else
				speed_duplex++;
			tp->mii.full_duplex = 0;
		}

	} else {
		tp->mii.force_media = 1;
		if (speed == SPEED_10) {
			if (duplex == DUPLEX_FULL) {
				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
				speed_duplex = NWAY_10M_FULL;
	} else {
	} else {
				anar |= ADVERTISE_10HALF;
		u16 anar, tmp1;
		u32 support;

		support = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
			  RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;

		if (tp->mii.supports_gmii)
			support |= RTL_ADVERTISED_1000_FULL;

		if (!(advertising & support))
			return -EINVAL;

		anar = r8152_mdio_read(tp, MII_ADVERTISE);
		tmp1 = anar & ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
				ADVERTISE_100HALF | ADVERTISE_100FULL);
		if (advertising & RTL_ADVERTISED_10_HALF) {
			tmp1 |= ADVERTISE_10HALF;
			speed_duplex = NWAY_10M_HALF;
			speed_duplex = NWAY_10M_HALF;
		}
		}
		} else if (speed == SPEED_100) {
		if (advertising & RTL_ADVERTISED_10_FULL) {
			if (duplex == DUPLEX_FULL) {
			tmp1 |= ADVERTISE_10FULL;
				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
			speed_duplex = NWAY_10M_FULL;
				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
		}
				speed_duplex = NWAY_100M_FULL;

			} else {
		if (advertising & RTL_ADVERTISED_100_HALF) {
				anar |= ADVERTISE_10HALF;
			tmp1 |= ADVERTISE_100HALF;
				anar |= ADVERTISE_100HALF;
			speed_duplex = NWAY_100M_HALF;
			speed_duplex = NWAY_100M_HALF;
		}
		}
		} else if (speed == SPEED_1000 && tp->mii.supports_gmii) {
		if (advertising & RTL_ADVERTISED_100_FULL) {
			if (duplex == DUPLEX_FULL) {
			tmp1 |= ADVERTISE_100FULL;
				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
			speed_duplex = NWAY_100M_FULL;
				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
		}
				gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;

			} else {
		if (anar != tmp1) {
				anar |= ADVERTISE_10HALF;
			r8152_mdio_write(tp, MII_ADVERTISE, tmp1);
				anar |= ADVERTISE_100HALF;
			tp->mii.advertising = tmp1;
				gbcr |= ADVERTISE_1000HALF;
		}
		}

		if (tp->mii.supports_gmii) {
			u16 gbcr;

			gbcr = r8152_mdio_read(tp, MII_CTRL1000);
			tmp1 = gbcr & ~(ADVERTISE_1000FULL |
					ADVERTISE_1000HALF);

			if (advertising & RTL_ADVERTISED_1000_FULL) {
				tmp1 |= ADVERTISE_1000FULL;
				speed_duplex = NWAY_1000M_FULL;
				speed_duplex = NWAY_1000M_FULL;
		} else {
			}
			ret = -EINVAL;

			goto out;
			if (gbcr != tmp1)
				r8152_mdio_write(tp, MII_CTRL1000, tmp1);
		}
		}


		bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
		bmcr = BMCR_ANENABLE | BMCR_ANRESTART;

		tp->mii.force_media = 0;
	}
	}


	if (test_and_clear_bit(PHY_RESET, &tp->flags))
	if (test_and_clear_bit(PHY_RESET, &tp->flags))
		bmcr |= BMCR_RESET;
		bmcr |= BMCR_RESET;


	if (tp->mii.supports_gmii)
		r8152_mdio_write(tp, MII_CTRL1000, gbcr);

	r8152_mdio_write(tp, MII_ADVERTISE, anar);
	r8152_mdio_write(tp, MII_BMCR, bmcr);
	r8152_mdio_write(tp, MII_BMCR, bmcr);


	switch (tp->version) {
	switch (tp->version) {
@@ -4122,7 +4157,8 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work)


	tp->rtl_ops.hw_phy_cfg(tp);
	tp->rtl_ops.hw_phy_cfg(tp);


	rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex);
	rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex,
			  tp->advertising);


	mutex_unlock(&tp->control);
	mutex_unlock(&tp->control);


@@ -4840,20 +4876,46 @@ static int rtl8152_set_link_ksettings(struct net_device *dev,
				      const struct ethtool_link_ksettings *cmd)
				      const struct ethtool_link_ksettings *cmd)
{
{
	struct r8152 *tp = netdev_priv(dev);
	struct r8152 *tp = netdev_priv(dev);
	u32 advertising = 0;
	int ret;
	int ret;


	ret = usb_autopm_get_interface(tp->intf);
	ret = usb_autopm_get_interface(tp->intf);
	if (ret < 0)
	if (ret < 0)
		goto out;
		goto out;


	if (test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
		     cmd->link_modes.advertising))
		advertising |= RTL_ADVERTISED_10_HALF;

	if (test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
		     cmd->link_modes.advertising))
		advertising |= RTL_ADVERTISED_10_FULL;

	if (test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
		     cmd->link_modes.advertising))
		advertising |= RTL_ADVERTISED_100_HALF;

	if (test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
		     cmd->link_modes.advertising))
		advertising |= RTL_ADVERTISED_100_FULL;

	if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
		     cmd->link_modes.advertising))
		advertising |= RTL_ADVERTISED_1000_HALF;

	if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
		     cmd->link_modes.advertising))
		advertising |= RTL_ADVERTISED_1000_FULL;

	mutex_lock(&tp->control);
	mutex_lock(&tp->control);


	ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed,
	ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed,
				cmd->base.duplex);
				cmd->base.duplex, advertising);
	if (!ret) {
	if (!ret) {
		tp->autoneg = cmd->base.autoneg;
		tp->autoneg = cmd->base.autoneg;
		tp->speed = cmd->base.speed;
		tp->speed = cmd->base.speed;
		tp->duplex = cmd->base.duplex;
		tp->duplex = cmd->base.duplex;
		tp->advertising = advertising;
	}
	}


	mutex_unlock(&tp->control);
	mutex_unlock(&tp->control);
@@ -5568,7 +5630,13 @@ static int rtl8152_probe(struct usb_interface *intf,
	tp->mii.phy_id = R8152_PHY_ID;
	tp->mii.phy_id = R8152_PHY_ID;


	tp->autoneg = AUTONEG_ENABLE;
	tp->autoneg = AUTONEG_ENABLE;
	tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100;
	tp->speed = SPEED_100;
	tp->advertising = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
			  RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
	if (tp->mii.supports_gmii) {
		tp->speed = SPEED_1000;
		tp->advertising |= RTL_ADVERTISED_1000_FULL;
	}
	tp->duplex = DUPLEX_FULL;
	tp->duplex = DUPLEX_FULL;


	tp->rx_copybreak = RTL8152_RXFG_HEADSZ;
	tp->rx_copybreak = RTL8152_RXFG_HEADSZ;