The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cxgb/common/cxgb_aq100x.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /**************************************************************************
    2 
    3 Copyright (c) 2009 Chelsio Inc.
    4 All rights reserved.
    5 
    6 Redistribution and use in source and binary forms, with or without
    7 modification, are permitted provided that the following conditions are met:
    8 
    9  1. Redistributions of source code must retain the above copyright notice,
   10     this list of conditions and the following disclaimer.
   11 
   12  2. Neither the name of the Chelsio Corporation nor the names of its
   13     contributors may be used to endorse or promote products derived from
   14     this software without specific prior written permission.
   15 
   16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26 POSSIBILITY OF SUCH DAMAGE.
   27 
   28 ***************************************************************************/
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/11.1/sys/dev/cxgb/common/cxgb_aq100x.c 276959 2015-01-11 07:51:58Z np $");
   32 
   33 #include <cxgb_include.h>
   34 
   35 #undef msleep
   36 #define msleep t3_os_sleep
   37 
   38 enum {
   39         /* MDIO_DEV_PMA_PMD registers */
   40         AQ_LINK_STAT    = 0xe800,
   41 
   42         /* MDIO_DEV_XGXS registers */
   43         AQ_XAUI_RX_CFG  = 0xc400,
   44         AQ_XAUI_KX_CFG  = 0xc440,
   45         AQ_XAUI_TX_CFG  = 0xe400,
   46 
   47         /* MDIO_DEV_ANEG registers */
   48         AQ_100M_CTRL    = 0x0010,
   49         AQ_10G_CTRL     = 0x0020,
   50         AQ_1G_CTRL      = 0xc400,
   51         AQ_ANEG_STAT    = 0xc800,
   52 
   53         /* MDIO_DEV_VEND1 registers */
   54         AQ_FW_VERSION   = 0x0020,
   55         AQ_THERMAL_THR  = 0xc421,
   56         AQ_THERMAL1     = 0xc820,
   57         AQ_THERMAL2     = 0xc821,
   58         AQ_IFLAG_GLOBAL = 0xfc00,
   59         AQ_IMASK_GLOBAL = 0xff00,
   60 };
   61 
   62 #define AQBIT(x)        (1 << (0x##x))
   63 #define ADV_1G_FULL     AQBIT(f)
   64 #define ADV_1G_HALF     AQBIT(e)
   65 #define ADV_10G_FULL    AQBIT(c)
   66 
   67 #define AQ_WRITE_REGS(phy, regs) do { \
   68         int i; \
   69         for (i = 0; i < ARRAY_SIZE(regs); i++) { \
   70                 (void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \
   71         } \
   72 } while (0)
   73 #define AQ_READ_REGS(phy, regs) do { \
   74         unsigned i, v; \
   75         for (i = 0; i < ARRAY_SIZE(regs); i++) { \
   76                 (void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \
   77         } \
   78 } while (0)
   79 
   80 /*
   81  * Return value is temperature in celcius, 0xffff for error or don't know.
   82  */
   83 static int
   84 aq100x_temperature(struct cphy *phy)
   85 {
   86         unsigned int v;
   87 
   88         if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) ||
   89             v == 0xffff || (v & 1) != 1)
   90                 return (0xffff);
   91 
   92         if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v))
   93                 return (0xffff);
   94 
   95         return ((int)((signed char)(v >> 8)));
   96 }
   97 
   98 static int
   99 aq100x_set_defaults(struct cphy *phy)
  100 {
  101         return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00);
  102 }
  103 
  104 static int
  105 aq100x_reset(struct cphy *phy, int wait)
  106 {
  107         int err;
  108         err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
  109         if (!err)
  110                 err = aq100x_set_defaults(phy);
  111         return (err);
  112 }
  113 
  114 static int
  115 aq100x_intr_enable(struct cphy *phy)
  116 {
  117         struct {
  118                 int mmd;
  119                 int reg;
  120                 int val;
  121         } imasks[] = {
  122                 {MDIO_DEV_VEND1, 0xd400, AQBIT(e)},
  123                 {MDIO_DEV_VEND1, 0xff01, AQBIT(2)},
  124                 {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)}
  125         };
  126 
  127         AQ_WRITE_REGS(phy, imasks);
  128 
  129         return (0);
  130 }
  131 
  132 static int
  133 aq100x_intr_disable(struct cphy *phy)
  134 {
  135         struct {
  136                 int mmd;
  137                 int reg;
  138                 int val;
  139         } imasks[] = {
  140                 {MDIO_DEV_VEND1, 0xd400, 0},
  141                 {MDIO_DEV_VEND1, 0xff01, 0},
  142                 {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0}
  143         };
  144 
  145         AQ_WRITE_REGS(phy, imasks);
  146 
  147         return (0);
  148 }
  149 
  150 static int
  151 aq100x_intr_clear(struct cphy *phy)
  152 {
  153         struct {
  154                 int mmd;
  155                 int reg;
  156         } iclr[] = {
  157                 {MDIO_DEV_VEND1, 0xcc00},
  158                 {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */
  159         };
  160 
  161         AQ_READ_REGS(phy, iclr);
  162 
  163         return (0);
  164 }
  165 
  166 static int
  167 aq100x_vendor_intr(struct cphy *phy, int *rc)
  168 {
  169         int err;
  170         unsigned int cause, v;
  171 
  172         err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause);
  173         if (err)
  174                 return (err);
  175 
  176         if (cause & AQBIT(2)) {
  177                 err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v);
  178                 if (err)
  179                         return (err);
  180 
  181                 if (v & AQBIT(e)) {
  182                         CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n",
  183                             phy->addr, aq100x_temperature(phy));
  184 
  185                         t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN,
  186                             phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0);
  187 
  188                         *rc |= cphy_cause_alarm;
  189                 }
  190 
  191                 cause &= ~4;
  192         }
  193 
  194         if (cause)
  195                 CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt"
  196                     " (0x%x)\n", phy->addr, cause);
  197 
  198         return (0);
  199 
  200 }
  201 
  202 static int
  203 aq100x_intr_handler(struct cphy *phy)
  204 {
  205         int err, rc = 0;
  206         unsigned int cause;
  207 
  208         err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause);
  209         if (err)
  210                 return (err);
  211 
  212         if (cause & AQBIT(0)) {
  213                 err = aq100x_vendor_intr(phy, &rc);
  214                 if (err)
  215                         return (err);
  216                 cause &= ~AQBIT(0);
  217         }
  218 
  219         if (cause)
  220                 CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n",
  221                     phy->addr, cause);
  222 
  223         return (rc);
  224 }
  225 
  226 static int
  227 aq100x_power_down(struct cphy *phy, int off)
  228 {
  229         int err, wait = 500;
  230         unsigned int v;
  231 
  232         err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN,
  233             off ? BMCR_PDOWN : 0);
  234         if (err || off)
  235                 return (err);
  236 
  237         msleep(300);
  238         do {
  239                 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
  240                 if (err)
  241                         return (err);
  242                 v &= BMCR_RESET;
  243                 if (v)
  244                         msleep(10);
  245         } while (v && --wait);
  246         if (v) {
  247                 CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n",
  248                     phy->addr, v);
  249                 return (ETIMEDOUT);
  250         }
  251 
  252         return (0);
  253 }
  254 
  255 static int
  256 aq100x_autoneg_enable(struct cphy *phy)
  257 {
  258         int err;
  259 
  260         err = aq100x_power_down(phy, 0);
  261         if (!err)
  262                 err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
  263                     BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART);
  264 
  265         return (err);
  266 }
  267 
  268 static int
  269 aq100x_autoneg_restart(struct cphy *phy)
  270 {
  271         return aq100x_autoneg_enable(phy);
  272 }
  273 
  274 static int
  275 aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
  276 {
  277         unsigned int adv;
  278         int err;
  279 
  280         /* 10G advertisement */
  281         adv = 0;
  282         if (advertise_map & ADVERTISED_10000baseT_Full)
  283                 adv |= ADV_10G_FULL;
  284         err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL,
  285                                   ADV_10G_FULL, adv);
  286         if (err)
  287                 return (err);
  288 
  289         /* 1G advertisement */
  290         adv = 0;
  291         if (advertise_map & ADVERTISED_1000baseT_Full)
  292                 adv |= ADV_1G_FULL;
  293         if (advertise_map & ADVERTISED_1000baseT_Half)
  294                 adv |= ADV_1G_HALF;
  295         err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL,
  296                                   ADV_1G_FULL | ADV_1G_HALF, adv);
  297         if (err)
  298                 return (err);
  299 
  300         /* 100M, pause advertisement */
  301         adv = 0;
  302         if (advertise_map & ADVERTISED_100baseT_Half)
  303                 adv |= ADVERTISE_100HALF;
  304         if (advertise_map & ADVERTISED_100baseT_Full)
  305                 adv |= ADVERTISE_100FULL;
  306         if (advertise_map & ADVERTISED_Pause)
  307                 adv |= ADVERTISE_PAUSE_CAP;
  308         if (advertise_map & ADVERTISED_Asym_Pause)
  309                 adv |= ADVERTISE_PAUSE_ASYM;
  310         err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv);
  311 
  312         return (err);
  313 }
  314 
  315 static int
  316 aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
  317 {
  318         return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
  319                                    BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0);
  320 }
  321 
  322 static int
  323 aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
  324 {
  325         int err, set;
  326 
  327         if (speed == SPEED_100)
  328                 set = BMCR_SPEED100;
  329         else if (speed == SPEED_1000)
  330                 set = BMCR_SPEED1000;
  331         else if (speed == SPEED_10000)
  332                 set = BMCR_SPEED1000 | BMCR_SPEED100;
  333         else
  334                 return (EINVAL);
  335 
  336         if (duplex != DUPLEX_FULL)
  337                 return (EINVAL);
  338 
  339         err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
  340             BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0);
  341         if (err)
  342                 return (err);
  343 
  344         err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
  345             BMCR_SPEED1000 | BMCR_SPEED100, set);
  346         if (err)
  347                 return (err);
  348 
  349         return (0);
  350 }
  351 
  352 static int
  353 aq100x_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex,
  354                        int *fc)
  355 {
  356         int err;
  357         unsigned int v, link = 0;
  358 
  359         err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v);
  360         if (err)
  361                 return (err);
  362         if (v == 0xffff || !(v & 1))
  363                 goto done;
  364 
  365         err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v);
  366         if (err)
  367                 return (err);
  368         if (v & 0x8000)
  369                 goto done;
  370         if (v & BMCR_ANENABLE) {
  371 
  372                 err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v);
  373                 if (err)
  374                         return (err);
  375                 if ((v & 0x20) == 0)
  376                         goto done;
  377 
  378                 err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v);
  379                 if (err)
  380                         return (err);
  381 
  382                 if (speed) {
  383                         switch (v & 0x6) {
  384                         case 0x6: *speed = SPEED_10000;
  385                                 break;
  386                         case 0x4: *speed = SPEED_1000;
  387                                 break;
  388                         case 0x2: *speed = SPEED_100;
  389                                 break;
  390                         case 0x0: *speed = SPEED_10;
  391                                 break;
  392                         }
  393                 }
  394 
  395                 if (duplex)
  396                         *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
  397 
  398                 if (fc) {
  399                         unsigned int lpa, adv;
  400                         err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa);
  401                         if (!err)
  402                                 err = mdio_read(phy, MDIO_DEV_ANEG,
  403                                     AQ_100M_CTRL, &adv);
  404                         if (err)
  405                                 return err;
  406 
  407                         if (lpa & adv & ADVERTISE_PAUSE_CAP)
  408                                 *fc = PAUSE_RX | PAUSE_TX;
  409                         else if (lpa & ADVERTISE_PAUSE_CAP &&
  410                             lpa & ADVERTISE_PAUSE_ASYM &&
  411                             adv & ADVERTISE_PAUSE_ASYM)
  412                                 *fc = PAUSE_TX;
  413                         else if (lpa & ADVERTISE_PAUSE_ASYM &&
  414                             adv & ADVERTISE_PAUSE_CAP)
  415                                 *fc = PAUSE_RX;
  416                         else
  417                                 *fc = 0;
  418                 }
  419 
  420         } else {
  421                 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
  422                 if (err)
  423                         return (err);
  424 
  425                 v &= BMCR_SPEED1000 | BMCR_SPEED100;
  426                 if (speed) {
  427                         if (v == (BMCR_SPEED1000 | BMCR_SPEED100))
  428                                 *speed = SPEED_10000;
  429                         else if (v == BMCR_SPEED1000)
  430                                 *speed = SPEED_1000;
  431                         else if (v == BMCR_SPEED100)
  432                                 *speed = SPEED_100;
  433                         else
  434                                 *speed = SPEED_10;
  435                 }
  436 
  437                 if (duplex)
  438                         *duplex = DUPLEX_FULL;
  439         }
  440 
  441         link = 1;
  442 done:
  443         if (link_state)
  444                 *link_state = link ? PHY_LINK_UP : PHY_LINK_DOWN;
  445         return (0);
  446 }
  447 
  448 static struct cphy_ops aq100x_ops = {
  449         .reset             = aq100x_reset,
  450         .intr_enable       = aq100x_intr_enable,
  451         .intr_disable      = aq100x_intr_disable,
  452         .intr_clear        = aq100x_intr_clear,
  453         .intr_handler      = aq100x_intr_handler,
  454         .autoneg_enable    = aq100x_autoneg_enable,
  455         .autoneg_restart   = aq100x_autoneg_restart,
  456         .advertise         = aq100x_advertise,
  457         .set_loopback      = aq100x_set_loopback,
  458         .set_speed_duplex  = aq100x_set_speed_duplex,
  459         .get_link_status   = aq100x_get_link_status,
  460         .power_down        = aq100x_power_down,
  461 };
  462 
  463 int
  464 t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
  465                        const struct mdio_ops *mdio_ops)
  466 {
  467         struct cphy *phy = &pinfo->phy;
  468         unsigned int v, v2, gpio, wait;
  469         int err;
  470         adapter_t *adapter = pinfo->adapter;
  471 
  472         cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops,
  473                   SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
  474                   SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI |
  475                   SUPPORTED_MISC_IRQ, "1000/10GBASE-T");
  476 
  477         /*
  478          * Hard reset the PHY.
  479          */
  480         gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
  481         t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
  482         msleep(1);
  483         t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
  484 
  485         /*
  486          * Give it enough time to load the firmware and get ready for mdio.
  487          */
  488         msleep(1000);
  489         wait = 500; /* in 10ms increments */
  490         do {
  491                 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
  492                 if (err || v == 0xffff) {
  493 
  494                         /* Allow prep_adapter to succeed when ffff is read */
  495 
  496                         CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
  497                                 phy_addr, err, v);
  498                         goto done;
  499                 }
  500 
  501                 v &= BMCR_RESET;
  502                 if (v)
  503                         msleep(10);
  504         } while (v && --wait);
  505         if (v) {
  506                 CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
  507                         phy_addr, v);
  508 
  509                 goto done; /* let prep_adapter succeed */
  510         }
  511 
  512         /* Firmware version check. */
  513         (void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v);
  514         if (v < 0x115)
  515                 CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr,
  516                     v >> 8, v & 0xff);
  517 
  518         /* The PHY should start in really-low-power mode. */
  519         (void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
  520         if ((v & BMCR_PDOWN) == 0)
  521                 CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
  522                         phy_addr);
  523 
  524         /*
  525          * Verify XAUI and 1000-X settings, but let prep succeed no matter what.
  526          */
  527         v = v2 = 0;
  528         (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v);
  529         (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2);
  530         if (v != 0x1b || v2 != 0x1b)
  531                 CH_WARN(adapter, "PHY%d: incorrect XAUI settings "
  532                     "(0x%x, 0x%x).\n", phy_addr, v, v2);
  533         v = 0;
  534         (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v);
  535         if ((v & 0xf) != 0xf)
  536                 CH_WARN(adapter, "PHY%d: incorrect 1000-X settings "
  537                     "(0x%x).\n", phy_addr, v);
  538 
  539         (void) aq100x_set_defaults(phy);
  540 done:
  541         return (err);
  542 }

Cache object: 6509f483436410d11a3fd4752d225826


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.