v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.git] / target / linux / generic / pending-4.14 / 701-phy_extension.patch
1 From: John Crispin <john@phrozen.org>
2 Subject: net: phy: add phy_ethtool_ioctl()
3
4 Signed-off-by: John Crispin <john@phrozen.org>
5 ---
6  drivers/net/phy/phy.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
7  include/linux/phy.h   |  1 +
8  2 files changed, 45 insertions(+)
9
10 --- a/drivers/net/phy/phy.c
11 +++ b/drivers/net/phy/phy.c
12 @@ -382,6 +382,73 @@ void phy_ethtool_ksettings_get(struct ph
13  }
14  EXPORT_SYMBOL(phy_ethtool_ksettings_get);
15  
16 +static int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
17 +{
18 +       cmd->supported = phydev->supported;
19 +
20 +       cmd->advertising = phydev->advertising;
21 +       cmd->lp_advertising = phydev->lp_advertising;
22 +
23 +       ethtool_cmd_speed_set(cmd, phydev->speed);
24 +       cmd->duplex = phydev->duplex;
25 +       if (phydev->interface == PHY_INTERFACE_MODE_MOCA)
26 +               cmd->port = PORT_BNC;
27 +       else
28 +               cmd->port = PORT_MII;
29 +       cmd->phy_address = phydev->mdio.addr;
30 +       cmd->transceiver = phy_is_internal(phydev) ?
31 +               XCVR_INTERNAL : XCVR_EXTERNAL;
32 +       cmd->autoneg = phydev->autoneg;
33 +       cmd->eth_tp_mdix_ctrl = phydev->mdix_ctrl;
34 +       cmd->eth_tp_mdix = phydev->mdix;
35 +
36 +       return 0;
37 +}
38 +
39 +int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
40 +{
41 +       u32 cmd;
42 +       int tmp;
43 +       struct ethtool_cmd ecmd = { ETHTOOL_GSET };
44 +       struct ethtool_value edata = { ETHTOOL_GLINK };
45 +
46 +       if (get_user(cmd, (u32 *) useraddr))
47 +               return -EFAULT;
48 +
49 +       switch (cmd) {
50 +       case ETHTOOL_GSET:
51 +               phy_ethtool_gset(phydev, &ecmd);
52 +               if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
53 +                       return -EFAULT;
54 +               return 0;
55 +
56 +       case ETHTOOL_SSET:
57 +               if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
58 +                       return -EFAULT;
59 +               return phy_ethtool_sset(phydev, &ecmd);
60 +
61 +       case ETHTOOL_NWAY_RST:
62 +               /* if autoneg is off, it's an error */
63 +               tmp = phy_read(phydev, MII_BMCR);
64 +               if (tmp & BMCR_ANENABLE) {
65 +                       tmp |= (BMCR_ANRESTART);
66 +                       phy_write(phydev, MII_BMCR, tmp);
67 +                       return 0;
68 +               }
69 +               return -EINVAL;
70 +
71 +       case ETHTOOL_GLINK:
72 +               edata.data = (phy_read(phydev,
73 +                               MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
74 +               if (copy_to_user(useraddr, &edata, sizeof(edata)))
75 +                       return -EFAULT;
76 +               return 0;
77 +       }
78 +
79 +       return -EOPNOTSUPP;
80 +}
81 +EXPORT_SYMBOL(phy_ethtool_ioctl);
82 +
83  /**
84   * phy_mii_ioctl - generic PHY MII ioctl interface
85   * @phydev: the phy_device struct
86 --- a/include/linux/phy.h
87 +++ b/include/linux/phy.h
88 @@ -905,6 +905,7 @@ void phy_ethtool_ksettings_get(struct ph
89                                struct ethtool_link_ksettings *cmd);
90  int phy_ethtool_ksettings_set(struct phy_device *phydev,
91                               const struct ethtool_link_ksettings *cmd);
92 +int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
93  int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
94  int phy_start_interrupts(struct phy_device *phydev);
95  void phy_print_status(struct phy_device *phydev);