Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[mii] Add generic MII reset function
iPXE provides no support for manually configuring the link speed. Provide a generic routine which should be able to reset any MII/GMII PHY and enable autonegotiation. Prototyped-by: Thomas Miletich <thomas.miletich@gmail.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
- Loading branch information
Showing
3 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License as | ||
* published by the Free Software Foundation; either version 2 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
* 02110-1301, USA. | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
#include <string.h> | ||
#include <unistd.h> | ||
#include <errno.h> | ||
#include <ipxe/mii.h> | ||
|
||
/** @file | ||
* | ||
* Media Independent Interface | ||
* | ||
*/ | ||
|
||
/** | ||
* Reset MII interface | ||
* | ||
* @v mii MII interface | ||
* @ret rc Return status code | ||
*/ | ||
int mii_reset ( struct mii_interface *mii ) { | ||
unsigned int i; | ||
int bmcr; | ||
int rc; | ||
|
||
/* Power-up, enable autonegotiation and initiate reset */ | ||
if ( ( rc = mii_write ( mii, MII_BMCR, | ||
( BMCR_RESET | BMCR_ANENABLE ) ) ) != 0 ) { | ||
DBGC ( mii, "MII %p could not write BMCR: %s\n", | ||
mii, strerror ( rc ) ); | ||
return rc; | ||
} | ||
|
||
/* Wait for reset to complete */ | ||
for ( i = 0 ; i < MII_RESET_MAX_WAIT_MS ; i++ ) { | ||
|
||
/* Check if reset has completed */ | ||
bmcr = mii_read ( mii, MII_BMCR ); | ||
if ( bmcr < 0 ) { | ||
rc = bmcr; | ||
DBGC ( mii, "MII %p could not read BMCR: %s\n", | ||
mii, strerror ( rc ) ); | ||
return rc; | ||
} | ||
|
||
/* If reset is not complete, delay 1ms and retry */ | ||
if ( bmcr & BMCR_RESET ) { | ||
mdelay ( 1 ); | ||
continue; | ||
} | ||
|
||
/* Force autonegotation on again, in case it was | ||
* cleared by the reset. | ||
*/ | ||
if ( ( rc = mii_write ( mii, MII_BMCR, BMCR_ANENABLE ) ) != 0 ){ | ||
DBGC ( mii, "MII %p could not write BMCR: %s\n", | ||
mii, strerror ( rc ) ); | ||
return rc; | ||
} | ||
|
||
DBGC ( mii, "MII %p reset after %dms\n", mii, i ); | ||
return 0; | ||
} | ||
|
||
DBGC ( mii, "MII %p timed out waiting for reset\n", mii ); | ||
return -ETIMEDOUT; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
#ifndef _IPXE_MII_H | ||
#define _IPXE_MII_H | ||
|
||
/** @file | ||
* | ||
* Media Independent Interface | ||
* | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
#include <mii.h> | ||
#include <ipxe/netdevice.h> | ||
|
||
struct mii_interface; | ||
|
||
/** MII interface operations */ | ||
struct mii_operations { | ||
/** | ||
* Read from MII register | ||
* | ||
* @v mii MII interface | ||
* @v reg Register address | ||
* @ret data Data read, or negative error | ||
*/ | ||
int ( * read ) ( struct mii_interface *mii, unsigned int reg ); | ||
/** | ||
* Write to MII register | ||
* | ||
* @v mii MII interface | ||
* @v reg Register address | ||
* @v data Data to write | ||
* @ret rc Return status code | ||
*/ | ||
int ( * write ) ( struct mii_interface *mii, unsigned int reg, | ||
unsigned int data ); | ||
}; | ||
|
||
/** An MII interface */ | ||
struct mii_interface { | ||
/** Interface operations */ | ||
struct mii_operations *op; | ||
}; | ||
|
||
/** | ||
* Initialise MII interface | ||
* | ||
* @v mii MII interface | ||
* @v op MII interface operations | ||
*/ | ||
static inline __attribute__ (( always_inline )) void | ||
mii_init ( struct mii_interface *mii, struct mii_operations *op ) { | ||
mii->op = op; | ||
} | ||
|
||
/** | ||
* Read from MII register | ||
* | ||
* @v mii MII interface | ||
* @v reg Register address | ||
* @ret data Data read, or negative error | ||
*/ | ||
static inline __attribute__ (( always_inline )) int | ||
mii_read ( struct mii_interface *mii, unsigned int reg ) { | ||
return mii->op->read ( mii, reg ); | ||
} | ||
|
||
/** | ||
* Write to MII register | ||
* | ||
* @v mii MII interface | ||
* @v reg Register address | ||
* @v data Data to write | ||
* @ret rc Return status code | ||
*/ | ||
static inline __attribute__ (( always_inline )) int | ||
mii_write ( struct mii_interface *mii, unsigned int reg, unsigned int data ) { | ||
return mii->op->write ( mii, reg, data ); | ||
} | ||
|
||
/** Maximum time to wait for a reset, in milliseconds */ | ||
#define MII_RESET_MAX_WAIT_MS 500 | ||
|
||
extern int mii_reset ( struct mii_interface *mii ); | ||
|
||
#endif /* _IPXE_MII_H */ |