Author: jmallett
Date: Wed Oct 13 09:17:44 2010
New Revision: 213762
URL: http://svn.freebsd.org/changeset/base/213762

Log:
  o) Make it possible to attach a PHY directly to an octe device rather than
     using miibus, since for some devices that use multiple addresses on the 
bus,
     going through miibus may be unclear, and for devices that are not standard
     MII PHYs, miibus may throw a fit, necessitating complicated interfaces to
     fake the interface that it expects during probe/attach.
  o) Make the mv88e61xx SMI interface in octe attach a PHY directly and fix some
     mistakes in the code that resulted from trying too hard to present a nice
     interface to miibus.
  o) Add a PHY driver for the mv88e61xx.  If attached (it is optional in kernel
     compiles so the default behavior of having a dumb switch is preserved) it
     will place the switch in a VLAN-tagging mode such that each physical port
     has a VLAN associated with it and interfaces for the VLANs can be created 
to
     address or bridge between them.
     XXX It would be nice for this to be part of a single module including the
         SMI interface, and for it to fit into a generic switch configuration
         framework and for it to use DSA rather than VLANs, but this is a start
         and gives some sense of the parameters of such frameworks that are not
         currently present in FreeBSD.  In lieu of a switch configuration
         interface, per-port media status and VLAN settings are in a sysctl 
tree.
     XXX There may be some minor nits remaining in the handling of broadcast,
         multicast and unknown destination traffic.  It would also be nice to go
         through and replace the few remaining magic numbers with macros at some
         point in the future.
     XXX This has only been tested with the MV88E6161, but it should work with
         minimal or no modification on related switches, so support for probing
         them was included.
  
  Thanks to Pat Saavedra of TELoIP and Rafal Jaworowski of Semihalf for their
  assistance in understanding the switch chipset.

Added:
  head/sys/mips/cavium/octe/mv88e61xxphy.c   (contents, props changed)
  head/sys/mips/cavium/octe/mv88e61xxphyreg.h   (contents, props changed)
Modified:
  head/sys/mips/cavium/files.octeon1
  head/sys/mips/cavium/octe/cavium-ethernet.h
  head/sys/mips/cavium/octe/ethernet-mdio.c
  head/sys/mips/cavium/octe/ethernet-mv88e61xx.c
  head/sys/mips/cavium/octe/octe.c
  head/sys/mips/conf/OCTEON1

Modified: head/sys/mips/cavium/files.octeon1
==============================================================================
--- head/sys/mips/cavium/files.octeon1  Wed Oct 13 06:28:40 2010        
(r213761)
+++ head/sys/mips/cavium/files.octeon1  Wed Oct 13 09:17:44 2010        
(r213762)
@@ -31,6 +31,7 @@ mips/cavium/octe/ethernet-sgmii.c             optio
 mips/cavium/octe/ethernet-spi.c                        optional octe
 mips/cavium/octe/ethernet-tx.c                 optional octe
 mips/cavium/octe/ethernet-xaui.c               optional octe
+mips/cavium/octe/mv88e61xxphy.c                        optional octe 
mv88e61xxphy
 mips/cavium/octe/octe.c                                optional octe
 mips/cavium/octe/octebus.c                     optional octe
 

Modified: head/sys/mips/cavium/octe/cavium-ethernet.h
==============================================================================
--- head/sys/mips/cavium/octe/cavium-ethernet.h Wed Oct 13 06:28:40 2010        
(r213761)
+++ head/sys/mips/cavium/octe/cavium-ethernet.h Wed Oct 13 09:17:44 2010        
(r213762)
@@ -72,6 +72,7 @@ typedef struct {
 
        uint8_t mac[6];
        int phy_id;
+       const char *phy_device;
        int (*mdio_read)(struct ifnet *, int, int);
        void (*mdio_write)(struct ifnet *, int, int, int);
 

Modified: head/sys/mips/cavium/octe/ethernet-mdio.c
==============================================================================
--- head/sys/mips/cavium/octe/ethernet-mdio.c   Wed Oct 13 06:28:40 2010        
(r213761)
+++ head/sys/mips/cavium/octe/ethernet-mdio.c   Wed Oct 13 09:17:44 2010        
(r213762)
@@ -132,6 +132,7 @@ int cvm_oct_mdio_setup_device(struct ifn
        cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
 
        priv->phy_id = cvmx_helper_board_get_mii_address(priv->port);
+       priv->phy_device = NULL;
        priv->mdio_read = NULL;
        priv->mdio_write = NULL;
 

Modified: head/sys/mips/cavium/octe/ethernet-mv88e61xx.c
==============================================================================
--- head/sys/mips/cavium/octe/ethernet-mv88e61xx.c      Wed Oct 13 06:28:40 
2010        (r213761)
+++ head/sys/mips/cavium/octe/ethernet-mv88e61xx.c      Wed Oct 13 09:17:44 
2010        (r213762)
@@ -49,8 +49,6 @@ __FBSDID("$FreeBSD$");
 #include "wrapper-cvmx-includes.h"
 #include "ethernet-headers.h"
 
-#define        MV88E61XX_SMI_PHY_SW    0x10    /* Switch PHY.  */
-
 #define        MV88E61XX_SMI_REG_CMD   0x00    /* Indirect command register.  
*/
 #define         MV88E61XX_SMI_CMD_BUSY         0x8000  /* Busy bit.  */
 #define         MV88E61XX_SMI_CMD_22           0x1000  /* Clause 22 (default 
45.)  */
@@ -61,89 +59,67 @@ __FBSDID("$FreeBSD$");
 
 #define        MV88E61XX_SMI_REG_DAT   0x01    /* Indirect data register.  */
 
-static int cvm_oct_mv88e61xx_mdio_read(struct ifnet *, int, int);
-static void cvm_oct_mv88e61xx_mdio_write(struct ifnet *, int, int, int);
 static int cvm_oct_mv88e61xx_smi_read(struct ifnet *, int, int);
 static void cvm_oct_mv88e61xx_smi_write(struct ifnet *, int, int, int);
-static int cvm_oct_mv88e61xx_smi_wait(struct ifnet *, int);
+static int cvm_oct_mv88e61xx_smi_wait(struct ifnet *);
 
 int
 cvm_oct_mv88e61xx_setup_device(struct ifnet *ifp)
 {
        cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
 
-       priv->mdio_read = cvm_oct_mv88e61xx_mdio_read;
-       priv->mdio_write = cvm_oct_mv88e61xx_mdio_write;
+       priv->mdio_read = cvm_oct_mv88e61xx_smi_read;
+       priv->mdio_write = cvm_oct_mv88e61xx_smi_write;
+       priv->phy_device = "mv88e61xxphy";
 
        return (0);
 }
 
 static int
-cvm_oct_mv88e61xx_mdio_read(struct ifnet *ifp, int phy_id, int location)
-{
-       /*
-        * Intercept reads of MII_BMSR.  The miibus uses this to determine
-        * PHY presence and we only want it to look for a PHY attachment
-        * for the switch PHY itself.  The PHY driver will talk to all of
-        * the other ports as need be.
-        */
-       switch (location) {
-       case MII_BMSR:
-               if (phy_id != MV88E61XX_SMI_PHY_SW)
-                       return (0);
-               return (BMSR_EXTSTAT | BMSR_ACOMP | BMSR_LINK);
-       default:
-               return (cvm_oct_mv88e61xx_smi_read(ifp, phy_id, location));
-       }
-}
-
-static void
-cvm_oct_mv88e61xx_mdio_write(struct ifnet *ifp, int phy_id, int location, int 
val)
-{
-       return (cvm_oct_mv88e61xx_smi_write(ifp, phy_id, location, val));
-}
-
-static int
 cvm_oct_mv88e61xx_smi_read(struct ifnet *ifp, int phy_id, int location)
 {
+       cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
        int error;
 
-       error = cvm_oct_mv88e61xx_smi_wait(ifp, phy_id);
+       error = cvm_oct_mv88e61xx_smi_wait(ifp);
        if (error != 0)
                return (0);
 
-       cvm_oct_mdio_write(ifp, phy_id, MV88E61XX_SMI_REG_CMD,
+       cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD,
            MV88E61XX_SMI_CMD_BUSY | MV88E61XX_SMI_CMD_22 |
            MV88E61XX_SMI_CMD_READ | MV88E61XX_SMI_CMD_PHY(phy_id) |
            MV88E61XX_SMI_CMD_REG(location));
 
-       error = cvm_oct_mv88e61xx_smi_wait(ifp, phy_id);
+       error = cvm_oct_mv88e61xx_smi_wait(ifp);
        if (error != 0)
                return (0);
 
-       return (cvm_oct_mdio_read(ifp, phy_id, MV88E61XX_SMI_REG_DAT));
+       return (cvm_oct_mdio_read(ifp, priv->phy_id, MV88E61XX_SMI_REG_DAT));
 }
 
 static void
 cvm_oct_mv88e61xx_smi_write(struct ifnet *ifp, int phy_id, int location, int 
val)
 {
-       cvm_oct_mv88e61xx_smi_wait(ifp, phy_id);
-       cvm_oct_mdio_write(ifp, phy_id, MV88E61XX_SMI_REG_DAT, val);
-       cvm_oct_mdio_write(ifp, phy_id, MV88E61XX_SMI_REG_CMD,
+       cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
+
+       cvm_oct_mv88e61xx_smi_wait(ifp);
+       cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_DAT, val);
+       cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD,
            MV88E61XX_SMI_CMD_BUSY | MV88E61XX_SMI_CMD_22 |
            MV88E61XX_SMI_CMD_WRITE | MV88E61XX_SMI_CMD_PHY(phy_id) |
            MV88E61XX_SMI_CMD_REG(location));
-       cvm_oct_mv88e61xx_smi_wait(ifp, phy_id);
+       cvm_oct_mv88e61xx_smi_wait(ifp);
 }
 
 static int
-cvm_oct_mv88e61xx_smi_wait(struct ifnet *ifp, int phy_id)
+cvm_oct_mv88e61xx_smi_wait(struct ifnet *ifp)
 {
+       cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
        uint16_t cmd;
        unsigned i;
 
        for (i = 0; i < 10000; i++) {
-               cmd = cvm_oct_mdio_read(ifp, phy_id, MV88E61XX_SMI_REG_CMD);
+               cmd = cvm_oct_mdio_read(ifp, priv->phy_id, 
MV88E61XX_SMI_REG_CMD);
                if ((cmd & MV88E61XX_SMI_CMD_BUSY) == 0)
                        return (0);
        }

Added: head/sys/mips/cavium/octe/mv88e61xxphy.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/mips/cavium/octe/mv88e61xxphy.c    Wed Oct 13 09:17:44 2010        
(r213762)
@@ -0,0 +1,630 @@
+/*-
+ * Copyright (c) 2010 Juli Mallett <jmall...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for the Marvell 88E61xx family of switch PHYs
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/sysctl.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include "miibus_if.h"
+
+#include "mv88e61xxphyreg.h"
+
+struct mv88e61xxphy_softc;
+
+struct mv88e61xxphy_port_softc {
+       struct mv88e61xxphy_softc *sc_switch;
+       unsigned sc_port;
+       unsigned sc_domain;
+       unsigned sc_vlan;
+       unsigned sc_priority;
+       unsigned sc_flags;
+};
+
+#define        MV88E61XXPHY_PORT_FLAG_VTU_UPDATE       (0x0001)
+
+struct mv88e61xxphy_softc {
+       device_t sc_dev;
+       struct mv88e61xxphy_port_softc sc_ports[MV88E61XX_PORTS];
+};
+
+enum mv88e61xxphy_vtu_membership_type {
+       MV88E61XXPHY_VTU_UNMODIFIED,
+       MV88E61XXPHY_VTU_UNTAGGED,
+       MV88E61XXPHY_VTU_TAGGED,
+       MV88E61XXPHY_VTU_DISCARDED,
+};
+
+enum mv88e61xxphy_sysctl_link_type {
+       MV88E61XXPHY_LINK_SYSCTL_DUPLEX,
+       MV88E61XXPHY_LINK_SYSCTL_LINK,
+       MV88E61XXPHY_LINK_SYSCTL_MEDIA,
+};
+
+enum mv88e61xxphy_sysctl_port_type {
+       MV88E61XXPHY_PORT_SYSCTL_DOMAIN,
+       MV88E61XXPHY_PORT_SYSCTL_VLAN,
+       MV88E61XXPHY_PORT_SYSCTL_PRIORITY,
+};
+
+/*
+ * Register access macros.
+ */
+#define        MV88E61XX_READ(sc, phy, reg)                                    
\
+       MIIBUS_READREG(device_get_parent((sc)->sc_dev), (phy), (reg))
+
+#define        MV88E61XX_WRITE(sc, phy, reg, val)                              
\
+       MIIBUS_WRITEREG(device_get_parent((sc)->sc_dev), (phy), (reg), (val))
+
+#define        MV88E61XX_READ_PORT(psc, reg)                                   
\
+       MV88E61XX_READ((psc)->sc_switch, MV88E61XX_PORT((psc)->sc_port), (reg))
+
+#define        MV88E61XX_WRITE_PORT(psc, reg, val)                             
\
+       MV88E61XX_WRITE((psc)->sc_switch, MV88E61XX_PORT((psc)->sc_port), 
(reg), (val))
+
+static int mv88e61xxphy_probe(device_t);
+static int mv88e61xxphy_attach(device_t);
+
+static void mv88e61xxphy_init(struct mv88e61xxphy_softc *);
+static void mv88e61xxphy_init_port(struct mv88e61xxphy_port_softc *);
+static void mv88e61xxphy_init_vtu(struct mv88e61xxphy_softc *);
+static int mv88e61xxphy_sysctl_link_proc(SYSCTL_HANDLER_ARGS);
+static int mv88e61xxphy_sysctl_port_proc(SYSCTL_HANDLER_ARGS);
+static void mv88e61xxphy_vtu_load(struct mv88e61xxphy_softc *, uint16_t);
+static void mv88e61xxphy_vtu_set_membership(struct mv88e61xxphy_softc *, 
unsigned, enum mv88e61xxphy_vtu_membership_type);
+static void mv88e61xxphy_vtu_wait(struct mv88e61xxphy_softc *);
+
+static int
+mv88e61xxphy_probe(device_t dev)
+{
+       uint16_t val;
+
+       val = MIIBUS_READREG(device_get_parent(dev), MV88E61XX_PORT(0),
+           MV88E61XX_PORT_REVISION);
+       switch (val >> 4) {
+       case 0x121:
+               device_set_desc(dev, "Marvell Link Street 88E6123 3-Port 
Gigabit Switch");
+               return (0);
+       case 0x161:
+               device_set_desc(dev, "Marvell Link Street 88E6161 6-Port 
Gigabit Switch");
+               return (0);
+       case 0x165:
+               device_set_desc(dev, "Marvell Link Street 88E6161 6-Port 
Advanced Gigabit Switch");
+               return (0);
+       default:
+               return (ENXIO);
+       }
+}
+
+static int
+mv88e61xxphy_attach(device_t dev)
+{
+       char portbuf[] = "N";
+       struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
+       struct sysctl_oid *tree = device_get_sysctl_tree(dev);
+       struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
+       struct sysctl_oid *port_node, *portN_node;
+       struct sysctl_oid_list *port_tree, *portN_tree;
+       struct mv88e61xxphy_softc *sc;
+       unsigned port;
+
+       sc = device_get_softc(dev);
+       sc->sc_dev = dev;
+
+       /*
+        * Initialize port softcs.
+        */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+               psc->sc_switch = sc;
+               psc->sc_port = port;
+               psc->sc_domain = 0; /* One broadcast domain by default.  */
+               psc->sc_vlan = port + 1; /* Tag VLANs by default.  */
+               psc->sc_priority = 0; /* No default special priority.  */
+               psc->sc_flags = 0;
+       }
+
+       /*
+        * Add per-port sysctl tree/handlers.
+        */
+       port_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "port",
+           CTLFLAG_RD, NULL, "Switch Ports");
+       port_tree = SYSCTL_CHILDREN(port_node);
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+
+               portbuf[0] = '0' + port;
+               portN_node = SYSCTL_ADD_NODE(ctx, port_tree, OID_AUTO, portbuf,
+                   CTLFLAG_RD, NULL, "Switch Port");
+               portN_tree = SYSCTL_CHILDREN(portN_node);
+
+               SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "duplex",
+                   CTLFLAG_RD | CTLTYPE_INT, psc,
+                   MV88E61XXPHY_LINK_SYSCTL_DUPLEX,
+                   mv88e61xxphy_sysctl_link_proc, "IU",
+                   "Media duplex status (0 = half duplex; 1 = full duplex)");
+
+               SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "link",
+                   CTLFLAG_RD | CTLTYPE_INT, psc,
+                   MV88E61XXPHY_LINK_SYSCTL_LINK,
+                   mv88e61xxphy_sysctl_link_proc, "IU",
+                   "Link status (0 = down; 1 = up)");
+
+               SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "media",
+                   CTLFLAG_RD | CTLTYPE_INT, psc,
+                   MV88E61XXPHY_LINK_SYSCTL_MEDIA,
+                   mv88e61xxphy_sysctl_link_proc, "IU",
+                   "Media speed (0 = unknown; 10 = 10Mbps; 100 = 100Mbps; 1000 
= 1Gbps)");
+
+               SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "domain",
+                   CTLFLAG_RW | CTLTYPE_INT, psc,
+                   MV88E61XXPHY_PORT_SYSCTL_DOMAIN,
+                   mv88e61xxphy_sysctl_port_proc, "IU",
+                   "Broadcast domain (ports can only talk to other ports in 
the same domain)");
+
+               SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "vlan",
+                   CTLFLAG_RW | CTLTYPE_INT, psc,
+                   MV88E61XXPHY_PORT_SYSCTL_VLAN,
+                   mv88e61xxphy_sysctl_port_proc, "IU",
+                   "Tag packets from/for this port with a given VLAN.");
+
+               SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "priority",
+                   CTLFLAG_RW | CTLTYPE_INT, psc,
+                   MV88E61XXPHY_PORT_SYSCTL_PRIORITY,
+                   mv88e61xxphy_sysctl_port_proc, "IU",
+                   "Default packet priority for this port.");
+       }
+
+       mv88e61xxphy_init(sc);
+
+       return (0);
+}
+
+static void
+mv88e61xxphy_init(struct mv88e61xxphy_softc *sc)
+{
+       unsigned port;
+       uint16_t val;
+       unsigned i;
+
+       /* Disable all ports.  */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+
+               val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_CONTROL);
+               val &= ~0x3;
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, val);
+       }
+
+       DELAY(2000);
+
+       /* Reset the switch.  */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_CONTROL, 0xc400);
+       for (i = 0; i < 100; i++) {
+               val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, 
MV88E61XX_GLOBAL_STATUS);
+               if ((val & 0xc800) == 0xc800)
+                       break;
+               DELAY(10);
+       }
+       if (i == 100) {
+               device_printf(sc->sc_dev, "%s: switch reset timed out.\n", 
__func__);
+               return;
+       }
+
+       /* Disable PPU.  */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_CONTROL, 0x0000);
+
+       /* Configure host port and send monitor frames to it.  */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_MONITOR,
+           (MV88E61XX_HOST_PORT << 12) | (MV88E61XX_HOST_PORT << 8) |
+           (MV88E61XX_HOST_PORT << 4));
+
+       /* Disable remote management.  */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_REMOTE_MGMT, 
0x0000);
+
+       /* Send all specifically-addressed frames to the host port.  */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_MANAGE_2X, 
0xffff);
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_MANAGE_0X, 
0xffff);
+
+       /* Remove provider-supplied tag and use it for switching.  */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_CONTROL2,
+           MV88E61XX_GLOBAL2_CONTROL2_REMOVE_PTAG);
+
+       /* Configure all ports.  */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+               mv88e61xxphy_init_port(psc);
+       }
+
+       /* Reprogram VLAN table (VTU.)  */
+       mv88e61xxphy_init_vtu(sc);
+
+       /* Enable all ports.  */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+
+               val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_CONTROL);
+               val |= 0x3;
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, val);
+       }
+}
+
+static void
+mv88e61xxphy_init_port(struct mv88e61xxphy_port_softc *psc)
+{
+       struct mv88e61xxphy_softc *sc;
+       unsigned allow_mask;
+
+       sc = psc->sc_switch;
+
+       /* Set media type and flow control.  */
+       if (psc->sc_port != MV88E61XX_HOST_PORT) {
+               /* Don't force any media type or flow control.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FORCE_MAC, 0x0003);
+       } else {
+               /* Make CPU port 1G FDX.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FORCE_MAC, 0x003e);
+       }
+
+       /* Don't limit flow control pauses.  */
+       MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_PAUSE_CONTROL, 0x0000);
+
+       /* Set various port functions per Linux.  */
+       if (psc->sc_port != MV88E61XX_HOST_PORT) {
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, 0x04bc);
+       } else {
+               /*
+                * Send frames for unknown unicast and multicast groups to
+                * host, too.
+                */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, 0x063f);
+       }
+
+       if (psc->sc_port != MV88E61XX_HOST_PORT) {
+               /* Disable trunking.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL2, 0x0000);
+       } else {
+               /* Disable trunking and send learn messages to host.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL2, 0x8000);
+       }
+
+       /*
+        * Port-based VLAN map; isolates MAC tables and forces ports to talk
+        * only to the host.
+        *
+        * Always allow the host to send to all ports and allow all ports to
+        * send to the host.
+        */
+       if (psc->sc_port != MV88E61XX_HOST_PORT) {
+               allow_mask = 1 << MV88E61XX_HOST_PORT;
+       } else {
+               allow_mask = (1 << MV88E61XX_PORTS) - 1;
+               allow_mask &= ~(1 << MV88E61XX_HOST_PORT);
+       }
+       MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_VLAN_MAP,
+           (psc->sc_domain << 12) | allow_mask);
+
+       /* VLAN tagging.  Set default priority and VLAN tag (or none.)  */
+       MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_VLAN,
+           (psc->sc_priority << 14) | psc->sc_vlan);
+
+       if (psc->sc_port == MV88E61XX_HOST_PORT) {
+               /* Set provider ingress tag.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_PROVIDER_PROTO,
+                   ETHERTYPE_VLAN);
+
+               /* Set provider egress tag.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_ETHER_PROTO,
+                   ETHERTYPE_VLAN);
+
+               /* Use secure 802.1q mode and accept only tagged frames.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FILTER,
+                   MV88E61XX_PORT_FILTER_MAP_DEST |
+                   MV88E61XX_PORT_FILTER_8021Q_SECURE |
+                   MV88E61XX_PORT_FILTER_DISCARD_UNTAGGED);
+       } else {
+               /* Don't allow tagged frames.  */
+               MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FILTER,
+                   MV88E61XX_PORT_FILTER_MAP_DEST |
+                   MV88E61XX_PORT_FILTER_DISCARD_TAGGED);
+       }
+}
+
+static void
+mv88e61xxphy_init_vtu(struct mv88e61xxphy_softc *sc)
+{
+       unsigned port;
+
+       /*
+        * Start flush of the VTU.
+        */
+       mv88e61xxphy_vtu_wait(sc);
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP,
+           MV88E61XX_GLOBAL_VTU_OP_BUSY | MV88E61XX_GLOBAL_VTU_OP_OP_FLUSH);
+
+       /*
+        * Queue each port's VLAN to be programmed.
+        */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+               psc->sc_flags &= ~MV88E61XXPHY_PORT_FLAG_VTU_UPDATE;
+               if (psc->sc_vlan == 0)
+                       continue;
+               psc->sc_flags |= MV88E61XXPHY_PORT_FLAG_VTU_UPDATE;
+       }
+
+       /*
+        * Program each VLAN that is in use.
+        */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+               if ((psc->sc_flags & MV88E61XXPHY_PORT_FLAG_VTU_UPDATE) == 0)
+                       continue;
+               mv88e61xxphy_vtu_load(sc, psc->sc_vlan);
+       }
+
+       /*
+        * Wait for last pending VTU operation to complete.
+        */
+       mv88e61xxphy_vtu_wait(sc);
+}
+
+static int
+mv88e61xxphy_sysctl_link_proc(SYSCTL_HANDLER_ARGS)
+{
+       struct mv88e61xxphy_port_softc *psc = arg1;
+       enum mv88e61xxphy_sysctl_link_type type = arg2;
+       uint16_t val;
+       unsigned out;
+
+       val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_STATUS);
+       switch (type) {
+       case MV88E61XXPHY_LINK_SYSCTL_DUPLEX:
+               if ((val & MV88E61XX_PORT_STATUS_DUPLEX) != 0)
+                       out = 1;
+               else
+                       out = 0;
+               break;
+       case MV88E61XXPHY_LINK_SYSCTL_LINK:
+               if ((val & MV88E61XX_PORT_STATUS_LINK) != 0)
+                       out = 1;
+               else
+                       out = 0;
+               break;
+       case MV88E61XXPHY_LINK_SYSCTL_MEDIA:
+               switch (val & MV88E61XX_PORT_STATUS_MEDIA) {
+               case MV88E61XX_PORT_STATUS_MEDIA_10M:
+                       out = 10;
+                       break;
+               case MV88E61XX_PORT_STATUS_MEDIA_100M:
+                       out = 100;
+                       break;
+               case MV88E61XX_PORT_STATUS_MEDIA_1G:
+                       out = 1000;
+                       break;
+               default:
+                       out = 0;
+                       break;
+               }
+               break;
+       default:
+               return (EINVAL);
+       }
+       return (sysctl_handle_int(oidp, NULL, out, req));
+}
+
+static int
+mv88e61xxphy_sysctl_port_proc(SYSCTL_HANDLER_ARGS)
+{
+       struct mv88e61xxphy_port_softc *psc = arg1;
+       enum mv88e61xxphy_sysctl_port_type type = arg2;
+       struct mv88e61xxphy_softc *sc = psc->sc_switch;
+       unsigned max, val, *valp;
+       int error;
+
+       switch (type) {
+       case MV88E61XXPHY_PORT_SYSCTL_DOMAIN:
+               valp = &psc->sc_domain;
+               max = 0xf;
+               break;
+       case MV88E61XXPHY_PORT_SYSCTL_VLAN:
+               valp = &psc->sc_vlan;
+               max = 0x1000;
+               break;
+       case MV88E61XXPHY_PORT_SYSCTL_PRIORITY:
+               valp = &psc->sc_priority;
+               max = 3;
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       val = *valp;
+       error = sysctl_handle_int(oidp, &val, 0, req);
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+
+       /* Bounds check value.  */
+       if (val >= max)
+               return (EINVAL);
+
+       /* Reinitialize switch with new value.  */
+       *valp = val;
+       mv88e61xxphy_init(sc);
+
+       return (0);
+}
+
+static void
+mv88e61xxphy_vtu_load(struct mv88e61xxphy_softc *sc, uint16_t vid)
+{
+       unsigned port;
+
+       /*
+        * Wait for previous operation to complete.
+        */
+       mv88e61xxphy_vtu_wait(sc);
+
+       /*
+        * Set VID.
+        */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_VID,
+           MV88E61XX_GLOBAL_VTU_VID_VALID | vid);
+
+       /*
+        * Add ports to this VTU.
+        */
+       for (port = 0; port < MV88E61XX_PORTS; port++) {
+               struct mv88e61xxphy_port_softc *psc;
+
+               psc = &sc->sc_ports[port];
+               if (psc->sc_vlan == vid) {
+                       /*
+                        * Send this port its VLAN traffic untagged.
+                        */
+                       psc->sc_flags &= ~MV88E61XXPHY_PORT_FLAG_VTU_UPDATE;
+                       mv88e61xxphy_vtu_set_membership(sc, port, 
MV88E61XXPHY_VTU_UNTAGGED);
+               } else if (psc->sc_port == MV88E61XX_HOST_PORT) {
+                       /*
+                        * The host sees all VLANs tagged.
+                        */
+                       mv88e61xxphy_vtu_set_membership(sc, port, 
MV88E61XXPHY_VTU_TAGGED);
+               } else {
+                       /*
+                        * This port isn't on this VLAN.
+                        */
+                       mv88e61xxphy_vtu_set_membership(sc, port, 
MV88E61XXPHY_VTU_DISCARDED);
+               }
+       }
+
+       /*
+        * Start adding this entry.
+        */
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP,
+           MV88E61XX_GLOBAL_VTU_OP_BUSY |
+           MV88E61XX_GLOBAL_VTU_OP_OP_VTU_LOAD);
+}
+
+static void
+mv88e61xxphy_vtu_set_membership(struct mv88e61xxphy_softc *sc, unsigned port,
+    enum mv88e61xxphy_vtu_membership_type type)
+{
+       unsigned shift, reg;
+       uint16_t bits;
+       uint16_t val;
+
+       switch (type) {
+       case MV88E61XXPHY_VTU_UNMODIFIED:
+               bits = 0;
+               break;
+       case MV88E61XXPHY_VTU_UNTAGGED:
+               bits = 1;
+               break;
+       case MV88E61XXPHY_VTU_TAGGED:
+               bits = 2;
+               break;
+       case MV88E61XXPHY_VTU_DISCARDED:
+               bits = 3;
+               break;
+       default:
+               return;
+       }
+
+       if (port < 4) {
+               reg = MV88E61XX_GLOBAL_VTU_DATA_P0P3;
+               shift = port * 4;
+       } else {
+               reg = MV88E61XX_GLOBAL_VTU_DATA_P4P5;
+               shift = (port - 4) * 4;
+       }
+
+       val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, reg);
+       val |= bits << shift;
+       MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, reg, val);
+}
+
+static void
+mv88e61xxphy_vtu_wait(struct mv88e61xxphy_softc *sc)
+{
+       uint16_t val;
+
+       for (;;) {
+               val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, 
MV88E61XX_GLOBAL_VTU_OP);
+               if ((val & MV88E61XX_GLOBAL_VTU_OP_BUSY) == 0)
+                       return;
+       }
+}
+
+static device_method_t mv88e61xxphy_methods[] = {
+       /* device interface */
+       DEVMETHOD(device_probe,         mv88e61xxphy_probe),
+       DEVMETHOD(device_attach,        mv88e61xxphy_attach),
+       DEVMETHOD(device_detach,        bus_generic_detach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+
+       { 0, 0 }
+};
+
+static devclass_t mv88e61xxphy_devclass;
+
+static driver_t mv88e61xxphy_driver = {
+       "mv88e61xxphy",
+       mv88e61xxphy_methods,
+       sizeof(struct mv88e61xxphy_softc)
+};
+
+DRIVER_MODULE(mv88e61xxphy, octe, mv88e61xxphy_driver, mv88e61xxphy_devclass, 
0, 0);

Added: head/sys/mips/cavium/octe/mv88e61xxphyreg.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/mips/cavium/octe/mv88e61xxphyreg.h Wed Oct 13 09:17:44 2010        
(r213762)
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2010 Juli Mallett <jmall...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Register definitions for Marvell MV88E61XX
+ *
+ * Note that names and definitions were gleaned from Linux and U-Boot patches
+ * released by Marvell, often by looking at contextual use of the registers
+ * involved, and may not be representative of the full functionality of those
+ * registers and are certainly not an exhaustive enumeration of registers.
+ *
+ * For an exhaustive enumeration of registers, check out the QD-DSDT package
+ * included in the Marvell ARM Feroceon Board Support Package for Linux.
+ */
+
+#ifndef        _MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_
+#define        _MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_
+
+/*
+ * Port addresses & per-port registers.
+ */
+#define        MV88E61XX_PORT(x)       (0x10 + (x))
+#define        MV88E61XX_HOST_PORT     (5)
+#define        MV88E61XX_PORTS         (6)
+
+#define        MV88E61XX_PORT_STATUS           (0x00)
+#define        MV88E61XX_PORT_FORCE_MAC        (0x01)
+#define        MV88E61XX_PORT_PAUSE_CONTROL    (0x02)
+#define        MV88E61XX_PORT_REVISION         (0x03)
+#define        MV88E61XX_PORT_CONTROL          (0x04)
+#define        MV88E61XX_PORT_CONTROL2         (0x05)
+#define        MV88E61XX_PORT_VLAN_MAP         (0x06)
+#define        MV88E61XX_PORT_VLAN             (0x07)
+#define        MV88E61XX_PORT_FILTER           (0x08)
+#define        MV88E61XX_PORT_EGRESS_CONTROL   (0x09)
+#define        MV88E61XX_PORT_EGRESS_CONTROL2  (0x0a)
+#define        MV88E61XX_PORT_PORT_LEARN       (0x0b)
+#define        MV88E61XX_PORT_ATU_CONTROL      (0x0c)
+#define        MV88E61XX_PORT_PRIORITY_CONTROL (0x0d)
+#define        MV88E61XX_PORT_ETHER_PROTO      (0x0f)
+#define        MV88E61XX_PORT_PROVIDER_PROTO   (0x1a)
+#define        MV88E61XX_PORT_PRIORITY_MAP     (0x18)
+#define        MV88E61XX_PORT_PRIORITY_MAP2    (0x19)
+
+/*
+ * Fields and values in each register.
+ */
+#define        MV88E61XX_PORT_STATUS_MEDIA             (0x0300)
+#define        MV88E61XX_PORT_STATUS_MEDIA_10M         (0x0000)
+#define        MV88E61XX_PORT_STATUS_MEDIA_100M        (0x0100)
+#define        MV88E61XX_PORT_STATUS_MEDIA_1G          (0x0200)
+#define        MV88E61XX_PORT_STATUS_DUPLEX            (0x0400)
+#define        MV88E61XX_PORT_STATUS_LINK              (0x0800)
+#define        MV88E61XX_PORT_STATUS_FC                (0x8000)
+
+#define        MV88E61XX_PORT_CONTROL_DOUBLE_TAG       (0x0200)
+
+#define        MV88E61XX_PORT_FILTER_MAP_DEST          (0x0080)
+#define        MV88E61XX_PORT_FILTER_DISCARD_UNTAGGED  (0x0100)
+#define        MV88E61XX_PORT_FILTER_DISCARD_TAGGED    (0x0200)
+#define        MV88E61XX_PORT_FILTER_8021Q_MODE        (0x0c00)
+#define        MV88E61XX_PORT_FILTER_8021Q_DISABLED    (0x0000)
+#define        MV88E61XX_PORT_FILTER_8021Q_FALLBACK    (0x0400)
+#define        MV88E61XX_PORT_FILTER_8021Q_CHECK       (0x0800)
+#define        MV88E61XX_PORT_FILTER_8021Q_SECURE      (0x0c00)
+
+/*
+ * Global address & global registers.
+ */
+#define        MV88E61XX_GLOBAL        (0x1b)
+
+#define        MV88E61XX_GLOBAL_STATUS         (0x00)
+#define        MV88E61XX_GLOBAL_CONTROL        (0x04)
+#define        MV88E61XX_GLOBAL_VTU_OP         (0x05)
+#define        MV88E61XX_GLOBAL_VTU_VID        (0x06)
+#define        MV88E61XX_GLOBAL_VTU_DATA_P0P3  (0x07)
+#define        MV88E61XX_GLOBAL_VTU_DATA_P4P5  (0x08)
+#define        MV88E61XX_GLOBAL_ATU_CONTROL    (0x0a)
+#define        MV88E61XX_GLOBAL_PRIORITY_MAP   (0x18)
+#define        MV88E61XX_GLOBAL_MONITOR        (0x1a)
+#define        MV88E61XX_GLOBAL_REMOTE_MGMT    (0x1c)
+#define        MV88E61XX_GLOBAL_STATS          (0x1d)
+
+/*
+ * Fields and values in each register.
+ */
+#define        MV88E61XX_GLOBAL_VTU_OP_BUSY            (0x8000)
+#define        MV88E61XX_GLOBAL_VTU_OP_OP              (0x7000)
+#define        MV88E61XX_GLOBAL_VTU_OP_OP_FLUSH        (0x1000)
+#define        MV88E61XX_GLOBAL_VTU_OP_OP_VTU_LOAD     (0x3000)
+
+#define        MV88E61XX_GLOBAL_VTU_VID_VALID          (0x1000)
+
+/*
+ * Second global address & second global registers.
+ */
+#define        MV88E61XX_GLOBAL2       (0x1c)
+
+#define        MV88E61XX_GLOBAL2_MANAGE_2X     (0x02)
+#define        MV88E61XX_GLOBAL2_MANAGE_0X     (0x03)
+#define        MV88E61XX_GLOBAL2_CONTROL2      (0x05)
+#define        MV88E61XX_GLOBAL2_TRUNK_MASK    (0x07)
+#define        MV88E61XX_GLOBAL2_TRUNK_MAP     (0x08)
+#define        MV88E61XX_GLOBAL2_RATELIMIT     (0x09)
+#define        MV88E61XX_GLOBAL2_VLAN_CONTROL  (0x0b)
+#define        MV88E61XX_GLOBAL2_MAC_ADDRESS   (0x0d)
+
+/*
+ * Fields and values in each register.
+ */
+#define        MV88E61XX_GLOBAL2_CONTROL2_DOUBLE_USE   (0x8000)
+#define        MV88E61XX_GLOBAL2_CONTROL2_LOOP_PREVENT (0x4000)
+#define        MV88E61XX_GLOBAL2_CONTROL2_FLOW_MESSAGE (0x2000)
+#define        MV88E61XX_GLOBAL2_CONTROL2_FLOOD_BC     (0x1000)
+#define        MV88E61XX_GLOBAL2_CONTROL2_REMOVE_PTAG  (0x0800)
+#define        MV88E61XX_GLOBAL2_CONTROL2_AGE_INT      (0x0400)
+#define        MV88E61XX_GLOBAL2_CONTROL2_FLOW_TAG     (0x0200)
+#define        MV88E61XX_GLOBAL2_CONTROL2_ALWAYS_VTU   (0x0100)
+#define        MV88E61XX_GLOBAL2_CONTROL2_FORCE_FC_PRI (0x0080)
+#define        MV88E61XX_GLOBAL2_CONTROL2_FC_PRI       (0x0070)
+#define        MV88E61XX_GLOBAL2_CONTROL2_MGMT_TO_HOST (0x0008)
+#define        MV88E61XX_GLOBAL2_CONTROL2_MGMT_PRI     (0x0007)
+
+#endif /* !_MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ */

Modified: head/sys/mips/cavium/octe/octe.c
==============================================================================
--- head/sys/mips/cavium/octe/octe.c    Wed Oct 13 06:28:40 2010        
(r213761)
+++ head/sys/mips/cavium/octe/octe.c    Wed Oct 13 09:17:44 2010        
(r213762)
@@ -146,6 +146,7 @@ octe_attach(device_t dev)
 {
        struct ifnet *ifp;
        cvm_oct_private_t *priv;
+       device_t child;
        unsigned qos;
        int error;
 
@@ -155,10 +156,15 @@ octe_attach(device_t dev)
        if_initname(ifp, device_get_name(dev), device_get_unit(dev));
 
        if (priv->phy_id != -1) {
-               error = mii_phy_probe(dev, &priv->miibus, octe_mii_medchange,
-                                     octe_mii_medstat);
-               if (error != 0) {
-                       device_printf(dev, "missing phy %u\n", priv->phy_id);
+               if (priv->phy_device == NULL) {
+                       error = mii_phy_probe(dev, &priv->miibus, 
octe_mii_medchange,
+                                             octe_mii_medstat);
+                       if (error != 0)
+                               device_printf(dev, "missing phy %u\n", 
priv->phy_id);
+               } else {
+                       child = device_add_child(dev, priv->phy_device, -1);
+                       if (child == NULL)
+                               device_printf(dev, "missing phy %u device 
%s\n", priv->phy_id, priv->phy_device);
                }
        }
 
@@ -202,7 +208,7 @@ octe_attach(device_t dev)
        IFQ_SET_READY(&ifp->if_snd);
        OCTE_TX_UNLOCK(priv);
 
-       return (0);
+       return (bus_generic_attach(dev));
 }
 
 static int

Modified: head/sys/mips/conf/OCTEON1
==============================================================================
--- head/sys/mips/conf/OCTEON1  Wed Oct 13 06:28:40 2010        (r213761)
+++ head/sys/mips/conf/OCTEON1  Wed Oct 13 09:17:44 2010        (r213762)
@@ -180,6 +180,10 @@ device             uart            # Generic UART driver
 # NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
 device         octe
 
+# Switch PHY support for the octe driver.  These currently present a VLAN per
+# physical port, but may eventually provide support for DSA or similar instead.
+#device                mv88e61xxphy    # Marvell 88E61XX
+
 # PCI Ethernet NICs.
 device         de              # DEC/Intel DC21x4x (``Tulip'')
 device         em              # Intel PRO/1000 Gigabit Ethernet Family
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to