iPXE
mii.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <errno.h>
00029 #include <ipxe/mii.h>
00030 
00031 /** @file
00032  *
00033  * Media Independent Interface
00034  *
00035  */
00036 
00037 /**
00038  * Restart autonegotiation
00039  *
00040  * @v mii               MII device
00041  * @ret rc              Return status code
00042  */
00043 int mii_restart ( struct mii_device *mii ) {
00044         int bmcr;
00045         int rc;
00046 
00047         /* Read BMCR */
00048         bmcr = mii_read ( mii, MII_BMCR );
00049         if ( bmcr < 0 ) {
00050                 rc = bmcr;
00051                 DBGC ( mii, "MII %p could not read BMCR: %s\n",
00052                        mii, strerror ( rc ) );
00053                 return rc;
00054         }
00055 
00056         /* Enable and restart autonegotiation */
00057         bmcr |= ( BMCR_ANENABLE | BMCR_ANRESTART );
00058         if ( ( rc = mii_write ( mii, MII_BMCR, bmcr ) ) != 0 ) {
00059                 DBGC ( mii, "MII %p could not write BMCR: %s\n",
00060                        mii, strerror ( rc ) );
00061                 return rc;
00062         }
00063 
00064         DBGC ( mii, "MII %p restarted autonegotiation\n", mii );
00065         return 0;
00066 }
00067 
00068 /**
00069  * Reset MII device
00070  *
00071  * @v mii               MII device
00072  * @ret rc              Return status code
00073  */
00074 int mii_reset ( struct mii_device *mii ) {
00075         unsigned int i;
00076         int bmcr;
00077         int rc;
00078 
00079         /* Power-up, enable autonegotiation and initiate reset */
00080         if ( ( rc = mii_write ( mii, MII_BMCR,
00081                                 ( BMCR_RESET | BMCR_ANENABLE ) ) ) != 0 ) {
00082                 DBGC ( mii, "MII %p could not write BMCR: %s\n",
00083                        mii, strerror ( rc ) );
00084                 return rc;
00085         }
00086 
00087         /* Wait for reset to complete */
00088         for ( i = 0 ; i < MII_RESET_MAX_WAIT_MS ; i++ ) {
00089 
00090                 /* Check if reset has completed */
00091                 bmcr = mii_read ( mii, MII_BMCR );
00092                 if ( bmcr < 0 ) {
00093                         rc = bmcr;
00094                         DBGC ( mii, "MII %p could not read BMCR: %s\n",
00095                                mii, strerror ( rc ) );
00096                         return rc;
00097                 }
00098 
00099                 /* If reset is not complete, delay 1ms and retry */
00100                 if ( bmcr & BMCR_RESET ) {
00101                         mdelay ( 1 );
00102                         continue;
00103                 }
00104 
00105                 /* Force autonegotation on again, in case it was
00106                  * cleared by the reset.
00107                  */
00108                 if ( ( rc = mii_restart ( mii ) ) != 0 )
00109                         return rc;
00110 
00111                 DBGC ( mii, "MII %p reset after %dms\n", mii, i );
00112                 return 0;
00113         }
00114 
00115         DBGC ( mii, "MII %p timed out waiting for reset\n", mii );
00116         return -ETIMEDOUT;
00117 }
00118 
00119 /**
00120  * Update link status via MII
00121  *
00122  * @v mii               MII device
00123  * @v netdev            Network device
00124  * @ret rc              Return status code
00125  */
00126 int mii_check_link ( struct mii_device *mii, struct net_device *netdev ) {
00127         int bmsr;
00128         int link;
00129         int rc;
00130 
00131         /* Read BMSR */
00132         bmsr = mii_read ( mii, MII_BMSR );
00133         if ( bmsr < 0 ) {
00134                 rc = bmsr;
00135                 return rc;
00136         }
00137 
00138         /* Report link status */
00139         link = ( bmsr & BMSR_LSTATUS );
00140         DBGC ( mii, "MII %p link %s (BMSR %#04x)\n",
00141                mii, ( link ? "up" : "down" ), bmsr );
00142         if ( link ) {
00143                 netdev_link_up ( netdev );
00144         } else {
00145                 netdev_link_down ( netdev );
00146         }
00147 
00148         return 0;
00149 }
00150 
00151 /**
00152  * Find PHY address
00153  *
00154  * @v mii               MII device
00155  * @ret rc              Return status code
00156  */
00157 int mii_find ( struct mii_device *mii ) {
00158         unsigned int address;
00159         int id;
00160 
00161         /* Try all possible PHY addresses */
00162         for ( address = 0 ; address <= MII_MAX_PHY_ADDRESS ; address++ ) {
00163                 mii->address = address;
00164                 id = mii_read ( mii, MII_PHYSID1 );
00165                 if ( ( id > 0x0000 ) && ( id < 0xffff ) ) {
00166                         DBGC ( mii, "MII %p found PHY at address %d\n",
00167                                mii, address );
00168                         return 0;
00169                 }
00170         }
00171 
00172         DBGC ( mii, "MII %p failed to find an address\n", mii );
00173         return -ENOENT;
00174 }