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

Cache object: 50475f128c2fa30686f48f3ccbdc0f01


[ 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.