bnx2x: MDC/MDIO CL45 IOCTLs
As suggested by Ben Hutchings <bhutchings@solarflare.com>, using the MDC/MDIO
IOCTL
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9948fa2..29935a9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2722,6 +2722,7 @@
select FW_LOADER
select ZLIB_INFLATE
select LIBCRC32C
+ select MDIO
help
This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 5864ae2..903c89d 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -30,6 +30,8 @@
#define BNX2X_NEW_NAPI
+
+#include <linux/mdio.h>
#include "bnx2x_reg.h"
#include "bnx2x_fw_defs.h"
#include "bnx2x_hsi.h"
@@ -895,6 +897,7 @@
struct link_params link_params;
struct link_vars link_vars;
+ struct mdio_if_info mdio;
struct bnx2x_common common;
struct bnx2x_port port;
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index a695e7f..14586676 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -8331,6 +8331,7 @@
u32 val, val2;
u32 config;
u16 i;
+ u32 ext_phy_type;
bp->link_params.bp = bp;
bp->link_params.port = port;
@@ -8390,6 +8391,21 @@
bnx2x_link_settings_requested(bp);
+ /*
+ * If connected directly, work with the internal PHY, otherwise, work
+ * with the external PHY
+ */
+ ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+ bp->mdio.prtad = bp->link_params.phy_addr;
+
+ else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+ (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
+ bp->mdio.prtad =
+ (bp->link_params.ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT;
+
val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
@@ -8614,7 +8630,7 @@
} else
cmd->port = PORT_TP;
- cmd->phy_address = bp->port.phy_addr;
+ cmd->phy_address = bp->mdio.prtad;
cmd->transceiver = XCVR_INTERNAL;
if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
@@ -11149,54 +11165,77 @@
}
/* called with rtnl_lock */
+static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
+ int devad, u16 addr)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u16 value;
+ int rc;
+ u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+
+ DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n",
+ prtad, devad, addr);
+
+ if (prtad != bp->mdio.prtad) {
+ DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
+ prtad, bp->mdio.prtad);
+ return -EINVAL;
+ }
+
+ /* The HW expects different devad if CL22 is used */
+ devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
+
+ bnx2x_acquire_phy_lock(bp);
+ rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad,
+ devad, addr, &value);
+ bnx2x_release_phy_lock(bp);
+ DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc);
+
+ if (!rc)
+ rc = value;
+ return rc;
+}
+
+/* called with rtnl_lock */
+static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad,
+ u16 addr, u16 value)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+ int rc;
+
+ DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x,"
+ " value 0x%x\n", prtad, devad, addr, value);
+
+ if (prtad != bp->mdio.prtad) {
+ DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
+ prtad, bp->mdio.prtad);
+ return -EINVAL;
+ }
+
+ /* The HW expects different devad if CL22 is used */
+ devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
+
+ bnx2x_acquire_phy_lock(bp);
+ rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad,
+ devad, addr, value);
+ bnx2x_release_phy_lock(bp);
+ return rc;
+}
+
+/* called with rtnl_lock */
static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct mii_ioctl_data *data = if_mii(ifr);
struct bnx2x *bp = netdev_priv(dev);
- int port = BP_PORT(bp);
- int err;
+ struct mii_ioctl_data *mdio = if_mii(ifr);
- switch (cmd) {
- case SIOCGMIIPHY:
- data->phy_id = bp->port.phy_addr;
+ DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
+ mdio->phy_id, mdio->reg_num, mdio->val_in);
- /* fallthrough */
+ if (!netif_running(dev))
+ return -EAGAIN;
- case SIOCGMIIREG: {
- u16 mii_regval;
-
- if (!netif_running(dev))
- return -EAGAIN;
-
- mutex_lock(&bp->port.phy_mutex);
- err = bnx2x_cl45_read(bp, port, 0, bp->port.phy_addr,
- DEFAULT_PHY_DEV_ADDR,
- (data->reg_num & 0x1f), &mii_regval);
- data->val_out = mii_regval;
- mutex_unlock(&bp->port.phy_mutex);
- return err;
- }
-
- case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (!netif_running(dev))
- return -EAGAIN;
-
- mutex_lock(&bp->port.phy_mutex);
- err = bnx2x_cl45_write(bp, port, 0, bp->port.phy_addr,
- DEFAULT_PHY_DEV_ADDR,
- (data->reg_num & 0x1f), data->val_in);
- mutex_unlock(&bp->port.phy_mutex);
- return err;
-
- default:
- /* do nothing */
- break;
- }
-
- return -EOPNOTSUPP;
+ return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
}
/* called with rtnl_lock */
@@ -11420,6 +11459,14 @@
dev->vlan_features |= NETIF_F_TSO6;
#endif
+ /* get_port_hwinfo() will set prtad and mmds properly */
+ bp->mdio.prtad = MDIO_PRTAD_NONE;
+ bp->mdio.mmds = 0;
+ bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+ bp->mdio.dev = dev;
+ bp->mdio.mdio_read = bnx2x_mdio_read;
+ bp->mdio.mdio_write = bnx2x_mdio_write;
+
return 0;
err_out_unmap: