Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.28-rc6 360 lines 10 kB view raw
1/**************************************************************************** 2 * Driver for Solarflare Solarstorm network controllers and boards 3 * Copyright 2006-2008 Solarflare Communications Inc. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published 7 * by the Free Software Foundation, incorporated herein by reference. 8 */ 9/* 10 * Useful functions for working with MDIO clause 45 PHYs 11 */ 12#include <linux/types.h> 13#include <linux/ethtool.h> 14#include <linux/delay.h> 15#include "net_driver.h" 16#include "mdio_10g.h" 17#include "boards.h" 18 19int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, 20 int spins, int spintime) 21{ 22 u32 ctrl; 23 int phy_id = port->mii.phy_id; 24 25 /* Catch callers passing values in the wrong units (or just silly) */ 26 EFX_BUG_ON_PARANOID(spins * spintime >= 5000); 27 28 mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1, 29 (1 << MDIO_MMDREG_CTRL1_RESET_LBN)); 30 /* Wait for the reset bit to clear. */ 31 do { 32 msleep(spintime); 33 ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1); 34 spins--; 35 36 } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))); 37 38 return spins ? spins : -ETIMEDOUT; 39} 40 41static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, 42 int fault_fatal) 43{ 44 int status; 45 int phy_id = efx->mii.phy_id; 46 47 if (LOOPBACK_INTERNAL(efx)) 48 return 0; 49 50 /* Read MMD STATUS2 to check it is responding. */ 51 status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2); 52 if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & 53 ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != 54 MDIO_MMDREG_STAT2_PRESENT_VAL) { 55 EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); 56 return -EIO; 57 } 58 59 /* Read MMD STATUS 1 to check for fault. */ 60 status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1); 61 if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) { 62 if (fault_fatal) { 63 EFX_ERR(efx, "PHY MMD %d reporting fatal" 64 " fault: status %x\n", mmd, status); 65 return -EIO; 66 } else { 67 EFX_LOG(efx, "PHY MMD %d reporting status" 68 " %x (expected)\n", mmd, status); 69 } 70 } 71 return 0; 72} 73 74/* This ought to be ridiculous overkill. We expect it to fail rarely */ 75#define MDIO45_RESET_TIME 1000 /* ms */ 76#define MDIO45_RESET_ITERS 100 77 78int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, 79 unsigned int mmd_mask) 80{ 81 const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS; 82 int tries = MDIO45_RESET_ITERS; 83 int rc = 0; 84 int in_reset; 85 86 while (tries) { 87 int mask = mmd_mask; 88 int mmd = 0; 89 int stat; 90 in_reset = 0; 91 while (mask) { 92 if (mask & 1) { 93 stat = mdio_clause45_read(efx, 94 efx->mii.phy_id, 95 mmd, 96 MDIO_MMDREG_CTRL1); 97 if (stat < 0) { 98 EFX_ERR(efx, "failed to read status of" 99 " MMD %d\n", mmd); 100 return -EIO; 101 } 102 if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) 103 in_reset |= (1 << mmd); 104 } 105 mask = mask >> 1; 106 mmd++; 107 } 108 if (!in_reset) 109 break; 110 tries--; 111 msleep(spintime); 112 } 113 if (in_reset != 0) { 114 EFX_ERR(efx, "not all MMDs came out of reset in time." 115 " MMDs still in reset: %x\n", in_reset); 116 rc = -ETIMEDOUT; 117 } 118 return rc; 119} 120 121int mdio_clause45_check_mmds(struct efx_nic *efx, 122 unsigned int mmd_mask, unsigned int fatal_mask) 123{ 124 int devices, mmd = 0; 125 int probe_mmd; 126 127 /* Historically we have probed the PHYXS to find out what devices are 128 * present,but that doesn't work so well if the PHYXS isn't expected 129 * to exist, if so just find the first item in the list supplied. */ 130 probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS : 131 __ffs(mmd_mask); 132 devices = mdio_clause45_read(efx, efx->mii.phy_id, 133 probe_mmd, MDIO_MMDREG_DEVS0); 134 135 /* Check all the expected MMDs are present */ 136 if (devices < 0) { 137 EFX_ERR(efx, "failed to read devices present\n"); 138 return -EIO; 139 } 140 if ((devices & mmd_mask) != mmd_mask) { 141 EFX_ERR(efx, "required MMDs not present: got %x, " 142 "wanted %x\n", devices, mmd_mask); 143 return -ENODEV; 144 } 145 EFX_TRACE(efx, "Devices present: %x\n", devices); 146 147 /* Check all required MMDs are responding and happy. */ 148 while (mmd_mask) { 149 if (mmd_mask & 1) { 150 int fault_fatal = fatal_mask & 1; 151 if (mdio_clause45_check_mmd(efx, mmd, fault_fatal)) 152 return -EIO; 153 } 154 mmd_mask = mmd_mask >> 1; 155 fatal_mask = fatal_mask >> 1; 156 mmd++; 157 } 158 159 return 0; 160} 161 162bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) 163{ 164 int phy_id = efx->mii.phy_id; 165 int status; 166 bool ok = true; 167 int mmd = 0; 168 169 /* If the port is in loopback, then we should only consider a subset 170 * of mmd's */ 171 if (LOOPBACK_INTERNAL(efx)) 172 return true; 173 else if (efx->loopback_mode == LOOPBACK_NETWORK) 174 return false; 175 else if (efx_phy_mode_disabled(efx->phy_mode)) 176 return false; 177 else if (efx->loopback_mode == LOOPBACK_PHYXS) 178 mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS | 179 MDIO_MMDREG_DEVS0_PCS | 180 MDIO_MMDREG_DEVS0_PMAPMD); 181 else if (efx->loopback_mode == LOOPBACK_PCS) 182 mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS | 183 MDIO_MMDREG_DEVS0_PMAPMD); 184 else if (efx->loopback_mode == LOOPBACK_PMAPMD) 185 mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD; 186 187 while (mmd_mask) { 188 if (mmd_mask & 1) { 189 /* Double reads because link state is latched, and a 190 * read moves the current state into the register */ 191 status = mdio_clause45_read(efx, phy_id, 192 mmd, MDIO_MMDREG_STAT1); 193 status = mdio_clause45_read(efx, phy_id, 194 mmd, MDIO_MMDREG_STAT1); 195 196 ok = ok && (status & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); 197 } 198 mmd_mask = (mmd_mask >> 1); 199 mmd++; 200 } 201 return ok; 202} 203 204void mdio_clause45_transmit_disable(struct efx_nic *efx) 205{ 206 int phy_id = efx->mii.phy_id; 207 int ctrl1, ctrl2; 208 209 ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, 210 MDIO_MMDREG_TXDIS); 211 if (efx->phy_mode & PHY_MODE_TX_DISABLED) 212 ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); 213 else 214 ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); 215 if (ctrl1 != ctrl2) 216 mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, 217 MDIO_MMDREG_TXDIS, ctrl2); 218} 219 220void mdio_clause45_phy_reconfigure(struct efx_nic *efx) 221{ 222 int phy_id = efx->mii.phy_id; 223 int ctrl1, ctrl2; 224 225 /* Handle (with debouncing) PMA/PMD loopback */ 226 ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, 227 MDIO_MMDREG_CTRL1); 228 229 if (efx->loopback_mode == LOOPBACK_PMAPMD) 230 ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN); 231 else 232 ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN); 233 234 if (ctrl1 != ctrl2) 235 mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, 236 MDIO_MMDREG_CTRL1, ctrl2); 237 238 /* Handle (with debouncing) PCS loopback */ 239 ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, 240 MDIO_MMDREG_CTRL1); 241 if (efx->loopback_mode == LOOPBACK_PCS) 242 ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN); 243 else 244 ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN); 245 246 if (ctrl1 != ctrl2) 247 mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS, 248 MDIO_MMDREG_CTRL1, ctrl2); 249 250 /* Handle (with debouncing) PHYXS network loopback */ 251 ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, 252 MDIO_MMDREG_CTRL1); 253 if (efx->loopback_mode == LOOPBACK_NETWORK) 254 ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN); 255 else 256 ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN); 257 258 if (ctrl1 != ctrl2) 259 mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS, 260 MDIO_MMDREG_CTRL1, ctrl2); 261} 262 263/** 264 * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. 265 * @efx: Efx NIC 266 * @ecmd: Buffer for settings 267 * 268 * On return the 'port', 'speed', 'supported' and 'advertising' fields of 269 * ecmd have been filled out based on the PMA type. 270 */ 271void mdio_clause45_get_settings(struct efx_nic *efx, 272 struct ethtool_cmd *ecmd) 273{ 274 int pma_type; 275 276 /* If no PMA is present we are presumably talking something XAUI-ish 277 * like CX4. Which we report as FIBRE (see below) */ 278 if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) { 279 ecmd->speed = SPEED_10000; 280 ecmd->port = PORT_FIBRE; 281 ecmd->supported = SUPPORTED_FIBRE; 282 ecmd->advertising = ADVERTISED_FIBRE; 283 return; 284 } 285 286 pma_type = mdio_clause45_read(efx, efx->mii.phy_id, 287 MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2); 288 pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK; 289 290 switch (pma_type) { 291 /* We represent CX4 as fibre in the absence of anything 292 better. */ 293 case MDIO_PMAPMD_CTRL2_10G_CX4: 294 ecmd->speed = SPEED_10000; 295 ecmd->port = PORT_FIBRE; 296 ecmd->supported = SUPPORTED_FIBRE; 297 ecmd->advertising = ADVERTISED_FIBRE; 298 break; 299 /* 10G Base-T */ 300 case MDIO_PMAPMD_CTRL2_10G_BT: 301 ecmd->speed = SPEED_10000; 302 ecmd->port = PORT_TP; 303 ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full; 304 ecmd->advertising = (ADVERTISED_FIBRE 305 | ADVERTISED_10000baseT_Full); 306 break; 307 case MDIO_PMAPMD_CTRL2_1G_BT: 308 ecmd->speed = SPEED_1000; 309 ecmd->port = PORT_TP; 310 ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full; 311 ecmd->advertising = (ADVERTISED_FIBRE 312 | ADVERTISED_1000baseT_Full); 313 break; 314 case MDIO_PMAPMD_CTRL2_100_BT: 315 ecmd->speed = SPEED_100; 316 ecmd->port = PORT_TP; 317 ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full; 318 ecmd->advertising = (ADVERTISED_FIBRE 319 | ADVERTISED_100baseT_Full); 320 break; 321 case MDIO_PMAPMD_CTRL2_10_BT: 322 ecmd->speed = SPEED_10; 323 ecmd->port = PORT_TP; 324 ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full; 325 ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full; 326 break; 327 /* All the other defined modes are flavours of 328 * 10G optical */ 329 default: 330 ecmd->speed = SPEED_10000; 331 ecmd->port = PORT_FIBRE; 332 ecmd->supported = SUPPORTED_FIBRE; 333 ecmd->advertising = ADVERTISED_FIBRE; 334 break; 335 } 336} 337 338/** 339 * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. 340 * @efx: Efx NIC 341 * @ecmd: New settings 342 * 343 * Currently this just enforces that we are _not_ changing the 344 * 'port', 'speed', 'supported' or 'advertising' settings as these 345 * cannot be changed on any currently supported PHY. 346 */ 347int mdio_clause45_set_settings(struct efx_nic *efx, 348 struct ethtool_cmd *ecmd) 349{ 350 struct ethtool_cmd tmpcmd; 351 mdio_clause45_get_settings(efx, &tmpcmd); 352 /* None of the current PHYs support more than one mode 353 * of operation (and only 10GBT ever will), so keep things 354 * simple for now */ 355 if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) && 356 (ecmd->supported == tmpcmd.supported) && 357 (ecmd->advertising == tmpcmd.advertising)) 358 return 0; 359 return -EOPNOTSUPP; 360}