Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[efi] Work around bugs in Emulex NII driver
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
fbacchella authored and mcb30 committed Aug 17, 2015
1 parent b710379 commit c0b61ba
Showing 1 changed file with 71 additions and 15 deletions.
86 changes: 71 additions & 15 deletions src/drivers/net/efi/nii.c
Expand Up @@ -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;
Expand All @@ -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 );
Expand All @@ -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
*
Expand Down Expand Up @@ -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;

Expand All @@ -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 ) );
Expand Down Expand Up @@ -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 ) );
Expand All @@ -717,17 +756,21 @@ 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;
int rc;

/* 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 );
Expand All @@ -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;

Expand All @@ -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 ) );
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit c0b61ba

Please sign in to comment.