rtems-libbsd/rtemsbsd/rtems/rtems-legacy-mii.c
Sebastian Huber 02373194fe Update due to Newlib 2017-06-07 changes
The following files are now provided by Newlib:

  * arpa/inet.h
  * net/if.h
  * netinet/in.h
  * netinet/tcp.h
  * sys/socket.h
  * sys/uio.h
  * sys/un.h

The <sys/param.h> and <sys/cpuset.h> are now compatible enough to be
used directly.

Update #2833.
2017-06-08 13:19:54 +02:00

255 lines
6.9 KiB
C

/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
* to be used by ethernet drivers [from their ioctl].
*
* KERNEL PART (support for drivers)
*
* NOTE: This much simpler than the BSD ifmedia API
*/
/*
* Authorship
* ----------
* This software was created by
* Till Straumann <strauman@slac.stanford.edu>, 2005,
* Stanford Linear Accelerator Center, Stanford University.
*
* Acknowledgement of sponsorship
* ------------------------------
* This software was produced by
* the Stanford Linear Accelerator Center, Stanford University,
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
*
* Government disclaimer of liability
* ----------------------------------
* Neither the United States nor the United States Department of Energy,
* nor any of their employees, makes any warranty, express or implied, or
* assumes any legal liability or responsibility for the accuracy,
* completeness, or usefulness of any data, apparatus, product, or process
* disclosed, or represents that its use would not infringe privately owned
* rights.
*
* Stanford disclaimer of liability
* --------------------------------
* Stanford University makes no representations or warranties, express or
* implied, nor assumes any liability for the use of this software.
*
* Stanford disclaimer of copyright
* --------------------------------
* Stanford University, owner of the copyright, hereby disclaims its
* copyright and all other rights in this software. Hence, anyone may
* freely use it for any purpose without restriction.
*
* Maintenance of notices
* ----------------------
* In the interest of clarity regarding the origin and status of this
* SLAC software, this and all the preceding Stanford University notices
* are to remain affixed to any copy or derivative of this software made
* or distributed by the recipient and are to be affixed to any copy of
* software made or distributed by the recipient that contains a copy or
* derivative of this software.
*
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
*/
/* include first to avoid 'malloc' clash with rtems_bsdnet_malloc() hack */
#include <machine/rtems-bsd-kernel-space.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <rtems/rtems_mii_ioctl.h>
#include <errno.h>
#define DEBUG
#ifndef MII_1000TCR
#define MII_1000TCR MII_100T2CR
#endif
#ifndef MII_1000TSR
#define MII_1000TSR MII_100T2SR
#endif
int
rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, uint32_t cmd,
int *media)
{
uint32_t bmcr, bmsr, aner, bmcr2 = 0, bmsr2 = 0, anar, lpar;
int phy = IFM_INST (*media);
uint32_t tmp;
int subtype = 0, options = 0;
switch (cmd) {
default:
return EINVAL;
#ifdef DEBUG
case 0:
#endif
case SIOCGIFMEDIA:
if (info->mdio_r (phy, uarg, MII_BMCR, &bmcr))
return EINVAL;
/* read BMSR twice to clear latched link status low */
if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
return EINVAL;
if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
return EINVAL;
if (info->mdio_r (phy, uarg, MII_ANER, &aner))
return EINVAL;
if (info->has_gmii) {
if (info->mdio_r (phy, uarg, MII_1000TCR, &bmcr2))
return EINVAL;
if (info->mdio_r (phy, uarg, MII_1000TSR, &bmsr2))
return EINVAL;
}
/* link status */
if (BMSR_LINK & bmsr)
options |= IFM_LINK_OK;
/* do we have autonegotiation disabled ? */
if (!(BMCR_AUTOEN & bmcr)) {
options |= IFM_ANEG_DIS;
/* duplex is enforced */
options |= BMCR_FDX & bmcr ? IFM_FDX : IFM_HDX;
/* determine speed */
switch (BMCR_SPEED (bmcr)) {
case BMCR_S10:
subtype = IFM_10_T;
break;
case BMCR_S100:
subtype = IFM_100_TX;
break;
case BMCR_S1000:
subtype = IFM_1000_T;
break;
default:
return ENOTSUP; /* ?? */
}
} else if (!(BMSR_LINK & bmsr) || !(BMSR_ACOMP & bmsr)) {
subtype = IFM_NONE;
} else {
/* everything ok on our side */
if ( ! (ANER_LPAN & aner) ) {
/* Link partner doesn't autonegotiate --> our settings are the
* result of 'parallel detect' (in particular: duplex status is HALF
* according to the standard!).
* Let them know that something's fishy...
*/
options |= IFM_ANEG_DIS;
}
tmp = ((bmcr2 << 2) & bmsr2) & (GTSR_LP_1000THDX | GTSR_LP_1000TFDX);
if (tmp) {
if (GTSR_LP_1000TFDX & tmp)
options |= IFM_FDX;
subtype = IFM_1000_T;
} else {
if (info->mdio_r (phy, uarg, MII_ANAR, &anar))
return EINVAL;
if (info->mdio_r (phy, uarg, MII_ANLPAR, &lpar))
return EINVAL;
if (ANLPAR_ACK & lpar) {
/* this is a negotiated link; otherwise we merely detect the partner's ability */
}
tmp = anar & lpar;
if (ANLPAR_TX_FD & tmp) {
options |= IFM_FDX;
subtype = IFM_100_TX;
} else if (ANLPAR_T4 & tmp) {
subtype = IFM_100_T4;
} else if (ANLPAR_TX & tmp) {
subtype = IFM_100_TX;
} else if (ANLPAR_10_FD & tmp) {
options |= IFM_FDX;
subtype = IFM_10_T;
} else {
subtype = IFM_10_T;
}
}
}
*media = IFM_MAKEWORD (IFM_ETHER, subtype, options, phy);
break;
#ifdef DEBUG
case 1:
#endif
case SIOCSIFMEDIA:
if (IFM_ETHER != IFM_TYPE (*media))
return EINVAL;
if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
return EINVAL;
tmp = (IFM_FDX & *media);
switch (IFM_SUBTYPE (*media)) {
default:
return ENOTSUP;
case IFM_AUTO:
bmcr = BMCR_AUTOEN | BMCR_STARTNEG;
tmp = 0;
break;
case IFM_1000_T:
if (!info->has_gmii)
return ENOTSUP;
if (info->mdio_r (phy, uarg, MII_EXTSR, &bmsr2))
return EINVAL;
if (!(bmsr2 & (tmp ? EXTSR_1000TFDX : EXTSR_1000THDX)))
return EOPNOTSUPP;
/* NOTE: gige standard demands auto-negotiation for gige links.
* Disabling autoneg did NOT work on the PHYs I tried
* (BCM5421S, intel 82540).
* I've seen drivers that simply change what they advertise
* to the desired gig mode and re-negotiate.
* We could do that here, too, but we don't see the point -
* If autoneg works fine then we can as well use it.
*/
bmcr = BMCR_S1000;
break;
case IFM_100_TX:
if (!(bmsr & (tmp ? BMSR_100TXFDX : BMSR_100TXHDX)))
return EOPNOTSUPP;
bmcr = BMCR_S100;
break;
case IFM_10_T:
if (!(bmsr & (tmp ? BMSR_10TFDX : BMSR_10THDX)))
return EOPNOTSUPP;
bmcr = BMCR_S10;
break;
}
if (tmp)
bmcr |= BMCR_FDX;
if (info->mdio_w (phy, uarg, MII_BMCR, bmcr))
return EINVAL;
/* TODO: should we adapt advertised capabilites ? */
break;
}
return 0;
}