mcdi_port.c revision d215697fe14a0c5a96765c6279b4751e632587a5
1afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings/**************************************************************************** 2afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * Driver for Solarflare Solarstorm network controllers and boards 3afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * Copyright 2009 Solarflare Communications Inc. 4afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * 5afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * This program is free software; you can redistribute it and/or modify it 6afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * under the terms of the GNU General Public License version 2 as published 7afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * by the Free Software Foundation, incorporated herein by reference. 8afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings */ 9afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 10afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings/* 11afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * Driver for PHY related operations via MCDI. 12afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings */ 13afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 15afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings#include "efx.h" 16afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings#include "phy.h" 17afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings#include "mcdi.h" 18afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings#include "mcdi_pcol.h" 19afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings#include "mdio_10g.h" 20affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson#include "nic.h" 21affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson#include "selftest.h" 22afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 233bd9303500b1961d15aae783f17075936026ae79Ben Hutchingsstruct efx_mcdi_phy_data { 24afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 flags; 25afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 type; 26afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 supported_cap; 27afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 channel; 28afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 port; 29afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 stats_mask; 30afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 name[20]; 31afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 media; 32afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 mmd_mask; 33afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 revision[20]; 34afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 forced_cap; 35afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings}; 36afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 37afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic int 383bd9303500b1961d15aae783f17075936026ae79Ben Hutchingsefx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg) 39afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 40afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN]; 41afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings size_t outlen; 42afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 43afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 44afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0); 45afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name)); 46afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 47afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0, 48afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings outbuf, sizeof(outbuf), &outlen); 49afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) 50afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 51afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 52afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { 5300bbb4a5344a5f81cf5d48e781e5c0df3e588d17Ben Hutchings rc = -EIO; 54afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 55afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 56afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 57afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS); 58afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE); 59afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->supported_cap = 60afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP); 61afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL); 62afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT); 63afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK); 64afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME), 65afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings sizeof(cfg->name)); 66afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE); 67afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK); 68afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION), 69afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings sizeof(cfg->revision)); 70afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 71afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 72afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 73afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsfail: 7462776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 75afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 76afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 77afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 78afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities, 79afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 flags, u32 loopback_mode, 80afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 loopback_speed) 81afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 82afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 inbuf[MC_CMD_SET_LINK_IN_LEN]; 83afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 84afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 85afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0); 86afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 87afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities); 88afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags); 89afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode); 90afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed); 91afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 92afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf), 93afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings NULL, 0, NULL); 94afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) 95afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 96afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 97afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 98afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 99afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsfail: 10062776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 101afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 102afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 103afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 104afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes) 105afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 106afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN]; 107afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings size_t outlen; 108afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 109afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 110afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0, 111afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings outbuf, sizeof(outbuf), &outlen); 112afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) 113afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 114afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 115afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) { 11600bbb4a5344a5f81cf5d48e781e5c0df3e588d17Ben Hutchings rc = -EIO; 117afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 118afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 119afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 120afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_SUGGESTED); 121afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 122afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 123afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 124afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsfail: 12562776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 126afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 127afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 128afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 129afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsint efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, 130afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings unsigned int prtad, unsigned int devad, u16 addr, 131afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u16 *value_out, u32 *status_out) 132afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 133afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 inbuf[MC_CMD_MDIO_READ_IN_LEN]; 134afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN]; 135afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings size_t outlen; 136afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 137afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 138afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus); 139afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); 140afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); 141afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); 142afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 143afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), 144afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings outbuf, sizeof(outbuf), &outlen); 145afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) 146afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 147afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 148afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); 149afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS); 150afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 151afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 152afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsfail: 15362776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 154afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 155afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 156afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 157afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsint efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, 158afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings unsigned int prtad, unsigned int devad, u16 addr, 159afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u16 value, u32 *status_out) 160afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 161afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 inbuf[MC_CMD_MDIO_WRITE_IN_LEN]; 162afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 outbuf[MC_CMD_MDIO_WRITE_OUT_LEN]; 163afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings size_t outlen; 164afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 165afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 166afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, bus); 167afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad); 168afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad); 169afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr); 170afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value); 171afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 172afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf), 173afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings outbuf, sizeof(outbuf), &outlen); 174afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) 175afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 176afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 177afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings *status_out = MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS); 178afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 179afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 180afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsfail: 18162776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 182afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 183afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 184afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 185afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic u32 mcdi_to_ethtool_cap(u32 media, u32 cap) 186afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 187afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 result = 0; 188afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 189afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings switch (media) { 190afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_KX4: 191afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_Backplane; 192afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) 193afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_1000baseKX_Full; 194afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) 195afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_10000baseKX4_Full; 196afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 197afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 198afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_XFP: 199afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_SFP_PLUS: 200afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_FIBRE; 201afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 202afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 203afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_BASE_T: 204afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_TP; 205afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) 206afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_10baseT_Half; 207afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) 208afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_10baseT_Full; 209afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) 210afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_100baseT_Half; 211afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) 212afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_100baseT_Full; 213afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) 214afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_1000baseT_Half; 215afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) 216afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_1000baseT_Full; 217afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) 218afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_10000baseT_Full; 219afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 220afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 221afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 222afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) 223afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_Pause; 224afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) 225afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_Asym_Pause; 226afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 227afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= SUPPORTED_Autoneg; 228afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 229afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return result; 230afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 231afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 232afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic u32 ethtool_to_mcdi_cap(u32 cap) 233afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 234afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 result = 0; 235afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 236afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_10baseT_Half) 237afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN); 238afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_10baseT_Full) 239afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN); 240afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_100baseT_Half) 241afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN); 242afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_100baseT_Full) 243afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN); 244afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_1000baseT_Half) 245afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN); 246afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full)) 247afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN); 248afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full)) 249afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN); 250afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_Pause) 251afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN); 252afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_Asym_Pause) 253afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN); 254afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (cap & SUPPORTED_Autoneg) 255afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings result |= (1 << MC_CMD_PHY_CAP_AN_LBN); 256afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 257afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return result; 258afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 259afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 260afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic u32 efx_get_mcdi_phy_flags(struct efx_nic *efx) 261afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 2623bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 263afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings enum efx_phy_mode mode, supported; 264afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 flags; 265afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 266afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings /* TODO: Advertise the capabilities supported by this PHY */ 267afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings supported = 0; 268afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_TXDIS_LBN)) 269afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings supported |= PHY_MODE_TX_DISABLED; 270afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_LOWPOWER_LBN)) 271afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings supported |= PHY_MODE_LOW_POWER; 272afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_POWEROFF_LBN)) 273afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings supported |= PHY_MODE_OFF; 274afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 275afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings mode = efx->phy_mode & supported; 276afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 277afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings flags = 0; 278afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (mode & PHY_MODE_TX_DISABLED) 279afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings flags |= (1 << MC_CMD_SET_LINK_TXDIS_LBN); 280afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (mode & PHY_MODE_LOW_POWER) 281afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings flags |= (1 << MC_CMD_SET_LINK_LOWPOWER_LBN); 282afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (mode & PHY_MODE_OFF) 283afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings flags |= (1 << MC_CMD_SET_LINK_POWEROFF_LBN); 284afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 285afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return flags; 286afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 287afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 288afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic u32 mcdi_to_ethtool_media(u32 media) 289afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 290afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings switch (media) { 291afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_XAUI: 292afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_CX4: 293afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_KX4: 294afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return PORT_OTHER; 295afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 296afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_XFP: 297afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_SFP_PLUS: 298afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return PORT_FIBRE; 299afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 300afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_MEDIA_BASE_T: 301afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return PORT_TP; 302afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 303afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings default: 304afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return PORT_OTHER; 305afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 306afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 307afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 308afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic int efx_mcdi_phy_probe(struct efx_nic *efx) 309afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 3103bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_data; 311ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; 312ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson u32 caps; 313afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 314afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 315ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson /* Initialise and populate phy_data */ 316ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); 317ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson if (phy_data == NULL) 318ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson return -ENOMEM; 319ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson 320ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson rc = efx_mcdi_get_phy_cfg(efx, phy_data); 321afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc != 0) 322afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 323afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 324ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson /* Read initial link advertisement */ 325ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); 326ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, 327ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson outbuf, sizeof(outbuf), NULL); 328ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson if (rc) 329ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson goto fail; 330ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson 331ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson /* Fill out nic state */ 332ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson efx->phy_data = phy_data; 333ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson efx->phy_type = phy_data->type; 334afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 335ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson efx->mdio_bus = phy_data->channel; 336ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson efx->mdio.prtad = phy_data->port; 337ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); 338afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->mdio.mode_support = 0; 339ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) 340afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->mdio.mode_support |= MDIO_SUPPORTS_C22; 341ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) 342afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; 343afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 344ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); 345ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) 346ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson efx->link_advertising = 347ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson mcdi_to_ethtool_cap(phy_data->media, caps); 348ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson else 349ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson phy_data->forced_cap = caps; 350ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson 351afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings /* Assert that we can map efx -> mcdi loopback modes */ 352afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); 353afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); 354afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); 355afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); 356afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); 357afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); 358afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); 359afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); 360afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); 361afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); 362afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); 363afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); 364afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); 365afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); 366afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); 367afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); 368afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); 369afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); 370afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); 371afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); 372afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); 373afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); 374afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); 375afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); 376afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); 377afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); 378afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); 379afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 380afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); 381afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc != 0) 382afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings goto fail; 383afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings /* The MC indicates that LOOPBACK_NONE is a valid loopback mode, 384afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * but by convention we don't */ 385afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->loopback_modes &= ~(1 << LOOPBACK_NONE); 386afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 3877a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson /* Set the initial link mode */ 3887a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson efx_mcdi_phy_decode_link( 3897a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson efx, &efx->link_state, 3907a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), 3917a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), 3927a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); 3937a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson 3947a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson /* Default to Autonegotiated flow control if the PHY supports it */ 3957a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; 3967a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 3977a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson efx->wanted_fc |= EFX_FC_AUTO; 398cffe9d4cdafdffa840abeb55c50fd2df2d7b0cdbSteve Hodgson efx_link_set_wanted_fc(efx, efx->wanted_fc); 3997a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson 400afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 401afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 402afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsfail: 403afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings kfree(phy_data); 404afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 405afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 406afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 407afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsint efx_mcdi_phy_reconfigure(struct efx_nic *efx) 408afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 4093bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 410afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 caps = (efx->link_advertising ? 411afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ethtool_to_mcdi_cap(efx->link_advertising) : 412afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings phy_cfg->forced_cap); 413afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 414afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), 415afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->loopback_mode, 0); 416afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 417afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 418afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsvoid efx_mcdi_phy_decode_link(struct efx_nic *efx, 419afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings struct efx_link_state *link_state, 420afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 speed, u32 flags, u32 fcntl) 421afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 422afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings switch (fcntl) { 423afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_FCNTL_AUTO: 424afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings WARN_ON(1); /* This is not a link mode */ 425afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX; 426afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 427afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_FCNTL_BIDIR: 428afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->fc = EFX_FC_TX | EFX_FC_RX; 429afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 430afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_FCNTL_RESPOND: 431afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->fc = EFX_FC_RX; 432afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 433afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings default: 434afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings WARN_ON(1); 435afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case MC_CMD_FCNTL_OFF: 436afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->fc = 0; 437afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings break; 438afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 439afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 440afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_LINK_UP_LBN)); 441afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_FULL_DUPLEX_LBN)); 442afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings link_state->speed = speed; 443afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 444afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 445afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings/* Verify that the forced flow control settings (!EFX_FC_AUTO) are 446afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * supported by the link partner. Warn the user if this isn't the case 447afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings */ 448afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsvoid efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) 449afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 4503bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 451afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 rmtadv; 452afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 453afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings /* The link partner capabilities are only relevent if the 454afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings * link supports flow control autonegotiation */ 4557a6b8f6f7f74085a1330b0f9765d81bcea8c58b7Steve Hodgson if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 456afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return; 457afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 458afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings /* If flow control autoneg is supported and enabled, then fine */ 459afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (efx->wanted_fc & EFX_FC_AUTO) 460afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return; 461afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 462afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rmtadv = 0; 463afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) 464afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rmtadv |= ADVERTISED_Pause; 465afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) 466afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rmtadv |= ADVERTISED_Asym_Pause; 467afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 468afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause) 46962776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, link, efx->net_dev, 47062776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings "warning: link partner doesn't support pause frames"); 471afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 472afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 473afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic bool efx_mcdi_phy_poll(struct efx_nic *efx) 474afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 475afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings struct efx_link_state old_state = efx->link_state; 476afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; 477afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 478afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 479afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings WARN_ON(!mutex_is_locked(&efx->mac_lock)); 480afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 481afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); 482afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 483afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, 484afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings outbuf, sizeof(outbuf), NULL); 485afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) { 48662776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", 48762776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings __func__, rc); 488afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->link_state.up = false; 489afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } else { 490afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx_mcdi_phy_decode_link( 491afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx, &efx->link_state, 492afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), 493afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), 494afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); 495afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 496afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 497afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return !efx_link_state_equal(&efx->link_state, &old_state); 498afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 499afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 500ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgsonstatic void efx_mcdi_phy_remove(struct efx_nic *efx) 501afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 502afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings struct efx_mcdi_phy_data *phy_data = efx->phy_data; 503afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 504afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->phy_data = NULL; 505afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings kfree(phy_data); 506afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 507afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 508afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) 509afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 5103bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 511afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; 512afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 513afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 514afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->supported = 515afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); 516afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->advertising = efx->link_advertising; 517afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->speed = efx->link_state.speed; 518afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->duplex = efx->link_state.fd; 519afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); 520afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->phy_address = phy_cfg->port; 521afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->transceiver = XCVR_INTERNAL; 522afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); 523afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->mdio_support = (efx->mdio.mode_support & 524afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); 525afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 526afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); 527afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, 528afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings outbuf, sizeof(outbuf), NULL); 529afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) { 53062776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", 53162776d034cc40c49bafdb3551a6ba35f78e3f08dBen Hutchings __func__, rc); 532afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return; 533afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 534afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings ecmd->lp_advertising = 535afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings mcdi_to_ethtool_cap(phy_cfg->media, 536afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); 537afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 538afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 539afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstatic int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) 540afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings{ 5413bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 542afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings u32 caps; 543afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings int rc; 544afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 545afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (ecmd->autoneg) { 546afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings caps = (ethtool_to_mcdi_cap(ecmd->advertising) | 547afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 1 << MC_CMD_PHY_CAP_AN_LBN); 548afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } else if (ecmd->duplex) { 549afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings switch (ecmd->speed) { 550afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; 551afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; 552afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; 553afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break; 554afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings default: return -EINVAL; 555afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 556afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } else { 557afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings switch (ecmd->speed) { 558afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; 559afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; 560afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; 561afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings default: return -EINVAL; 562afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 563afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 564afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 565afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), 566afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx->loopback_mode, 0); 567afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (rc) 568afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return rc; 569afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 570afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings if (ecmd->autoneg) { 571afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx_link_set_advertising( 572afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx, ecmd->advertising | ADVERTISED_Autoneg); 573afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings phy_cfg->forced_cap = 0; 574afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } else { 575afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings efx_link_set_advertising(efx, 0); 576afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings phy_cfg->forced_cap = caps; 577afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings } 578afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings return 0; 579afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings} 580afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings 5814f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchingsstatic int efx_mcdi_phy_test_alive(struct efx_nic *efx) 5824f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings{ 5834f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN]; 5844f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings size_t outlen; 5854f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings int rc; 5864f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings 5874f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0); 5884f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings 5894f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0, 5904f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings outbuf, sizeof(outbuf), &outlen); 5914f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings if (rc) 5924f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings return rc; 5934f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings 5944f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN) 59500bbb4a5344a5f81cf5d48e781e5c0df3e588d17Ben Hutchings return -EIO; 5964f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK) 5974f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings return -EINVAL; 5984f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings 5994f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings return 0; 6004f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings} 6014f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings 602affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgsonstatic const char *const mcdi_sft9001_cable_diag_names[] = { 603affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairA.length", 604affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairB.length", 605affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairC.length", 606affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairD.length", 607affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairA.status", 608affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairB.status", 609affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairC.status", 610affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson "cable.pairD.status", 611affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson}; 612affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 613affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgsonstatic int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode, 614affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson int *results) 615affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson{ 616affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson unsigned int retry, i, count = 0; 617affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson size_t outlen; 618affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson u32 status; 619affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson u8 *buf, *ptr; 620affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson int rc; 621affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 622affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson buf = kzalloc(0x100, GFP_KERNEL); 623affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (buf == NULL) 624affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return -ENOMEM; 625affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 626affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0); 627affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode); 628affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN, 629affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson NULL, 0, NULL); 630affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (rc) 631affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson goto out; 632affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 633affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson /* Wait up to 10s for BIST to finish */ 634affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson for (retry = 0; retry < 100; ++retry) { 635affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0); 636affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0, 637affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson buf, 0x100, &outlen); 638affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (rc) 639affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson goto out; 640affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 641affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT); 642affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (status != MC_CMD_POLL_BIST_RUNNING) 643affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson goto finished; 644affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 645affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson msleep(100); 646affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 647affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 648affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson rc = -ETIMEDOUT; 649affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson goto out; 650affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 651affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgsonfinished: 652affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1; 653affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 654affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson /* SFT9001 specific cable diagnostics output */ 655affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (efx->phy_type == PHY_TYPE_SFT9001B && 656affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT || 657affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) { 658affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); 659affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (status == MC_CMD_POLL_BIST_PASSED && 660affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) { 661affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson for (i = 0; i < 8; i++) { 662affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson results[count + i] = 663affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i], 664affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson EFX_DWORD_0); 665affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 666affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 667affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson count += 8; 668affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 669affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson rc = count; 670affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 671affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgsonout: 672affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson kfree(buf); 673affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 674affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return rc; 675affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson} 676affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 677affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgsonstatic int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results, 678affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson unsigned flags) 679affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson{ 6803bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 681affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson u32 mode; 682affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson int rc; 683affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 684affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) { 685affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results); 686affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (rc < 0) 687affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return rc; 688affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 689affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson results += rc; 690affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 691affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 692affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson /* If we support both LONG and SHORT, then run each in response to 693affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson * break or not. Otherwise, run the one we support */ 694affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson mode = 0; 695affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN)) { 696affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if ((flags & ETH_TEST_FL_OFFLINE) && 697affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson (phy_cfg->flags & 698affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) 699affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson mode = MC_CMD_PHY_BIST_CABLE_LONG; 700affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson else 701affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson mode = MC_CMD_PHY_BIST_CABLE_SHORT; 702affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } else if (phy_cfg->flags & 703affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN)) 704affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson mode = MC_CMD_PHY_BIST_CABLE_LONG; 705affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 706affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (mode != 0) { 707affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson rc = efx_mcdi_bist(efx, mode, results); 708affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (rc < 0) 709affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return rc; 710affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson results += rc; 711affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 712affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 713affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return 0; 714affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson} 715affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 716d215697fe14a0c5a96765c6279b4751e632587a5stephen hemmingerstatic const char *efx_mcdi_phy_test_name(struct efx_nic *efx, 717d215697fe14a0c5a96765c6279b4751e632587a5stephen hemminger unsigned int index) 718affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson{ 7193bd9303500b1961d15aae783f17075936026ae79Ben Hutchings struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; 720affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 721affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) { 722affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (index == 0) 723affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return "bist"; 724affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson --index; 725affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 726affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 727affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN) | 728affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) { 729affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (index == 0) 730affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return "cable"; 731affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson --index; 732affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 733affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (efx->phy_type == PHY_TYPE_SFT9001B) { 734affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names)) 735affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return mcdi_sft9001_cable_diag_names[index]; 736affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names); 737affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 738affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson } 739affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 740affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson return NULL; 741affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson} 742affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson 743afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchingsstruct efx_phy_operations efx_mcdi_phy_ops = { 744afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings .probe = efx_mcdi_phy_probe, 745ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson .init = efx_port_dummy_op_int, 746afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings .reconfigure = efx_mcdi_phy_reconfigure, 747afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings .poll = efx_mcdi_phy_poll, 748ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson .fini = efx_port_dummy_op_void, 749ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4Steve Hodgson .remove = efx_mcdi_phy_remove, 750afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings .get_settings = efx_mcdi_phy_get_settings, 751afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings .set_settings = efx_mcdi_phy_set_settings, 7524f16c0739145476ba37a7fa9eea0c33850efc2ceBen Hutchings .test_alive = efx_mcdi_phy_test_alive, 753affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson .run_tests = efx_mcdi_phy_run_tests, 754affaf485ca628cb7d7f57ae5e2b8c710c58b11aaSteve Hodgson .test_name = efx_mcdi_phy_test_name, 755afd4aea03f597f29421dc5767e7d1f754730ec23Ben Hutchings}; 756