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/mii/mii_fdt.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  * Copyright (c) 2017 Ian Lepore <ian@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Development sponsored by Microsemi, Inc.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * 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 AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * Utility functions for PHY drivers on systems configured using FDT data.
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/socket.h>
   39 #include <sys/bus.h>
   40 #include <sys/malloc.h>
   41 
   42 #include <net/if.h>
   43 #include <net/if_media.h>
   44 
   45 #include <dev/ofw/openfirm.h>
   46 #include <dev/ofw/ofw_bus.h>
   47 #include <dev/ofw/ofw_bus_subr.h>
   48 
   49 #include <dev/mii/mii.h>
   50 #include <dev/mii/miivar.h>
   51 #include <dev/mii/mii_fdt.h>
   52 
   53 /*
   54  * Table to translate MII_CONTYPE_xxxx constants to/from devicetree strings.
   55  * We explicitly associate the enum values with the strings in a table to avoid
   56  * relying on this list being sorted in the same order as the enum in miivar.h,
   57  * and to avoid problems if the enum gains new types that aren't in the FDT
   58  * data.  However, the "unknown" entry must be first because it is referenced
   59  * using subscript 0 in mii_fdt_contype_to_name().
   60  */
   61 static struct contype_names {
   62         mii_contype_t type;
   63         const char   *name;
   64 } fdt_contype_names[] = {
   65         {MII_CONTYPE_UNKNOWN,           "unknown"},
   66         {MII_CONTYPE_MII,               "mii"},
   67         {MII_CONTYPE_GMII,              "gmii"},
   68         {MII_CONTYPE_SGMII,             "sgmii"},
   69         {MII_CONTYPE_QSGMII,            "qsgmii"},
   70         {MII_CONTYPE_TBI,               "tbi"},
   71         {MII_CONTYPE_REVMII,            "rev-mii"},
   72         {MII_CONTYPE_RMII,              "rmii"},
   73         {MII_CONTYPE_RGMII,             "rgmii"},
   74         {MII_CONTYPE_RGMII_ID,          "rgmii-id"},
   75         {MII_CONTYPE_RGMII_RXID,        "rgmii-rxid"},
   76         {MII_CONTYPE_RGMII_TXID,        "rgmii-txid"},
   77         {MII_CONTYPE_RTBI,              "rtbi"},
   78         {MII_CONTYPE_SMII,              "smii"},
   79         {MII_CONTYPE_XGMII,             "xgmii"},
   80         {MII_CONTYPE_TRGMII,            "trgmii"},
   81         {MII_CONTYPE_2000BX,            "2000base-x"},
   82         {MII_CONTYPE_2500BX,            "2500base-x"},
   83         {MII_CONTYPE_RXAUI,             "rxaui"},
   84 };                                                           
   85 
   86 static phandle_t
   87 mii_fdt_get_phynode(phandle_t macnode)
   88 {
   89         static const char *props[] = {
   90             "phy-handle", "phy", "phy-device"
   91         };
   92         pcell_t xref;
   93         u_int i;
   94 
   95         for (i = 0; i < nitems(props); ++i) {
   96                 if (OF_getencprop(macnode, props[i], &xref, sizeof(xref)) > 0)
   97                         return (OF_node_from_xref(xref));
   98         }
   99         return (-1);
  100 }
  101 
  102 static phandle_t
  103 mii_fdt_lookup_phy(phandle_t node, int addr)
  104 {
  105         phandle_t ports, phynode, child;
  106         int reg;
  107 
  108         /* First try to see if we have a direct xref pointing to a PHY. */
  109         phynode = mii_fdt_get_phynode(node);
  110         if (phynode != -1)
  111                 return (phynode);
  112 
  113         /*
  114          * Now handle the "switch" case.
  115          * Search "ports" subnode for nodes that describe a switch port
  116          * including a PHY xref.
  117          * Since we have multiple candidates select one based on PHY address.
  118          */
  119         ports = ofw_bus_find_child(node, "ports");
  120         if (ports <= 0)
  121                 return (-1);
  122 
  123         for (child = OF_child(ports); child != 0; child = OF_peer(child)) {
  124                 if (ofw_bus_node_status_okay(child) == 0)
  125                         continue;
  126 
  127                 phynode = mii_fdt_get_phynode(child);
  128                 if (phynode <= 0)
  129                         continue;
  130 
  131                 if (OF_getencprop(phynode, "reg", &reg, sizeof(reg)) <= 0)
  132                         continue;
  133 
  134                 if (reg == addr)
  135                         return (phynode);
  136         }
  137         return (-1);
  138 }
  139 
  140 mii_contype_t
  141 mii_fdt_contype_from_name(const char *name)
  142 {
  143         u_int i;
  144 
  145         for (i = 0; i < nitems(fdt_contype_names); ++i) {
  146                 if (strcmp(name, fdt_contype_names[i].name) == 0)
  147                         return (fdt_contype_names[i].type);
  148         }
  149         return (MII_CONTYPE_UNKNOWN);
  150 }
  151 
  152 const char *
  153 mii_fdt_contype_to_name(mii_contype_t contype)
  154 {
  155         u_int i;
  156 
  157         for (i = 0; i < nitems(fdt_contype_names); ++i) {
  158                 if (contype == fdt_contype_names[i].type)
  159                         return (fdt_contype_names[i].name);
  160         }
  161         return (fdt_contype_names[0].name);
  162 }
  163 
  164 mii_contype_t
  165 mii_fdt_get_contype(phandle_t macnode)
  166 {
  167         char val[32];
  168 
  169         if (OF_getprop(macnode, "phy-mode", val, sizeof(val)) <= 0 &&
  170             OF_getprop(macnode, "phy-connection-type", val, sizeof(val)) <= 0) {
  171                 return (MII_CONTYPE_UNKNOWN);
  172         }
  173         return (mii_fdt_contype_from_name(val));
  174 }
  175 
  176 void
  177 mii_fdt_free_config(struct mii_fdt_phy_config *cfg)
  178 {
  179 
  180         free(cfg, M_OFWPROP);
  181 }
  182 
  183 mii_fdt_phy_config_t *
  184 mii_fdt_get_config(device_t phydev)
  185 {
  186         struct mii_attach_args *ma;
  187         mii_fdt_phy_config_t *cfg;
  188         device_t miibus, macdev;
  189         pcell_t val;
  190 
  191         ma = device_get_ivars(phydev);
  192         miibus = device_get_parent(phydev);
  193         macdev = device_get_parent(miibus);
  194 
  195         cfg = malloc(sizeof(*cfg), M_OFWPROP, M_ZERO | M_WAITOK);
  196 
  197         /*
  198          * If we can't find our parent MAC's node, there's nothing more we can
  199          * fill in; cfg is already full of zero/default values, return it.
  200          */
  201         if ((cfg->macnode = ofw_bus_get_node(macdev)) == -1)
  202                 return (cfg);
  203 
  204         cfg->con_type = mii_fdt_get_contype(cfg->macnode);
  205 
  206         /*
  207          * If we can't find our own PHY node, there's nothing more we can fill
  208          * in, just return what we've got.
  209          */
  210         cfg->phynode = mii_fdt_lookup_phy(cfg->macnode, ma->mii_phyno);
  211         if (cfg->phynode == -1)
  212                 return (cfg);
  213 
  214         if (OF_getencprop(cfg->phynode, "max-speed", &val, sizeof(val)) > 0)
  215                 cfg->max_speed = val;
  216 
  217         if (ofw_bus_node_is_compatible(cfg->phynode,
  218             "ethernet-phy-ieee802.3-c45"))
  219                 cfg->flags |= MIIF_FDT_COMPAT_CLAUSE45;
  220 
  221         if (OF_hasprop(cfg->phynode, "broken-turn-around"))
  222                 cfg->flags |= MIIF_FDT_BROKEN_TURNAROUND;
  223         if (OF_hasprop(cfg->phynode, "enet-phy-lane-swap"))
  224                 cfg->flags |= MIIF_FDT_LANE_SWAP;
  225         if (OF_hasprop(cfg->phynode, "enet-phy-lane-no-swap"))
  226                 cfg->flags |= MIIF_FDT_NO_LANE_SWAP;
  227         if (OF_hasprop(cfg->phynode, "eee-broken-100tx"))
  228                 cfg->flags |= MIIF_FDT_EEE_BROKEN_100TX;
  229         if (OF_hasprop(cfg->phynode, "eee-broken-1000t"))
  230                 cfg->flags |= MIIF_FDT_EEE_BROKEN_1000T;
  231         if (OF_hasprop(cfg->phynode, "eee-broken-10gt"))
  232                 cfg->flags |= MIIF_FDT_EEE_BROKEN_10GT;
  233         if (OF_hasprop(cfg->phynode, "eee-broken-1000kx"))
  234                 cfg->flags |= MIIF_FDT_EEE_BROKEN_1000KX;
  235         if (OF_hasprop(cfg->phynode, "eee-broken-10gkx4"))
  236                 cfg->flags |= MIIF_FDT_EEE_BROKEN_10GKX4;
  237         if (OF_hasprop(cfg->phynode, "eee-broken-10gkr"))
  238                 cfg->flags |= MIIF_FDT_EEE_BROKEN_10GKR;
  239 
  240         return (cfg);
  241 }
  242 
  243 static int
  244 miibus_fdt_probe(device_t dev)
  245 {
  246         device_t parent;
  247 
  248         parent = device_get_parent(dev);
  249         if (ofw_bus_get_node(parent) == -1)
  250                 return (ENXIO);
  251 
  252         device_set_desc(dev, "OFW MII bus");
  253         return (BUS_PROBE_DEFAULT);
  254 }
  255 
  256 static int
  257 miibus_fdt_attach(device_t dev)
  258 {
  259         struct mii_attach_args *ma;
  260         int i, error, nchildren;
  261         device_t parent, *children;
  262         phandle_t phy_node;
  263 
  264         parent = device_get_parent(dev);
  265 
  266         error = device_get_children(dev, &children, &nchildren);
  267         if (error != 0 || nchildren == 0)
  268                 return (ENXIO);
  269 
  270         for (i = 0; i < nchildren; i++) {
  271                 ma = device_get_ivars(children[i]);
  272                 bzero(&ma->obd, sizeof(ma->obd));
  273                 phy_node = mii_fdt_lookup_phy(ofw_bus_get_node(parent),
  274                     ma->mii_phyno);
  275                 if (phy_node == -1) {
  276                         device_printf(dev,
  277                             "Warning: failed to find OFW node for PHY%d\n",
  278                             ma->mii_phyno);
  279                         continue;
  280                 }
  281                 error = ofw_bus_gen_setup_devinfo(&ma->obd, phy_node);
  282                 if (error != 0) {
  283                         device_printf(dev,
  284                             "Warning: failed to setup OFW devinfo for PHY%d\n",
  285                             ma->mii_phyno);
  286                         continue;
  287                 }
  288                 /*
  289                  * Setup interrupt resources.
  290                  * Only a handful of PHYs support those,
  291                  * so it's fine if we fail here.
  292                  */
  293                 resource_list_init(&ma->rl);
  294                 (void)ofw_bus_intr_to_rl(children[i], phy_node, &ma->rl, NULL);
  295         }
  296 
  297         free(children, M_TEMP);
  298         return (miibus_attach(dev));
  299 }
  300 
  301 static struct resource_list *
  302 miibus_fdt_get_resource_list(device_t bus, device_t child)
  303 {
  304         struct mii_attach_args *ma;
  305 
  306         ma = device_get_ivars(child);
  307 
  308         if (ma->obd.obd_node == 0)
  309                 return (NULL);
  310 
  311         return (&ma->rl);
  312 }
  313 
  314 static const struct ofw_bus_devinfo*
  315 miibus_fdt_get_devinfo(device_t bus, device_t child)
  316 {
  317         struct mii_attach_args *ma;
  318 
  319         ma = device_get_ivars(child);
  320 
  321         if (ma->obd.obd_node == 0)
  322                 return (NULL);
  323 
  324         return (&ma->obd);
  325 }
  326 
  327 static device_method_t miibus_fdt_methods[] = {
  328         DEVMETHOD(device_probe,         miibus_fdt_probe),
  329         DEVMETHOD(device_attach,        miibus_fdt_attach),
  330 
  331         /* ofw_bus interface */
  332         DEVMETHOD(ofw_bus_get_devinfo,  miibus_fdt_get_devinfo),
  333         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
  334         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
  335         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
  336         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
  337         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
  338 
  339         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
  340         DEVMETHOD(bus_teardown_intr,            bus_generic_teardown_intr),
  341         DEVMETHOD(bus_release_resource,         bus_generic_release_resource),
  342         DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
  343         DEVMETHOD(bus_deactivate_resource,      bus_generic_deactivate_resource),
  344         DEVMETHOD(bus_adjust_resource,          bus_generic_adjust_resource),
  345         DEVMETHOD(bus_alloc_resource,           bus_generic_rl_alloc_resource),
  346         DEVMETHOD(bus_get_resource,             bus_generic_rl_get_resource),
  347         DEVMETHOD(bus_set_resource,             bus_generic_rl_set_resource),
  348         DEVMETHOD(bus_get_resource_list,        miibus_fdt_get_resource_list),
  349 
  350         DEVMETHOD_END
  351 };
  352 
  353 DEFINE_CLASS_1(miibus, miibus_fdt_driver, miibus_fdt_methods,
  354     sizeof(struct mii_data), miibus_driver);

Cache object: b387e081c1233d17251fe3b0fa03784f


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