source: rtems/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c @ a912777c

4.104.114.84.95
Last change on this file since a912777c was a912777c, checked in by Till Straumann <strauman@…>, on Aug 9, 2006 at 12:01:55 AM
  • libnetworking/rtems/rtems_mii_ioctl_kern.c: read ANER and include partner's autoneg capability when determining active link parameters.
  • Property mode set to 100644
File size: 4.6 KB
Line 
1/* $Id$ */
2
3/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
4 * to be used by ethernet drivers [from their ioctl].
5 *
6 * KERNEL PART (support for drivers)
7 *
8 * NOTE: This much simpler than the BSD ifmedia API
9 */
10
11/* Author: Till Straumann, <straumanatslacdotstandorddotedu>, 2005 */
12
13/* include first to avoid 'malloc' clash with rtems_bsdnet_malloc() hack */
14
15#include <rtems.h>
16#include <rtems/rtems_bsdnet.h>
17#include <sys/mbuf.h>
18#include <sys/socket.h>
19#include <sys/sockio.h>
20#include <net/ethernet.h>
21#include <net/if.h>
22
23#ifndef __KERNEL__
24#define __KERNEL__
25#endif
26
27#include <rtems/rtems_mii_ioctl.h>
28
29#include <sys/errno.h>
30
31
32#define DEBUG
33
34
35#ifndef MII_1000TCR
36#define MII_1000TCR MII_100T2CR
37#endif
38
39#ifndef MII_1000TSR
40#define MII_1000TSR MII_100T2SR
41#endif
42
43int
44rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, int cmd,
45                 int *media)
46{
47  uint32_t bmcr, bmsr, aner, bmcr2 = 0, bmsr2 = 0, anar, lpar;
48  int phy = IFM_INST (*media);
49  unsigned tmp;
50  int subtype = 0, options = 0;
51
52  switch (cmd) {
53  default:
54    return EINVAL;
55
56#ifdef DEBUG
57  case 0:
58#endif
59  case SIOCGIFMEDIA:
60    if (info->mdio_r (phy, uarg, MII_BMCR, &bmcr))
61      return EINVAL;
62    if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
63      return EINVAL;
64    if (info->mdio_r (phy, uarg, MII_ANER, &aner))
65      return EINVAL;
66    if (info->has_gmii) {
67      if (info->mdio_r (phy, uarg, MII_1000TCR, &bmcr2))
68        return EINVAL;
69      if (info->mdio_r (phy, uarg, MII_1000TSR, &bmsr2))
70        return EINVAL;
71    }
72
73    /* link status */
74    if (BMSR_LINK & bmsr)
75      options |= IFM_LINK_OK;
76
77    /* do we have autonegotiation disabled ? */
78    if (!(BMCR_AUTOEN & bmcr)) {
79      options |= IFM_ANEG_DIS;
80
81      /* duplex is enforced */
82      options |= BMCR_FDX & bmcr ? IFM_FDX : IFM_HDX;
83
84      /* determine speed */
85      switch (BMCR_SPEED (bmcr)) {
86      case BMCR_S10:
87        subtype = IFM_10_T;
88        break;
89      case BMCR_S100:
90        subtype = IFM_100_TX;
91        break;
92      case BMCR_S1000:
93        subtype = IFM_1000_T;
94        break;
95      default:
96        return ENOTSUP;         /* ?? */
97      }
98    } else if (!(BMSR_LINK & bmsr) || !(BMSR_ACOMP & bmsr)) {
99      subtype = IFM_NONE;
100    } else {
101      /* everything ok on our side */
102
103          if ( ! (ANER_LPAN & aner) ) {
104                /* Link partner doesn't autonegotiate --> our settings are the
105                 * result of 'parallel detect' (in particular: duplex status is HALF
106                 * according to the standard!).
107                 * Let them know that something's fishy...
108                 */
109                options |= IFM_ANEG_DIS;
110          }
111
112      tmp = ((bmcr2 >> 2) & bmsr2) & (GTSR_LP_1000THDX | GTSR_LP_1000TFDX);
113      if (tmp) {
114        if (GTSR_LP_1000TFDX & tmp)
115          options |= IFM_FDX;
116        subtype = IFM_1000_T;
117      } else {
118        if (info->mdio_r (phy, uarg, MII_ANAR, &anar))
119          return EINVAL;
120        if (info->mdio_r (phy, uarg, MII_ANLPAR, &lpar))
121          return EINVAL;
122        if (ANLPAR_ACK & lpar) {
123          /* this is a negotiated link; otherwise we merely detect the partner's ability */
124        }
125        tmp = anar & lpar;
126        if (ANLPAR_TX_FD & tmp) {
127          options |= IFM_FDX;
128          subtype = IFM_100_TX;
129        } else if (ANLPAR_T4 & tmp) {
130          subtype = IFM_100_T4;
131        } else if (ANLPAR_TX & tmp) {
132          subtype = IFM_100_TX;
133        } else if (ANLPAR_10_FD & tmp) {
134          options |= IFM_FDX;
135          subtype = IFM_10_T;
136        } else {
137          subtype = IFM_10_T;
138        }
139      }
140    }
141
142    *media = IFM_MAKEWORD (IFM_ETHER, subtype, options, phy);
143
144    break;
145
146#ifdef DEBUG
147  case 1:
148#endif
149  case SIOCSIFMEDIA:
150    if (IFM_ETHER != IFM_TYPE (*media))
151      return EINVAL;
152
153    if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
154      return EINVAL;
155
156    tmp = (IFM_FDX & *media);
157
158    switch (IFM_SUBTYPE (*media)) {
159    default:
160      return ENOTSUP;
161
162    case IFM_AUTO:
163      bmcr = BMCR_AUTOEN | BMCR_STARTNEG;
164      tmp = 0;
165      break;
166
167    case IFM_1000_T:
168      if (!info->has_gmii)
169        return ENOTSUP;
170
171      if (info->mdio_r (phy, uarg, MII_EXTSR, &bmsr2))
172        return EINVAL;
173
174      if (!(bmsr2 & (tmp ? EXTSR_1000TFDX : EXTSR_1000THDX)))
175        return EOPNOTSUPP;
176      bmcr = BMCR_S1000;
177      break;
178
179    case IFM_100_TX:
180      if (!(bmsr & (tmp ? BMSR_100TXFDX : BMSR_100TXHDX)))
181        return EOPNOTSUPP;
182      bmcr = BMCR_S100;
183      break;
184
185    case IFM_10_T:
186      if (!(bmsr & (tmp ? BMSR_10TFDX : BMSR_10THDX)))
187        return EOPNOTSUPP;
188      bmcr = BMCR_S10;
189      break;
190    }
191
192    if (tmp)
193      bmcr |= BMCR_FDX;
194
195    if (info->mdio_w (phy, uarg, MII_BMCR, bmcr))
196      return EINVAL;
197
198    /* TODO: should we adapt advertised capabilites ? */
199
200    break;
201  }
202
203  return 0;
204}
Note: See TracBrowser for help on using the repository browser.