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>
This commit is contained in:
Eilon Greenstein 2009-08-12 08:23:08 +00:00 committed by David S. Miller
parent 239d686d49
commit 01cd452846
3 changed files with 94 additions and 43 deletions

View file

@ -2722,6 +2722,7 @@ config BNX2X
select FW_LOADER select FW_LOADER
select ZLIB_INFLATE select ZLIB_INFLATE
select LIBCRC32C select LIBCRC32C
select MDIO
help help
This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards. This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module

View file

@ -30,6 +30,8 @@
#define BNX2X_NEW_NAPI #define BNX2X_NEW_NAPI
#include <linux/mdio.h>
#include "bnx2x_reg.h" #include "bnx2x_reg.h"
#include "bnx2x_fw_defs.h" #include "bnx2x_fw_defs.h"
#include "bnx2x_hsi.h" #include "bnx2x_hsi.h"
@ -895,6 +897,7 @@ struct bnx2x {
struct link_params link_params; struct link_params link_params;
struct link_vars link_vars; struct link_vars link_vars;
struct mdio_if_info mdio;
struct bnx2x_common common; struct bnx2x_common common;
struct bnx2x_port port; struct bnx2x_port port;

View file

@ -8331,6 +8331,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
u32 val, val2; u32 val, val2;
u32 config; u32 config;
u16 i; u16 i;
u32 ext_phy_type;
bp->link_params.bp = bp; bp->link_params.bp = bp;
bp->link_params.port = port; bp->link_params.port = port;
@ -8390,6 +8391,21 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bnx2x_link_settings_requested(bp); 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); val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
@ -8614,7 +8630,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
} else } else
cmd->port = PORT_TP; cmd->port = PORT_TP;
cmd->phy_address = bp->port.phy_addr; cmd->phy_address = bp->mdio.prtad;
cmd->transceiver = XCVR_INTERNAL; cmd->transceiver = XCVR_INTERNAL;
if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
@ -11148,55 +11164,78 @@ static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
return 0; return 0;
} }
/* 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 */ /* called with rtnl_lock */
static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 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); struct bnx2x *bp = netdev_priv(dev);
int port = BP_PORT(bp); struct mii_ioctl_data *mdio = if_mii(ifr);
int err;
switch (cmd) { DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
case SIOCGMIIPHY: mdio->phy_id, mdio->reg_num, mdio->val_in);
data->phy_id = bp->port.phy_addr;
/* fallthrough */ if (!netif_running(dev))
return -EAGAIN;
case SIOCGMIIREG: { return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
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;
} }
/* called with rtnl_lock */ /* called with rtnl_lock */
@ -11420,6 +11459,14 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->vlan_features |= NETIF_F_TSO6; dev->vlan_features |= NETIF_F_TSO6;
#endif #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; return 0;
err_out_unmap: err_out_unmap: