mirror of https://github.com/ipxe/ipxe.git
[efi] Work around bugs in Emulex NII driver
Modified-by: Michael Brown <mcb30@ipxe.org> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/54/head
parent
b71037989d
commit
c0b61bad99
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue