root/drivers/net/ethernet/sfc/falcon/mdio_10g.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ef4_mdio_id_oui
  2. ef4_mdio_reset_mmd
  3. ef4_mdio_check_mmd
  4. ef4_mdio_wait_reset_mmds
  5. ef4_mdio_check_mmds
  6. ef4_mdio_links_ok
  7. ef4_mdio_transmit_disable
  8. ef4_mdio_phy_reconfigure
  9. ef4_mdio_set_mmd_lpower
  10. ef4_mdio_set_mmds_lpower
  11. ef4_mdio_set_link_ksettings
  12. ef4_mdio_an_reconfigure
  13. ef4_mdio_get_pause
  14. ef4_mdio_test_alive

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /****************************************************************************
   3  * Driver for Solarflare network controllers and boards
   4  * Copyright 2006-2011 Solarflare Communications Inc.
   5  */
   6 /*
   7  * Useful functions for working with MDIO clause 45 PHYs
   8  */
   9 #include <linux/types.h>
  10 #include <linux/ethtool.h>
  11 #include <linux/delay.h>
  12 #include "net_driver.h"
  13 #include "mdio_10g.h"
  14 #include "workarounds.h"
  15 
  16 unsigned ef4_mdio_id_oui(u32 id)
  17 {
  18         unsigned oui = 0;
  19         int i;
  20 
  21         /* The bits of the OUI are designated a..x, with a=0 and b variable.
  22          * In the id register c is the MSB but the OUI is conventionally
  23          * written as bytes h..a, p..i, x..q.  Reorder the bits accordingly. */
  24         for (i = 0; i < 22; ++i)
  25                 if (id & (1 << (i + 10)))
  26                         oui |= 1 << (i ^ 7);
  27 
  28         return oui;
  29 }
  30 
  31 int ef4_mdio_reset_mmd(struct ef4_nic *port, int mmd,
  32                             int spins, int spintime)
  33 {
  34         u32 ctrl;
  35 
  36         /* Catch callers passing values in the wrong units (or just silly) */
  37         EF4_BUG_ON_PARANOID(spins * spintime >= 5000);
  38 
  39         ef4_mdio_write(port, mmd, MDIO_CTRL1, MDIO_CTRL1_RESET);
  40         /* Wait for the reset bit to clear. */
  41         do {
  42                 msleep(spintime);
  43                 ctrl = ef4_mdio_read(port, mmd, MDIO_CTRL1);
  44                 spins--;
  45 
  46         } while (spins && (ctrl & MDIO_CTRL1_RESET));
  47 
  48         return spins ? spins : -ETIMEDOUT;
  49 }
  50 
  51 static int ef4_mdio_check_mmd(struct ef4_nic *efx, int mmd)
  52 {
  53         int status;
  54 
  55         if (mmd != MDIO_MMD_AN) {
  56                 /* Read MMD STATUS2 to check it is responding. */
  57                 status = ef4_mdio_read(efx, mmd, MDIO_STAT2);
  58                 if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) {
  59                         netif_err(efx, hw, efx->net_dev,
  60                                   "PHY MMD %d not responding.\n", mmd);
  61                         return -EIO;
  62                 }
  63         }
  64 
  65         return 0;
  66 }
  67 
  68 /* This ought to be ridiculous overkill. We expect it to fail rarely */
  69 #define MDIO45_RESET_TIME       1000 /* ms */
  70 #define MDIO45_RESET_ITERS      100
  71 
  72 int ef4_mdio_wait_reset_mmds(struct ef4_nic *efx, unsigned int mmd_mask)
  73 {
  74         const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
  75         int tries = MDIO45_RESET_ITERS;
  76         int rc = 0;
  77         int in_reset;
  78 
  79         while (tries) {
  80                 int mask = mmd_mask;
  81                 int mmd = 0;
  82                 int stat;
  83                 in_reset = 0;
  84                 while (mask) {
  85                         if (mask & 1) {
  86                                 stat = ef4_mdio_read(efx, mmd, MDIO_CTRL1);
  87                                 if (stat < 0) {
  88                                         netif_err(efx, hw, efx->net_dev,
  89                                                   "failed to read status of"
  90                                                   " MMD %d\n", mmd);
  91                                         return -EIO;
  92                                 }
  93                                 if (stat & MDIO_CTRL1_RESET)
  94                                         in_reset |= (1 << mmd);
  95                         }
  96                         mask = mask >> 1;
  97                         mmd++;
  98                 }
  99                 if (!in_reset)
 100                         break;
 101                 tries--;
 102                 msleep(spintime);
 103         }
 104         if (in_reset != 0) {
 105                 netif_err(efx, hw, efx->net_dev,
 106                           "not all MMDs came out of reset in time."
 107                           " MMDs still in reset: %x\n", in_reset);
 108                 rc = -ETIMEDOUT;
 109         }
 110         return rc;
 111 }
 112 
 113 int ef4_mdio_check_mmds(struct ef4_nic *efx, unsigned int mmd_mask)
 114 {
 115         int mmd = 0, probe_mmd, devs1, devs2;
 116         u32 devices;
 117 
 118         /* Historically we have probed the PHYXS to find out what devices are
 119          * present,but that doesn't work so well if the PHYXS isn't expected
 120          * to exist, if so just find the first item in the list supplied. */
 121         probe_mmd = (mmd_mask & MDIO_DEVS_PHYXS) ? MDIO_MMD_PHYXS :
 122             __ffs(mmd_mask);
 123 
 124         /* Check all the expected MMDs are present */
 125         devs1 = ef4_mdio_read(efx, probe_mmd, MDIO_DEVS1);
 126         devs2 = ef4_mdio_read(efx, probe_mmd, MDIO_DEVS2);
 127         if (devs1 < 0 || devs2 < 0) {
 128                 netif_err(efx, hw, efx->net_dev,
 129                           "failed to read devices present\n");
 130                 return -EIO;
 131         }
 132         devices = devs1 | (devs2 << 16);
 133         if ((devices & mmd_mask) != mmd_mask) {
 134                 netif_err(efx, hw, efx->net_dev,
 135                           "required MMDs not present: got %x, wanted %x\n",
 136                           devices, mmd_mask);
 137                 return -ENODEV;
 138         }
 139         netif_vdbg(efx, hw, efx->net_dev, "Devices present: %x\n", devices);
 140 
 141         /* Check all required MMDs are responding and happy. */
 142         while (mmd_mask) {
 143                 if ((mmd_mask & 1) && ef4_mdio_check_mmd(efx, mmd))
 144                         return -EIO;
 145                 mmd_mask = mmd_mask >> 1;
 146                 mmd++;
 147         }
 148 
 149         return 0;
 150 }
 151 
 152 bool ef4_mdio_links_ok(struct ef4_nic *efx, unsigned int mmd_mask)
 153 {
 154         /* If the port is in loopback, then we should only consider a subset
 155          * of mmd's */
 156         if (LOOPBACK_INTERNAL(efx))
 157                 return true;
 158         else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS)
 159                 return false;
 160         else if (ef4_phy_mode_disabled(efx->phy_mode))
 161                 return false;
 162         else if (efx->loopback_mode == LOOPBACK_PHYXS)
 163                 mmd_mask &= ~(MDIO_DEVS_PHYXS |
 164                               MDIO_DEVS_PCS |
 165                               MDIO_DEVS_PMAPMD |
 166                               MDIO_DEVS_AN);
 167         else if (efx->loopback_mode == LOOPBACK_PCS)
 168                 mmd_mask &= ~(MDIO_DEVS_PCS |
 169                               MDIO_DEVS_PMAPMD |
 170                               MDIO_DEVS_AN);
 171         else if (efx->loopback_mode == LOOPBACK_PMAPMD)
 172                 mmd_mask &= ~(MDIO_DEVS_PMAPMD |
 173                               MDIO_DEVS_AN);
 174 
 175         return mdio45_links_ok(&efx->mdio, mmd_mask);
 176 }
 177 
 178 void ef4_mdio_transmit_disable(struct ef4_nic *efx)
 179 {
 180         ef4_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
 181                           MDIO_PMA_TXDIS, MDIO_PMD_TXDIS_GLOBAL,
 182                           efx->phy_mode & PHY_MODE_TX_DISABLED);
 183 }
 184 
 185 void ef4_mdio_phy_reconfigure(struct ef4_nic *efx)
 186 {
 187         ef4_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
 188                           MDIO_CTRL1, MDIO_PMA_CTRL1_LOOPBACK,
 189                           efx->loopback_mode == LOOPBACK_PMAPMD);
 190         ef4_mdio_set_flag(efx, MDIO_MMD_PCS,
 191                           MDIO_CTRL1, MDIO_PCS_CTRL1_LOOPBACK,
 192                           efx->loopback_mode == LOOPBACK_PCS);
 193         ef4_mdio_set_flag(efx, MDIO_MMD_PHYXS,
 194                           MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK,
 195                           efx->loopback_mode == LOOPBACK_PHYXS_WS);
 196 }
 197 
 198 static void ef4_mdio_set_mmd_lpower(struct ef4_nic *efx,
 199                                     int lpower, int mmd)
 200 {
 201         int stat = ef4_mdio_read(efx, mmd, MDIO_STAT1);
 202 
 203         netif_vdbg(efx, drv, efx->net_dev, "Setting low power mode for MMD %d to %d\n",
 204                   mmd, lpower);
 205 
 206         if (stat & MDIO_STAT1_LPOWERABLE) {
 207                 ef4_mdio_set_flag(efx, mmd, MDIO_CTRL1,
 208                                   MDIO_CTRL1_LPOWER, lpower);
 209         }
 210 }
 211 
 212 void ef4_mdio_set_mmds_lpower(struct ef4_nic *efx,
 213                               int low_power, unsigned int mmd_mask)
 214 {
 215         int mmd = 0;
 216         mmd_mask &= ~MDIO_DEVS_AN;
 217         while (mmd_mask) {
 218                 if (mmd_mask & 1)
 219                         ef4_mdio_set_mmd_lpower(efx, low_power, mmd);
 220                 mmd_mask = (mmd_mask >> 1);
 221                 mmd++;
 222         }
 223 }
 224 
 225 /**
 226  * ef4_mdio_set_link_ksettings - Set (some of) the PHY settings over MDIO.
 227  * @efx:                Efx NIC
 228  * @cmd:                New settings
 229  */
 230 int ef4_mdio_set_link_ksettings(struct ef4_nic *efx,
 231                                 const struct ethtool_link_ksettings *cmd)
 232 {
 233         struct ethtool_link_ksettings prev = {
 234                 .base.cmd = ETHTOOL_GLINKSETTINGS
 235         };
 236         u32 prev_advertising, advertising;
 237         u32 prev_supported;
 238 
 239         efx->phy_op->get_link_ksettings(efx, &prev);
 240 
 241         ethtool_convert_link_mode_to_legacy_u32(&advertising,
 242                                                 cmd->link_modes.advertising);
 243         ethtool_convert_link_mode_to_legacy_u32(&prev_advertising,
 244                                                 prev.link_modes.advertising);
 245         ethtool_convert_link_mode_to_legacy_u32(&prev_supported,
 246                                                 prev.link_modes.supported);
 247 
 248         if (advertising == prev_advertising &&
 249             cmd->base.speed == prev.base.speed &&
 250             cmd->base.duplex == prev.base.duplex &&
 251             cmd->base.port == prev.base.port &&
 252             cmd->base.autoneg == prev.base.autoneg)
 253                 return 0;
 254 
 255         /* We can only change these settings for -T PHYs */
 256         if (prev.base.port != PORT_TP || cmd->base.port != PORT_TP)
 257                 return -EINVAL;
 258 
 259         /* Check that PHY supports these settings */
 260         if (!cmd->base.autoneg ||
 261             (advertising | SUPPORTED_Autoneg) & ~prev_supported)
 262                 return -EINVAL;
 263 
 264         ef4_link_set_advertising(efx, advertising | ADVERTISED_Autoneg);
 265         ef4_mdio_an_reconfigure(efx);
 266         return 0;
 267 }
 268 
 269 /**
 270  * ef4_mdio_an_reconfigure - Push advertising flags and restart autonegotiation
 271  * @efx:                Efx NIC
 272  */
 273 void ef4_mdio_an_reconfigure(struct ef4_nic *efx)
 274 {
 275         int reg;
 276 
 277         WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
 278 
 279         /* Set up the base page */
 280         reg = ADVERTISE_CSMA | ADVERTISE_RESV;
 281         if (efx->link_advertising & ADVERTISED_Pause)
 282                 reg |= ADVERTISE_PAUSE_CAP;
 283         if (efx->link_advertising & ADVERTISED_Asym_Pause)
 284                 reg |= ADVERTISE_PAUSE_ASYM;
 285         ef4_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
 286 
 287         /* Set up the (extended) next page */
 288         efx->phy_op->set_npage_adv(efx, efx->link_advertising);
 289 
 290         /* Enable and restart AN */
 291         reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
 292         reg |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART | MDIO_AN_CTRL1_XNP;
 293         ef4_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
 294 }
 295 
 296 u8 ef4_mdio_get_pause(struct ef4_nic *efx)
 297 {
 298         BUILD_BUG_ON(EF4_FC_AUTO & (EF4_FC_RX | EF4_FC_TX));
 299 
 300         if (!(efx->wanted_fc & EF4_FC_AUTO))
 301                 return efx->wanted_fc;
 302 
 303         WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
 304 
 305         return mii_resolve_flowctrl_fdx(
 306                 mii_advertise_flowctrl(efx->wanted_fc),
 307                 ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA));
 308 }
 309 
 310 int ef4_mdio_test_alive(struct ef4_nic *efx)
 311 {
 312         int rc;
 313         int devad = __ffs(efx->mdio.mmds);
 314         u16 physid1, physid2;
 315 
 316         mutex_lock(&efx->mac_lock);
 317 
 318         physid1 = ef4_mdio_read(efx, devad, MDIO_DEVID1);
 319         physid2 = ef4_mdio_read(efx, devad, MDIO_DEVID2);
 320 
 321         if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
 322             (physid2 == 0x0000) || (physid2 == 0xffff)) {
 323                 netif_err(efx, hw, efx->net_dev,
 324                           "no MDIO PHY present with ID %d\n", efx->mdio.prtad);
 325                 rc = -EINVAL;
 326         } else {
 327                 rc = ef4_mdio_check_mmds(efx, efx->mdio.mmds);
 328         }
 329 
 330         mutex_unlock(&efx->mac_lock);
 331         return rc;
 332 }

/* [<][>][^][v][top][bottom][index][help] */