From e131ac0754276a757cb7a5cb731fd4aa618f84fe Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 3 Nov 2005 03:09:45 +0000 Subject: 2005-11-02 straumanatslacdotstanford.edu * libnetworking/Makefile.am, libnetworking/preinstall.am: Added simple implementation of ethernet media ioctl SIOCSIFMEDIA/SIOCGIFMEDIA for mii compliant phys. * libnetworking/rtems/rtems_mii_ioctl.c, libnetworking/rtems/rtems_mii_ioctl.h, libnetworking/rtems/rtems_mii_ioctl_kern.c: New files. --- cpukit/ChangeLog | 9 + cpukit/libnetworking/rtems/rtems_mii_ioctl.c | 129 +++++++++++++++ cpukit/libnetworking/rtems/rtems_mii_ioctl.h | 99 +++++++++++ cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c | 193 ++++++++++++++++++++++ 4 files changed, 430 insertions(+) create mode 100644 cpukit/libnetworking/rtems/rtems_mii_ioctl.c create mode 100644 cpukit/libnetworking/rtems/rtems_mii_ioctl.h create mode 100644 cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index ed2fc2942b..c06eea1227 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,12 @@ +2005-11-02 straumanatslacdotstanford.edu + + * libnetworking/Makefile.am, + libnetworking/preinstall.am: Added simple implementation of ethernet + media ioctl SIOCSIFMEDIA/SIOCGIFMEDIA for mii compliant phys. + * libnetworking/rtems/rtems_mii_ioctl.c, + libnetworking/rtems/rtems_mii_ioctl.h, + libnetworking/rtems/rtems_mii_ioctl_kern.c: New files. + 2005-11-02 straumanatslacdotstanford.edu * libi2c/Makefile.am, libi2c/Makefile.in, libi2c/libi2c.c, diff --git a/cpukit/libnetworking/rtems/rtems_mii_ioctl.c b/cpukit/libnetworking/rtems/rtems_mii_ioctl.c new file mode 100644 index 0000000000..5ee8186f05 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_mii_ioctl.c @@ -0,0 +1,129 @@ +/* $Id$ */ + +/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA + * to be used by ethernet drivers [from their ioctl]. + * + * USERSPACE UTILITIES + * + * NOTE: This much simpler than the BSD ifmedia API + */ + +/* Author: Till Straumann, , 2005 */ + +#include + +#undef _KERNEL +#undef KERNEL + +#include + +#include +#include +#include +#include +#include + +static struct ifmedia_description shared_media_strings[] = + IFM_SUBTYPE_SHARED_DESCRIPTIONS; +static struct ifmedia_description ethern_media_strings[] = + IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; +static struct ifmedia_description eth_al_media_strings[] = + IFM_SUBTYPE_ETHERNET_ALIASES; + +static const char * +find_desc (int tag, struct ifmedia_description *list) +{ + while (list->ifmt_string && tag != list->ifmt_word) + list++; + return list->ifmt_string; +} + +#define WHATPRINT(buf,sz,fmt...) \ + ( (sz) > 0 ? snprintf((buf),(sz),fmt) : fprintf((buf) ? (FILE*)(buf) : stdout, fmt) ) + +int +rtems_ifmedia2str (int media, char *buf, int bufsz) +{ + const char *mdesc; + const char *dupdesc = 0; + + /* only ethernet supported, so far */ + if (IFM_ETHER != IFM_TYPE (media)) + return -1; + + if (!(mdesc = find_desc (IFM_SUBTYPE (media), shared_media_strings))) + mdesc = find_desc (IFM_SUBTYPE (media), ethern_media_strings); + + if (!mdesc) + return -1; + + if (IFM_NONE != IFM_SUBTYPE (media)) + dupdesc = IFM_FDX & media ? " full-duplex" : " half-duplex"; + + return WHATPRINT (buf, bufsz, + "Ethernet [phy instance: %i]: (link %s, autoneg %s) -- media: %s%s", + IFM_INST (media), + IFM_LINK_OK & media ? "ok" : "down", + IFM_ANEG_DIS & media ? "off" : "on", + mdesc, dupdesc ? dupdesc : ""); +} + +static int +find_tag (const char *desc, struct ifmedia_description *list) +{ + while (list->ifmt_string) { + if (strstr (desc, list->ifmt_string)) + return list->ifmt_word; + list++; + } + return -1; +} + + +/* convert a string to a media word + * RETURNS: 0 on failure; valid results have always at least IFM_ETHER set + */ +int +rtems_str2ifmedia (const char *str, int phy) +{ + int sub, opt = 0; + char *chpt; + + if (!strncmp (str, "auto", 4)) { + sub = IFM_AUTO; + } else if ((sub = find_tag (str, ethern_media_strings)) < 0) { + if ((sub = find_tag (str, eth_al_media_strings)) < 0) { + /* allow more */ + + /* if no number, 0 is returned which will not pass the test */ + switch (strtol (str, &chpt, 10)) { + case 10: + sub = IFM_10_T; + break; + case 100: + sub = IFM_100_TX; + break; + case 1000: + sub = IFM_1000_T; + break; + default: + return 0; + } + + /* need 'b' or 'base' */ + if ('b' != *chpt++) + return 0; + if (!strncmp (chpt, "ase", 3)) + chpt += 3; + if (toupper (*chpt++) != 'T') + return 0; + if (IFM_100_TX == sub && toupper (*chpt++) != 'X') + return 0; + } + } + + if (strstr (str, "full") || strstr (str, "FDX") || strstr (str, "fdx")) + opt |= IFM_FDX; + + return IFM_MAKEWORD (IFM_ETHER, sub, opt, phy); +} diff --git a/cpukit/libnetworking/rtems/rtems_mii_ioctl.h b/cpukit/libnetworking/rtems/rtems_mii_ioctl.h new file mode 100644 index 0000000000..5de2ed4f09 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_mii_ioctl.h @@ -0,0 +1,99 @@ +#ifndef RTEMS_MII_IOCTL_H +#define RTEMS_MII_IOCTL_H + +/* $Id$ */ + +/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA + * to be used by ethernet drivers [from their ioctl]. + * + * NOTE: This much simpler than the BSD ifmedia API + */ + +/* Author: Till Straumann, , 2005 */ + +/* These should be moved out of ... */ +#include /* MII register definitions */ +#include /* media word definitions; rest of API (ifmedia) unused! */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL) || defined(__KERNEL__) +/* mdio routines to be provided by driver */ + +/* read mii register 'reg' at 'phy' (-1 meaning any/currently active) + * RETURNS 0 on success, -1 otherwise (e.g., illegal phy) + */ +typedef int (*rtems_mdio_read_func) (int phy, void *uarg, unsigned reg, + unsigned32 * pval); + +/* write mii register 'reg' at 'phy' (-1 meaning any/currently active) + * RETURNS 0 on success, -1 otherwise (e.g., illegal phy) + */ +typedef int (*rtems_mdio_write_func) (int phy, void *uarg, unsigned reg, + unsigned32 val); + +/* Values to this must be provided by the driver */ +struct rtems_mdio_info +{ + rtems_mdio_read_func mdio_r; + rtems_mdio_write_func mdio_w; + unsigned has_gmii:1; /* supports gigabit */ +}; + +/* Implement SIOCSIFMEDIA/SIOCGIFMEDIA; get/set the current media word. Note + * that this does NOT implement the full BSD 'ifmedia' API; also, it only + * implements IFM_ETHER... + * + * INPUT: + * SIOCGIFMEDIA: the media word must set the phy instance (-1 for 'any') + * + */ +int +rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, int cmd, + int *media); + +#endif + +/* The driver flags have the following meaning (SIOCGIFMEDIA only): + */ +#define IFM_LINK_OK IFM_FLAG0 +#define IFM_ANEG_DIS IFM_FLAG1 /* autoneg. disabled; media forced */ + +/* convert a media word to a string; + * + * RETURNS: number of characters written to 'buf' + * + * INPUT: if 'bufsz' is set to IFMEDIA2STR_PRINT_TO_FILE, 'buf' can be a FILE pointer + * where the info is printed insted. This can be NULL in which + * case 'stdout' is used. + */ + +#define IFMEDIA2STR_PRINT_TO_FILE 0 + +int rtems_ifmedia2str (int media, char *buf, int bufsz); + +/* convert a string to a media word + * RETURNS: 0 on failure (unrecognized or invalid mode); + * valid results have always at least IFM_ETHER set. + * + * In addition to IFM_SUBTYPE_ETHERNET_DESCRIPTIONS and IFM_SUBTYPE_ETHERNET_ALIASES, + * the strings + * + * '10' [ '0' [ '0' ]] 'b' [ 'ase' ] ( 't' | 'T' ) (* if 100bT [ 'x' | 'X' ] is required here *) + * + * are recognized (e.g., 10bT, 100bTX) + * + * if any of the strings 'full' or 'FDX' or 'fdx' is present, a full-duplex mode + * is selected (half-duplex otherwise). + * e.g., '100bTx-full' + */ + +int rtems_str2ifmedia (const char *str, int phy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c b/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c new file mode 100644 index 0000000000..cd763917be --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c @@ -0,0 +1,193 @@ +/* $Id$ */ + +/* 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 + */ + +/* Author: Till Straumann, , 2005 */ + +/* include first to avoid 'malloc' clash with rtems_bsdnet_malloc() hack */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include + +#include + + +#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, int cmd, + int *media) +{ + unsigned32 bmcr, bmsr, bmcr2 = 0, bmsr2 = 0, anar, lpar; + int phy = IFM_INST (*media); + unsigned 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; + if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr)) + 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 */ + + 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; + 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; +} -- cgit v1.2.3