david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[efi] Work around bugs in Emulex NII driver

Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Fabrice Bacchella 2015-08-13 12:44:21 +02:00 committed by Michael Brown
parent b71037989d
commit c0b61bad99
1 changed files with 71 additions and 15 deletions

View File

@ -575,9 +575,10 @@ static int nii_get_init_info ( struct nii_nic *nii,
* Initialise UNDI
*
* @v nii NII NIC
* @v flags Flags
* @ret rc Return status code
*/
static int nii_initialise ( struct nii_nic *nii ) {
static int nii_initialise_flags ( struct nii_nic *nii, unsigned int flags ) {
PXE_CPB_INITIALIZE cpb;
PXE_DB_INITIALIZE db;
unsigned int op;
@ -600,8 +601,7 @@ static int nii_initialise ( struct nii_nic *nii ) {
memset ( &db, 0, sizeof ( db ) );
/* Issue command */
op = NII_OP ( PXE_OPCODE_INITIALIZE,
PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE );
op = NII_OP ( PXE_OPCODE_INITIALIZE, flags );
if ( ( stat = nii_issue_cpb_db ( nii, op, &cpb, sizeof ( cpb ),
&db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
@ -618,6 +618,36 @@ static int nii_initialise ( struct nii_nic *nii ) {
return rc;
}
/**
* Initialise UNDI
*
* @v nii NII NIC
* @ret rc Return status code
*/
static int nii_initialise ( struct nii_nic *nii ) {
unsigned int flags;
/* Initialise UNDI */
flags = PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE;
return nii_initialise_flags ( nii, flags );
}
/**
* Initialise UNDI and detect cable
*
* @v nii NII NIC
* @ret rc Return status code
*/
static int nii_initialise_and_detect ( struct nii_nic *nii ) {
unsigned int flags;
/* Initialise UNDI and detect cable. This is required to work
* around bugs in some Emulex NII drivers.
*/
flags = PXE_OPFLAGS_INITIALIZE_DETECT_CABLE;
return nii_initialise_flags ( nii, flags );
}
/**
* Shut down UNDI
*
@ -650,6 +680,7 @@ static void nii_shutdown ( struct nii_nic *nii ) {
static int nii_get_station_address ( struct nii_nic *nii,
struct net_device *netdev ) {
PXE_DB_STATION_ADDRESS db;
unsigned int op;
int stat;
int rc;
@ -658,8 +689,9 @@ static int nii_get_station_address ( struct nii_nic *nii,
goto err_initialise;
/* Issue command */
if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_STATION_ADDRESS, &db,
sizeof ( db ) ) ) < 0 ) {
op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
PXE_OPFLAGS_STATION_ADDRESS_READ );
if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not get station address: %s\n",
nii->dev.name, strerror ( rc ) );
@ -689,18 +721,25 @@ static int nii_get_station_address ( struct nii_nic *nii,
*/
static int nii_set_station_address ( struct nii_nic *nii,
struct net_device *netdev ) {
uint32_t implementation = nii->undi->Implementation;
PXE_CPB_STATION_ADDRESS cpb;
unsigned int op;
int stat;
int rc;
/* Fail if setting station address is unsupported */
if ( ! ( implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE ) )
return -ENOTSUP;
/* Construct parameter block */
memset ( &cpb, 0, sizeof ( cpb ) );
memcpy ( cpb.StationAddr, netdev->ll_addr,
netdev->ll_protocol->ll_addr_len );
/* Issue command */
if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_STATION_ADDRESS,
&cpb, sizeof ( cpb ) ) ) < 0 ) {
op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
PXE_OPFLAGS_STATION_ADDRESS_WRITE );
if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not set station address: %s\n",
nii->dev.name, strerror ( rc ) );
@ -717,6 +756,7 @@ static int nii_set_station_address ( struct nii_nic *nii,
* @ret rc Return status code
*/
static int nii_set_rx_filters ( struct nii_nic *nii ) {
uint32_t implementation = nii->undi->Implementation;
unsigned int flags;
unsigned int op;
int stat;
@ -724,10 +764,13 @@ static int nii_set_rx_filters ( struct nii_nic *nii ) {
/* Construct receive filter set */
flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
PXE_OPFLAGS_RECEIVE_FILTER_UNICAST |
PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST |
PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST );
PXE_OPFLAGS_RECEIVE_FILTER_UNICAST );
if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED )
flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED )
flags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED )
flags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
/* Issue command */
op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
@ -752,6 +795,7 @@ static int nii_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct nii_nic *nii = netdev->priv;
PXE_CPB_TRANSMIT cpb;
unsigned int op;
int stat;
int rc;
@ -768,8 +812,10 @@ static int nii_transmit ( struct net_device *netdev,
cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len;
/* Transmit packet */
if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_TRANSMIT, &cpb,
sizeof ( cpb ) ) ) < 0 ) {
op = NII_OP ( PXE_OPCODE_TRANSMIT,
( PXE_OPFLAGS_TRANSMIT_WHOLE |
PXE_OPFLAGS_TRANSMIT_DONT_BLOCK ) );
if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not transmit: %s\n",
nii->dev.name, strerror ( rc ) );
@ -924,8 +970,18 @@ static int nii_open ( struct net_device *netdev ) {
struct nii_nic *nii = netdev->priv;
int rc;
/* Initialise NIC */
if ( ( rc = nii_initialise ( nii ) ) != 0 )
/* Initialise NIC
*
* Some Emulex NII drivers have a bug which prevents packets
* from being sent or received unless we specifically ask it
* to detect cable presence during initialisation. Work
* around these buggy drivers by requesting cable detection at
* this point, even though we don't care about link state here
* (and would prefer to have the NIC initialise even if no
* cable is present, to match the behaviour of all other iPXE
* drivers).
*/
if ( ( rc = nii_initialise_and_detect ( nii ) ) != 0 )
goto err_initialise;
/* Attempt to set station address */