Commit d00a90ca authored by David S. Miller's avatar David S. Miller

Merge branch 'asix-pm-improvements'

Robert Foss says:

====================
net/usb: asix driver improvements

This is a resubmission of v3, since the netdev
mailinlist was not sent the previous submission.

This series improves power management of the asix driver.

 - Suspend/resume support is improved to save needed registers.
 - Device disconnection is improved.
 - Fixes AX88772x resume failures
 - Implementes IEEE 802.3 spec section "22.2.4.1.1 Reset" correctly
 - Fixes AX_CMD_WRITE_MEDIUM_MODE being set incorrectly

Changes since v1:
- Added proper metadata tags to series.
- Added two more patches to series.

Changes since v2:
- Added coverletter
- Tested patches on AX88772A/AX88772B/AX88178/AX88179 hardware
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c7735f1b 535baf85
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define AX_CMD_SET_SW_MII 0x06 #define AX_CMD_SET_SW_MII 0x06
#define AX_CMD_READ_MII_REG 0x07 #define AX_CMD_READ_MII_REG 0x07
#define AX_CMD_WRITE_MII_REG 0x08 #define AX_CMD_WRITE_MII_REG 0x08
#define AX_CMD_STATMNGSTS_REG 0x09
#define AX_CMD_SET_HW_MII 0x0a #define AX_CMD_SET_HW_MII 0x0a
#define AX_CMD_READ_EEPROM 0x0b #define AX_CMD_READ_EEPROM 0x0b
#define AX_CMD_WRITE_EEPROM 0x0c #define AX_CMD_WRITE_EEPROM 0x0c
...@@ -71,6 +72,17 @@ ...@@ -71,6 +72,17 @@
#define AX_CMD_SW_RESET 0x20 #define AX_CMD_SW_RESET 0x20
#define AX_CMD_SW_PHY_STATUS 0x21 #define AX_CMD_SW_PHY_STATUS 0x21
#define AX_CMD_SW_PHY_SELECT 0x22 #define AX_CMD_SW_PHY_SELECT 0x22
#define AX_QCTCTRL 0x2A
#define AX_CHIPCODE_MASK 0x70
#define AX_AX88772_CHIPCODE 0x00
#define AX_AX88772A_CHIPCODE 0x10
#define AX_AX88772B_CHIPCODE 0x20
#define AX_HOST_EN 0x01
#define AX_PHYSEL_PSEL 0x01
#define AX_PHYSEL_SSMII 0
#define AX_PHYSEL_SSEN 0x10
#define AX_PHY_SELECT_MASK (BIT(3) | BIT(2)) #define AX_PHY_SELECT_MASK (BIT(3) | BIT(2))
#define AX_PHY_SELECT_INTERNAL 0 #define AX_PHY_SELECT_INTERNAL 0
...@@ -173,6 +185,10 @@ struct asix_rx_fixup_info { ...@@ -173,6 +185,10 @@ struct asix_rx_fixup_info {
}; };
struct asix_common_private { struct asix_common_private {
void (*resume)(struct usbnet *dev);
void (*suspend)(struct usbnet *dev);
u16 presvd_phy_advertise;
u16 presvd_phy_bmcr;
struct asix_rx_fixup_info rx_fixup_info; struct asix_rx_fixup_info rx_fixup_info;
}; };
...@@ -182,10 +198,10 @@ extern const struct driver_info ax88172a_info; ...@@ -182,10 +198,10 @@ extern const struct driver_info ax88172a_info;
#define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */ #define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */
int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data); u16 size, void *data, int in_pm);
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data); u16 size, void *data, int in_pm);
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
u16 index, u16 size, void *data); u16 index, u16 size, void *data);
...@@ -197,27 +213,31 @@ int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb); ...@@ -197,27 +213,31 @@ int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags); gfp_t flags);
int asix_set_sw_mii(struct usbnet *dev); int asix_set_sw_mii(struct usbnet *dev, int in_pm);
int asix_set_hw_mii(struct usbnet *dev); int asix_set_hw_mii(struct usbnet *dev, int in_pm);
int asix_read_phy_addr(struct usbnet *dev, int internal); int asix_read_phy_addr(struct usbnet *dev, int internal);
int asix_get_phy_addr(struct usbnet *dev); int asix_get_phy_addr(struct usbnet *dev);
int asix_sw_reset(struct usbnet *dev, u8 flags); int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm);
u16 asix_read_rx_ctl(struct usbnet *dev); u16 asix_read_rx_ctl(struct usbnet *dev, int in_pm);
int asix_write_rx_ctl(struct usbnet *dev, u16 mode); int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm);
u16 asix_read_medium_status(struct usbnet *dev); u16 asix_read_medium_status(struct usbnet *dev, int in_pm);
int asix_write_medium_mode(struct usbnet *dev, u16 mode); int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm);
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep); int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm);
void asix_set_multicast(struct net_device *net); void asix_set_multicast(struct net_device *net);
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc); int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val); void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc);
void asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc,
int val);
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo);
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo);
......
This diff is collapsed.
This diff is collapsed.
...@@ -81,7 +81,7 @@ static void ax88172a_adjust_link(struct net_device *netdev) ...@@ -81,7 +81,7 @@ static void ax88172a_adjust_link(struct net_device *netdev)
} }
if (mode != priv->oldmode) { if (mode != priv->oldmode) {
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode, 0);
priv->oldmode = mode; priv->oldmode = mode;
netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n", netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n",
phydev->speed, phydev->duplex, mode); phydev->speed, phydev->duplex, mode);
...@@ -176,18 +176,19 @@ static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy) ...@@ -176,18 +176,19 @@ static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy)
{ {
int ret; int ret;
ret = asix_sw_reset(dev, AX_SWRESET_IPPD); ret = asix_sw_reset(dev, AX_SWRESET_IPPD, 0);
if (ret < 0) if (ret < 0)
goto err; goto err;
msleep(150); msleep(150);
ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, 0);
if (ret < 0) if (ret < 0)
goto err; goto err;
msleep(150); msleep(150);
ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD); ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD,
0);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -213,7 +214,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -213,7 +214,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
dev->driver_priv = priv; dev->driver_priv = priv;
/* Get the MAC address */ /* Get the MAC address */
ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Failed to read MAC address: %d\n", ret); netdev_err(dev->net, "Failed to read MAC address: %d\n", ret);
goto free; goto free;
...@@ -224,7 +225,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -224,7 +225,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->ethtool_ops = &ax88172a_ethtool_ops; dev->net->ethtool_ops = &ax88172a_ethtool_ops;
/* are we using the internal or the external phy? */ /* are we using the internal or the external phy? */
ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf); ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Failed to read software interface selection register: %d\n", netdev_err(dev->net, "Failed to read software interface selection register: %d\n",
ret); ret);
...@@ -303,20 +304,20 @@ static int ax88172a_reset(struct usbnet *dev) ...@@ -303,20 +304,20 @@ static int ax88172a_reset(struct usbnet *dev)
ax88172a_reset_phy(dev, priv->use_embdphy); ax88172a_reset_phy(dev, priv->use_embdphy);
msleep(150); msleep(150);
rx_ctl = asix_read_rx_ctl(dev); rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
ret = asix_write_rx_ctl(dev, 0x0000); ret = asix_write_rx_ctl(dev, 0x0000, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
rx_ctl = asix_read_rx_ctl(dev); rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
msleep(150); msleep(150);
ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, 0, NULL); AX88772_IPG2_DEFAULT, 0, NULL, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
goto out; goto out;
...@@ -325,20 +326,20 @@ static int ax88172a_reset(struct usbnet *dev) ...@@ -325,20 +326,20 @@ static int ax88172a_reset(struct usbnet *dev)
/* Rewrite MAC address */ /* Rewrite MAC address */
memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
data->mac_addr); data->mac_addr, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
rx_ctl = asix_read_rx_ctl(dev); rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
rx_ctl); rx_ctl);
rx_ctl = asix_read_medium_status(dev); rx_ctl = asix_read_medium_status(dev, 0);
netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n", netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n",
rx_ctl); rx_ctl);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment