root/usr/src/uts/common/sys/mii.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * mii.h
 * Generic MII/PHY Support for MAC drivers.
 */

#ifndef _SYS_MII_H
#define _SYS_MII_H

#include <sys/mac_provider.h>
#include <sys/netlb.h>

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * NOTES
 *
 * The device driver is required to protect its own registers.  The
 * MII common code will call MII entry points asynchronously, from a
 * taskq, and holds an internal lock across such calls (except the
 * notify entry point).  Therefore, device drivers MUST NOT hold any
 * locks across calls into the MII framework.
 *
 * If a device must be suspended (e.g. due to DDI_SUSPEND) the MII
 * layer can be suspended by calling mii_stop().  After this point,
 * the monitoring task will be suspended and the driver can be assured
 * that MII will not interfere until restarted with mii_start().
 *
 * Note that monitoring is not started until mii_start() is called.
 * The mii_start() function may be called multiple times.  It performs
 * an implicit reset of the MII bus and PHY.
 *
 * Once started, if not already done, a probe of the MII bus is done to
 * find a suitable PHY.  If no PHY is found, then you won't have any
 * link!  Once a suitable PHY is selected, any other PHYs are isolated and
 * powered down.  The device driver can cause MII to re-probe the bus for
 * changes to the available PHYs by calling mii_probe().  Note that this
 * will also cause a full reset of all PHYs.
 *
 * The mii_reset entry point, which is optional, is used to notify the
 * driver when the MII layer has reset the device.  This can allow
 * certain drivers the opportunity to "fix up" things after reset.
 * Note however, that when possible, it is better if the logic is
 * encoded into a vendor specific PHY module.
 */

#ifdef  _KERNEL

typedef struct mii_handle *mii_handle_t;
typedef struct mii_ops mii_ops_t;

struct mii_ops {
        int             mii_version;
        uint16_t        (*mii_read)(void *, uint8_t, uint8_t);
        void            (*mii_write)(void *, uint8_t, uint8_t, uint16_t);
        void            (*mii_notify)(void *, link_state_t);
        void            (*mii_reset)(void *);
};
#define MII_OPS_VERSION 0

/*
 * Support routines.
 */

/*
 * mii_alloc
 *
 *      Allocate an MII handle.  Called during driver's attach(9e)
 *      handling, this routine is valid in kernel context only.
 *
 * Arguments
 *
 *      private         A private state structure, provided back to
 *                      entry points.
 *      dip             The dev_info node for the MAC driver.
 *      ops             Entry points into the MAC driver.
 *
 * Returns
 *      Handle to MII bus on success, NULL on failure.
 */
mii_handle_t mii_alloc(void *private, dev_info_t *dip, mii_ops_t *ops);

/*
 * mii_alloc
 *
 *      Allocate an MII handle.  Called during driver's attach(9e)
 *      handling, this routine is valid in kernel context only.  This
 *      routine is an alternative to mii_alloc() for use when the
 *      instance number (PPA) is not the same as the devinfo instance
 *      number, and hence needs to be overridden.
 *
 * Arguments
 *
 *      private         A private state structure, provided back to
 *                      entry points.
 *      dip             The dev_info node for the MAC driver.
 *      instance        The instance (PPA) of the interface.
 *      ops             Entry points into the MAC driver.
 *
 * Returns
 *      Handle to MII bus on success, NULL on failure.
 */
mii_handle_t mii_alloc_instance(void *private, dev_info_t *dip, int instance,
    mii_ops_t *ops);

/*
 * mii_free
 *
 *      Free an MII handle and associated resources.  Call from
 *      detach(9e) handling, this routine is valid in kernel context
 *      only.
 */
void mii_free(mii_handle_t mii);

/*
 * mii_set_pauseable
 *
 *      Lets the MII know if the MAC layer can support pause or
 *      asymetric pause capabilities.  The MII layer will use this to
 *      determine what capabilities should be negotiated for (along
 *      with user preferences, of course.)  If not called, the MII
 *      will assume the device has no support for flow control.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      cap             B_TRUE if the device supports symmetric of pause.
 *      asym            B_TRUE if the device supports asymmetric pause.
 */
void mii_set_pauseable(mii_handle_t mii, boolean_t cap, boolean_t asym);

/*
 * mii_reset
 *
 *      Schedules a reset of the MII bus.  Normally not needed, but
 *      can be used to perform a full master reset, including
 *      rescanning for PHYs.  This function may be called in any
 *      context except high level interrupt context, but must be
 *      called without any locks held.  The reset will probably not
 *      be complete until sometime after the call returns.
 *
 *      Note that if mii_start has not been called, then the reset
 *      will not be performed until _after_ the MII is started.
 */
void mii_reset(mii_handle_t mii);


/*
 * mii_start
 *
 *      Starts monitoring of the MII bus.  Normally this is called as
 *      a result of a driver's mac_start() entry point, but it may also
 *      be called when a PHY needs to be reset or during handling of
 *      DDI_RESUME.   This function may be called in any context except
 *      high level interrupt context, but
 *      must be called without any locks held.
 */
void mii_start(mii_handle_t mii);

/*
 * mii_stop
 *
 *      Stops monitoring of the MII bus.  Normally this is called as a
 *      result of a driver's mac_stop() entry point.  As a side
 *      effect, also isolates and powers down any active PHY.  On
 *      return, the MII layer is guaranteed not to be executing any
 *      code in the MII entry points.  This function may be called in
 *      any context except high level interrupt context, but must be
 *      called without any locks held.
 */
void mii_stop(mii_handle_t mii);

/*
 * mii_resume
 *
 *      Starts monitoring of the MII bus.  Normally this is called as
 *      a part of a driver's DDI_RESUME handling.  This function may
 *      be called in any context except high level interrupt context,
 *      but must be called without any locks held.
 */
void mii_resume(mii_handle_t mii);

/*
 * mii_suspend
 *
 *      Suspends monitoring of the MII bus.  Normally this is called
 *      as a part of a driver's DDI_SUSPEND handling.  On return, the
 *      MII layer is guaranteed not to be executing any code in the
 *      MII entry points.  This function may be called in any context
 *      except high level interrupt context, but must be called
 *      without any locks held.
 */
void mii_suspend(mii_handle_t mii);

/*
 * mii_probe
 *
 *      Used to reset the entire MII bus and probe for PHYs.  This
 *      routine should be called if the driver has reason to believe that
 *      PHYs have changed.  This is implicitly executed the first time
 *      monitoring is started on the MII bus, and normally need not be
 *      explicitly called. This function may be called in any context
 *      except high level interrupt context, but must be called
 *      without any locks held.
 */
void mii_probe(mii_handle_t mii);

/*
 * mii_check
 *
 *      Used to alert the MII layer that it should check for changes.
 *      This can be called by drivers in response to link status
 *      interrupts, for example, giving a quicker response to link
 *      status changes without waiting for the MII timer to expire.
 *      This function may be called in any context except high level
 *      interrupt context, but must be called without any locks held.
 */
void mii_check(mii_handle_t mii);

/*
 * mii_get_addr
 *
 *      Used to get the PHY address that is currently active for the MII
 *      bus.  This function may be called in any context.
 *
 * Returns
 *
 *      The PHY address (0-31) if a PHY is active on the MII bus.  If
 *      no PHY is active, -1 is returned.
 */
int mii_get_addr(mii_handle_t mii);

/*
 * mii_get_id
 *
 *      Used to get the identifier of the active PHY.  This function
 *      may be called in any context.
 *
 * Returns
 *
 *      The PHY identifier register contents, encoded with the high
 *      order (PHYIDH) bits in the upper word and the low order bits
 *      in the lower word.  If no PHY is active, the value -1 will be
 *      returned.
 */
uint32_t mii_get_id(mii_handle_t mii);

/*
 * mii_get_speed
 *
 *      Used to get the speed of the active PHY.  This function may be
 *      called in any context.
 *
 * Returns
 *
 *      The speed, in Mbps, if the active PHY has link (10, 100, or 1000),
 *      otherwise 0.
 */
int mii_get_speed(mii_handle_t mii);

/*
 * mii_get_duplex
 *
 *      Used to get the duplex of the active PHY.  This function may
 *      be called in any context.
 *
 * Returns
 *
 *      The duplex, if the active PHY has link (LINK_DUPLEX_FULL or
 *      LINK_DUPLEX_HALF), otherwise LINK_DUPLEX_UNKNOWN.
 */
link_duplex_t mii_get_duplex(mii_handle_t mii);

/*
 * mii_get_state
 *
 *      Used to get the state of the link on the active PHY.  This
 *      function may be called in any context.
 *
 * Returns
 *
 *      The link state (LINK_STATE_UP or LINK_STATE_DOWN), if known,
 *      otherwise LINK_STATE_UNKNOWN.
 */
link_state_t mii_get_state(mii_handle_t mii);

/*
 * mii_get_flowctrl
 *
 *      Used to get the state of the negotiated flow control on the
 *      active PHY.  This function may be called in any context.
 *
 * Returns
 *
 *      The flowctrl state (LINK_FLOWCTRL_NONE, LINK_FLOWCTRL_RX,
 *      LINK_FLOWCTRL_TX, or LINK_FLOWCTRL_BI.
 */
link_flowctrl_t mii_get_flowctrl(mii_handle_t mii);

/*
 * mii_get_loopmodes
 *
 *      This function is used to support the LB_GET_INFO_SIZE and
 *      LB_GET_INFO ioctls.  It probably should not be used outside of
 *      that context.  The modes supplied are supported by the MII/PHY.
 *      Drivers may wish to add modes for MAC internal loopbacks as well.
 *      See <sys/netlb.h> for more information.
 *
 *      Note that the first item in the modes array will always be the
 *      mode to disable the MII/PHY loopback, and will have the value
 *      MII_LOOPBACK_NONE.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      modes           Location to receive an array of loopback modes.
 *                      Drivers should ensure that enough room is available.
 *                      There will never be more than MII_LOOPBACK_MAX modes
 *                      returned.  May be NULL, in which case no data will
 *                      be returned to the caller.
 *
 * Returns
 *
 *      Count of number of modes available, in no case larger than
 *      MII_LOOPBACK_MAX.
 */
int mii_get_loopmodes(mii_handle_t mii, lb_property_t *modes);

#define MII_LOOPBACK_MAX        16
#define MII_LOOPBACK_NONE       0

/*
 * mii_set_loopback
 *
 *      Sets the loopback mode, intended for use in support of the
 *      LB_SET_MODE ioctl.  The mode value will be one of the values
 *      returned in the modes array (see mii_get_loopmodes), or the
 *      special value MII_LOOPBACK_NONE to return to normal operation.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      mode            New loopback mode number; MII_LOOPBACK_NONE indicates
 *                      a return to normal operation.
 *
 * Returns
 *
 *      Zero on success, or EINVAL if the mode is invalid or unsupported.
 */
int mii_set_loopback(mii_handle_t mii, uint32_t mode);

/*
 * mii_get_loopback
 *
 *      Queries the loopback mode, intended for use in support of the
 *      LB_GET_MODE ioctl, but may be useful in programming device
 *      settings that are sensitive to loopback setting.
 *
 * Returns
 *
 *      The current mode number (one of the reported by
 *      mii_get_loopmodes), or the special value MII_LOOPBACK_NONE
 *      indicating that loopback is not in use.
 */
uint32_t mii_get_loopback(mii_handle_t mii);

/*
 * mii_m_loop_ioctl
 *
 *      Used to support the driver's mc_ioctl() for loopback ioctls.
 *      If the driver is going to use the loopback optons from the
 *      PHY, and isn't adding any MAC level loopback, then this function
 *      can handle the entire set of ioctls, removing yet more code from
 *      the driver.  Ultimately, this is a very reasonable thing to do,
 *      since the PHY level loopback should exercise all of the same
 *      MAC level circuitry that a MAC internal loopback would do.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      wq              The write queue supplied to mc_ioctl().
 *      msg             The mblk from the mc_ioctl (contains an iocblk).
 *
 * Returns
 *
 *      B_TRUE if the ioctl was handled by the driver.
 *      B_FALSE if the ioctl was not handled, and may need to be
 *      handled by the driver.
 */
boolean_t mii_m_loop_ioctl(mii_handle_t mii, queue_t *wq, mblk_t *msg);

/*
 * mii_m_getprop
 *
 *      Used to support the driver's mc_getprop() mac callback,
 *      and only to be called from that function (and without any
 *      locks held).  This routine will process all of the properties
 *      that are relevant to MII on behalf of the driver.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      name            Property name.
 *      id              Property ID.
 *      sz              Size of property in bytes.
 *      val             Location to receive property value.
 *
 * Returns
 *
 *      0 on successful handling of property.
 *      EINVAL if invalid arguments (e.g. a bad size) are supplied.
 *      ENOTSUP if the prooperty is not supported by MII or the PHY.
 */
int mii_m_getprop(mii_handle_t mii, const char *name, mac_prop_id_t id,
    uint_t sz, void *val);

/*
 * mii_m_setprop
 *
 *      Used to support the driver's mc_setprop() mac callback,
 *      and only to be called from that function (and without any
 *      locks held).  This routine will process all of the properties
 *      that are relevant to MII on behalf of the driver.  This will
 *      often result in the PHY being reset.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      name            Property name.
 *      id              Property ID.
 *      sz              Size of property in bytes.
 *      val             Location of property value.
 *
 * Returns
 *
 *      0 on successful handling of property.
 *      EINVAL if invalid arguments (e.g. a bad size) are supplied.
 *      ENOTSUP if the prooperty is not supported by MII or the PHY,
 *      or if the property is read-only.
 */
int mii_m_setprop(mii_handle_t mii, const char *name, mac_prop_id_t id,
    uint_t sz, const void *val);

/*
 * mii_m_propinfo
 *
 *      Used to support the driver's mc_setprop() mac callback,
 *      and only to be called from that function (and without any
 *      locks held).
 *
 * Arguments
 *
 *      mii             MII handle.
 *      name            Property name.
 *      id              Property ID.
 *      prh             Property info handle.
 *
 */
void mii_m_propinfo(mii_handle_t mii, const char *name, mac_prop_id_t id,
    mac_prop_info_handle_t prh);


/*
 * mii_m_getstat
 *
 *      Used to support the driver's mc_getstat() mac callback for
 *      statistic collection, and only to be called from that function
 *      (without any locks held).  This routine will process all of
 *      the statistics that are relevant to MII on behalf of the
 *      driver.
 *
 * Arguments
 *
 *      mii             MII handle.
 *      stat            Statistic number.
 *      val             Location to receive statistic value.
 *
 * Returns
 *
 *      0 on successful handling of statistic.
 *      ENOTSUP if the statistic is not supported by MII.
 */
int mii_m_getstat(mii_handle_t mii, uint_t stat, uint64_t *val);

#endif  /* _KERNEL */

#ifdef  __cplusplus
}
#endif

#endif /* _SYS_MII_H */