18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2009-2013 Solarflare Communications Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * Driver for PHY related operations via MCDI. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include "efx.h" 138c2ecf20Sopenharmony_ci#include "mcdi_port.h" 148c2ecf20Sopenharmony_ci#include "mcdi.h" 158c2ecf20Sopenharmony_ci#include "mcdi_pcol.h" 168c2ecf20Sopenharmony_ci#include "nic.h" 178c2ecf20Sopenharmony_ci#include "selftest.h" 188c2ecf20Sopenharmony_ci#include "mcdi_port_common.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int efx_mcdi_mdio_read(struct net_device *net_dev, 218c2ecf20Sopenharmony_ci int prtad, int devad, u16 addr) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 248c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_READ_IN_LEN); 258c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_READ_OUT_LEN); 268c2ecf20Sopenharmony_ci size_t outlen; 278c2ecf20Sopenharmony_ci int rc; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, efx->mdio_bus); 308c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); 318c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); 328c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), 358c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlen); 368c2ecf20Sopenharmony_ci if (rc) 378c2ecf20Sopenharmony_ci return rc; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS) != 408c2ecf20Sopenharmony_ci MC_CMD_MDIO_STATUS_GOOD) 418c2ecf20Sopenharmony_ci return -EIO; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int efx_mcdi_mdio_write(struct net_device *net_dev, 478c2ecf20Sopenharmony_ci int prtad, int devad, u16 addr, u16 value) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 508c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_WRITE_IN_LEN); 518c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_WRITE_OUT_LEN); 528c2ecf20Sopenharmony_ci size_t outlen; 538c2ecf20Sopenharmony_ci int rc; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, efx->mdio_bus); 568c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad); 578c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad); 588c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr); 598c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf), 628c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlen); 638c2ecf20Sopenharmony_ci if (rc) 648c2ecf20Sopenharmony_ci return rc; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS) != 678c2ecf20Sopenharmony_ci MC_CMD_MDIO_STATUS_GOOD) 688c2ecf20Sopenharmony_ci return -EIO; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciu32 efx_mcdi_phy_get_caps(struct efx_nic *efx) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct efx_mcdi_phy_data *phy_data = efx->phy_data; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return phy_data->supported_cap; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cibool efx_mcdi_mac_check_fault(struct efx_nic *efx) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); 838c2ecf20Sopenharmony_ci size_t outlength; 848c2ecf20Sopenharmony_ci int rc; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, 898c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlength); 908c2ecf20Sopenharmony_ci if (rc) 918c2ecf20Sopenharmony_ci return true; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint efx_mcdi_port_probe(struct efx_nic *efx) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci int rc; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Set up MDIO structure for PHY */ 1018c2ecf20Sopenharmony_ci efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; 1028c2ecf20Sopenharmony_ci efx->mdio.mdio_read = efx_mcdi_mdio_read; 1038c2ecf20Sopenharmony_ci efx->mdio.mdio_write = efx_mcdi_mdio_write; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Fill out MDIO structure, loopback modes, and initial link state */ 1068c2ecf20Sopenharmony_ci rc = efx_mcdi_phy_probe(efx); 1078c2ecf20Sopenharmony_ci if (rc != 0) 1088c2ecf20Sopenharmony_ci return rc; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return efx_mcdi_mac_init_stats(efx); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_civoid efx_mcdi_port_remove(struct efx_nic *efx) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci efx_mcdi_phy_remove(efx); 1168c2ecf20Sopenharmony_ci efx_mcdi_mac_fini_stats(efx); 1178c2ecf20Sopenharmony_ci} 118