summaryrefslogtreecommitdiffstats
path: root/src/drivers/net/efi/nii.c
diff options
context:
space:
mode:
authorMichael Brown2023-01-11 01:18:18 +0100
committerMichael Brown2023-01-11 01:18:18 +0100
commitab19546386b13d6c54aea1647fac06960c544efc (patch)
tree527a784e9532c0f2d6e4690ab1d2c406e71f3200 /src/drivers/net/efi/nii.c
parent[cachedhcp] Retain cached DHCPACK after startup if not already consumed (diff)
downloadipxe-ab19546386b13d6c54aea1647fac06960c544efc.tar.gz
ipxe-ab19546386b13d6c54aea1647fac06960c544efc.tar.xz
ipxe-ab19546386b13d6c54aea1647fac06960c544efc.zip
[efi] Disable receive filters to work around buggy UNDI drivers
Some UNDI drivers (such as the AMI UsbNetworkPkg currently in the process of being upstreamed into EDK2) have a bug that will prevent any packets from being received unless at least one attempt has been made to disable some receive filters. Work around these buggy drivers by attempting to disable receive filters before enabling them. Ignore any errors, since we genuinely do not care whether or not the disabling succeeds. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/net/efi/nii.c')
-rw-r--r--src/drivers/net/efi/nii.c57
1 files changed, 47 insertions, 10 deletions
diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c
index 833462e7..5d9aea8d 100644
--- a/src/drivers/net/efi/nii.c
+++ b/src/drivers/net/efi/nii.c
@@ -921,18 +921,17 @@ static int nii_set_station_address ( struct nii_nic *nii,
* Set receive filters
*
* @v nii NII NIC
+ * @v flags Flags
* @ret rc Return status code
*/
-static int nii_set_rx_filters ( struct nii_nic *nii ) {
+static int nii_set_rx_filters ( struct nii_nic *nii, unsigned int flags ) {
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 );
+ flags |= 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 )
@@ -944,8 +943,12 @@ static int nii_set_rx_filters ( struct nii_nic *nii ) {
op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
if ( ( stat = nii_issue ( nii, op ) ) < 0 ) {
rc = -EIO_STAT ( stat );
- DBGC ( nii, "NII %s could not set receive filters %#04x: %s\n",
- nii->dev.name, flags, strerror ( rc ) );
+ DBGC ( nii, "NII %s could not %s%sable receive filters "
+ "%#04x: %s\n", nii->dev.name,
+ ( ( flags & PXE_OPFLAGS_RECEIVE_FILTER_ENABLE ) ?
+ "en" : "" ),
+ ( ( flags & PXE_OPFLAGS_RECEIVE_FILTER_DISABLE ) ?
+ "dis" : "" ), flags, strerror ( rc ) );
return rc;
}
@@ -953,6 +956,28 @@ static int nii_set_rx_filters ( struct nii_nic *nii ) {
}
/**
+ * Enable receive filters
+ *
+ * @v nii NII NIC
+ * @ret rc Return status code
+ */
+static int nii_enable_rx_filters ( struct nii_nic *nii ) {
+
+ return nii_set_rx_filters ( nii, PXE_OPFLAGS_RECEIVE_FILTER_ENABLE );
+}
+
+/**
+ * Disable receive filters
+ *
+ * @v nii NII NIC
+ * @ret rc Return status code
+ */
+static int nii_disable_rx_filters ( struct nii_nic *nii ) {
+
+ return nii_set_rx_filters ( nii, PXE_OPFLAGS_RECEIVE_FILTER_DISABLE );
+}
+
+/**
* Transmit packet
*
* @v netdev Network device
@@ -1175,13 +1200,25 @@ static int nii_open ( struct net_device *netdev ) {
/* Treat as non-fatal */
}
- /* Set receive filters */
- if ( ( rc = nii_set_rx_filters ( nii ) ) != 0 )
- goto err_set_rx_filters;
+ /* Disable receive filters
+ *
+ * We have no reason to disable receive filters here (or
+ * anywhere), but some NII drivers have a bug which prevents
+ * packets from being received unless we attempt to disable
+ * the receive filters.
+ *
+ * Ignore any failures, since we genuinely don't care if the
+ * NII driver cannot disable the filters.
+ */
+ nii_disable_rx_filters ( nii );
+
+ /* Enable receive filters */
+ if ( ( rc = nii_enable_rx_filters ( nii ) ) != 0 )
+ goto err_enable_rx_filters;
return 0;
- err_set_rx_filters:
+ err_enable_rx_filters:
nii_shutdown ( nii );
err_initialise:
return rc;