Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /****************************************************************************
0003  * Driver for Solarflare network controllers and boards
0004  * Copyright 2009-2013 Solarflare Communications Inc.
0005  */
0006 
0007 /*
0008  * Driver for PHY related operations via MCDI.
0009  */
0010 
0011 #include <linux/slab.h>
0012 #include "efx.h"
0013 #include "mcdi_port.h"
0014 #include "mcdi.h"
0015 #include "mcdi_pcol.h"
0016 #include "nic.h"
0017 #include "selftest.h"
0018 #include "mcdi_port_common.h"
0019 
0020 static int efx_mcdi_mdio_read(struct net_device *net_dev,
0021                   int prtad, int devad, u16 addr)
0022 {
0023     struct efx_nic *efx = efx_netdev_priv(net_dev);
0024     MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_READ_IN_LEN);
0025     MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_READ_OUT_LEN);
0026     size_t outlen;
0027     int rc;
0028 
0029     MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, efx->mdio_bus);
0030     MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad);
0031     MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad);
0032     MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr);
0033 
0034     rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf),
0035               outbuf, sizeof(outbuf), &outlen);
0036     if (rc)
0037         return rc;
0038 
0039     if (MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS) !=
0040         MC_CMD_MDIO_STATUS_GOOD)
0041         return -EIO;
0042 
0043     return (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE);
0044 }
0045 
0046 static int efx_mcdi_mdio_write(struct net_device *net_dev,
0047                    int prtad, int devad, u16 addr, u16 value)
0048 {
0049     struct efx_nic *efx = efx_netdev_priv(net_dev);
0050     MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_WRITE_IN_LEN);
0051     MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_WRITE_OUT_LEN);
0052     size_t outlen;
0053     int rc;
0054 
0055     MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, efx->mdio_bus);
0056     MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad);
0057     MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad);
0058     MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr);
0059     MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value);
0060 
0061     rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf),
0062               outbuf, sizeof(outbuf), &outlen);
0063     if (rc)
0064         return rc;
0065 
0066     if (MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS) !=
0067         MC_CMD_MDIO_STATUS_GOOD)
0068         return -EIO;
0069 
0070     return 0;
0071 }
0072 
0073 u32 efx_mcdi_phy_get_caps(struct efx_nic *efx)
0074 {
0075     struct efx_mcdi_phy_data *phy_data = efx->phy_data;
0076 
0077     return phy_data->supported_cap;
0078 }
0079 
0080 bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
0081 {
0082     MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
0083     size_t outlength;
0084     int rc;
0085 
0086     BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
0087 
0088     rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
0089               outbuf, sizeof(outbuf), &outlength);
0090     if (rc)
0091         return true;
0092 
0093     return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0;
0094 }
0095 
0096 int efx_mcdi_port_probe(struct efx_nic *efx)
0097 {
0098     int rc;
0099 
0100     /* Set up MDIO structure for PHY */
0101     efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
0102     efx->mdio.mdio_read = efx_mcdi_mdio_read;
0103     efx->mdio.mdio_write = efx_mcdi_mdio_write;
0104 
0105     /* Fill out MDIO structure, loopback modes, and initial link state */
0106     rc = efx_mcdi_phy_probe(efx);
0107     if (rc != 0)
0108         return rc;
0109 
0110     return efx_mcdi_mac_init_stats(efx);
0111 }
0112 
0113 void efx_mcdi_port_remove(struct efx_nic *efx)
0114 {
0115     efx_mcdi_phy_remove(efx);
0116     efx_mcdi_mac_fini_stats(efx);
0117 }