summaryrefslogtreecommitdiffstats
path: root/src/drivers/net
diff options
context:
space:
mode:
authorSimon Rettberg2023-04-04 15:12:41 +0200
committerSimon Rettberg2023-04-04 15:12:41 +0200
commit5ba496dce11d10198a0eae0c8440dccb256fbf32 (patch)
tree549903f1dab893870335a6e4767a4530444d2e83 /src/drivers/net
parent[vesafb] Map Unicode characters to CP437 if possible (diff)
parent[tls] Handle fragmented handshake records (diff)
downloadipxe-5ba496dce11d10198a0eae0c8440dccb256fbf32.tar.gz
ipxe-5ba496dce11d10198a0eae0c8440dccb256fbf32.tar.xz
ipxe-5ba496dce11d10198a0eae0c8440dccb256fbf32.zip
Merge branch 'master' into openslx
Diffstat (limited to 'src/drivers/net')
-rw-r--r--src/drivers/net/ecm.c5
-rw-r--r--src/drivers/net/efi/nii.c59
-rw-r--r--src/drivers/net/efi/snp.c66
-rw-r--r--src/drivers/net/efi/snponly.c2
-rw-r--r--src/drivers/net/ena.c93
-rw-r--r--src/drivers/net/ena.h46
-rw-r--r--src/drivers/net/intel.c20
-rw-r--r--src/drivers/net/intel.h10
-rw-r--r--src/drivers/net/intelx.c1
-rw-r--r--src/drivers/net/netfront.c49
-rw-r--r--src/drivers/net/netfront.h5
-rw-r--r--src/drivers/net/realtek.c4
-rw-r--r--src/drivers/net/realtek.h5
13 files changed, 316 insertions, 49 deletions
diff --git a/src/drivers/net/ecm.c b/src/drivers/net/ecm.c
index 68ac962ab..ab1f98370 100644
--- a/src/drivers/net/ecm.c
+++ b/src/drivers/net/ecm.c
@@ -121,10 +121,9 @@ int ecm_fetch_mac ( struct usb_function *func,
}
/* Apply system-specific MAC address as current link-layer
- * address, if present and not already used.
+ * address, if present.
*/
- if ( ( ( rc = acpi_mac ( amac ) ) == 0 ) &&
- ! find_netdev_by_ll_addr ( &ethernet_protocol, amac ) ) {
+ if ( ( rc = acpi_mac ( amac ) ) == 0 ) {
memcpy ( netdev->ll_addr, amac, ETH_ALEN );
DBGC ( usb, "USB %s using system-specific MAC %s\n",
func->name, eth_ntoa ( netdev->ll_addr ) );
diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c
index 833462e77..be5bce4b4 100644
--- a/src/drivers/net/efi/nii.c
+++ b/src/drivers/net/efi/nii.c
@@ -222,7 +222,7 @@ static int nii_pci_open ( struct nii_nic *nii ) {
/* Locate PCI I/O protocol */
if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid,
- &pci_device ) ) != 0 ) {
+ &pci_device, 0 ) ) != 0 ) {
DBGC ( nii, "NII %s could not locate PCI I/O protocol: %s\n",
nii->dev.name, strerror ( rc ) );
goto err_locate;
@@ -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;
diff --git a/src/drivers/net/efi/snp.c b/src/drivers/net/efi/snp.c
index fbd606902..1920cdbc5 100644
--- a/src/drivers/net/efi/snp.c
+++ b/src/drivers/net/efi/snp.c
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_snp.h>
+#include <ipxe/efi/efi_utils.h>
#include "snpnet.h"
#include "nii.h"
@@ -40,31 +41,46 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* Check to see if driver supports a device
*
* @v device EFI device handle
+ * @v protocol Protocol GUID
* @ret rc Return status code
*/
-static int snp_supported ( EFI_HANDLE device ) {
+static int snp_nii_supported ( EFI_HANDLE device, EFI_GUID *protocol ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE parent;
EFI_STATUS efirc;
+ int rc;
/* Check that this is not a device we are providing ourselves */
if ( find_snpdev ( device ) != NULL ) {
- DBGCP ( device, "SNP %s is provided by this binary\n",
+ DBGCP ( device, "HANDLE %s is provided by this binary\n",
efi_handle_name ( device ) );
return -ENOTTY;
}
- /* Test for presence of simple network protocol */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_simple_network_protocol_guid,
+ /* Test for presence of protocol */
+ if ( ( efirc = bs->OpenProtocol ( device, protocol,
NULL, efi_image_handle, device,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
- DBGCP ( device, "SNP %s is not an SNP device\n",
- efi_handle_name ( device ) );
+ DBGCP ( device, "HANDLE %s is not a %s device\n",
+ efi_handle_name ( device ),
+ efi_guid_ntoa ( protocol ) );
return -EEFI ( efirc );
}
- DBGC ( device, "SNP %s is an SNP device\n",
- efi_handle_name ( device ) );
+ /* Check that there are no instances of this protocol further
+ * up this device path.
+ */
+ if ( ( rc = efi_locate_device ( device, protocol,
+ &parent, 1 ) ) == 0 ) {
+ DBGC2 ( device, "HANDLE %s has %s-supporting parent ",
+ efi_handle_name ( device ),
+ efi_guid_ntoa ( protocol ) );
+ DBGC2 ( device, "%s\n", efi_handle_name ( parent ) );
+ return -ENOTTY;
+ }
+
+ DBGC ( device, "HANDLE %s is a %s device\n",
+ efi_handle_name ( device ), efi_guid_ntoa ( protocol ) );
return 0;
}
@@ -74,30 +90,20 @@ static int snp_supported ( EFI_HANDLE device ) {
* @v device EFI device handle
* @ret rc Return status code
*/
-static int nii_supported ( EFI_HANDLE device ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_STATUS efirc;
+static int snp_supported ( EFI_HANDLE device ) {
- /* Check that this is not a device we are providing ourselves */
- if ( find_snpdev ( device ) != NULL ) {
- DBGCP ( device, "NII %s is provided by this binary\n",
- efi_handle_name ( device ) );
- return -ENOTTY;
- }
+ return snp_nii_supported ( device, &efi_simple_network_protocol_guid );
+}
- /* Test for presence of NII protocol */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_nii31_protocol_guid,
- NULL, efi_image_handle, device,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
- DBGCP ( device, "NII %s is not an NII device\n",
- efi_handle_name ( device ) );
- return -EEFI ( efirc );
- }
- DBGC ( device, "NII %s is an NII device\n",
- efi_handle_name ( device ) );
+/**
+ * Check to see if driver supports a device
+ *
+ * @v device EFI device handle
+ * @ret rc Return status code
+ */
+static int nii_supported ( EFI_HANDLE device ) {
- return 0;
+ return snp_nii_supported ( device, &efi_nii31_protocol_guid );
}
/** EFI SNP driver */
diff --git a/src/drivers/net/efi/snponly.c b/src/drivers/net/efi/snponly.c
index cb7ea1bbc..674e0a050 100644
--- a/src/drivers/net/efi/snponly.c
+++ b/src/drivers/net/efi/snponly.c
@@ -80,7 +80,7 @@ static int chained_locate ( struct chained_protocol *chained ) {
/* Locate handle supporting this protocol */
if ( ( rc = efi_locate_device ( device, chained->protocol,
- &parent ) ) != 0 ) {
+ &parent, 0 ) ) != 0 ) {
DBGC ( device, "CHAINED %s does not support %s: %s\n",
efi_handle_name ( device ),
efi_guid_ntoa ( chained->protocol ), strerror ( rc ) );
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c
index 22e7e1e30..7ce5b9eb9 100644
--- a/src/drivers/net/ena.c
+++ b/src/drivers/net/ena.c
@@ -351,6 +351,90 @@ static int ena_admin ( struct ena_nic *ena, union ena_aq_req *req,
}
/**
+ * Set async event notification queue config
+ *
+ * @v ena ENA device
+ * @v enabled Bitmask of the groups to enable
+ * @ret rc Return status code
+ */
+static int ena_set_aenq_config ( struct ena_nic *ena, uint32_t enabled ) {
+ union ena_aq_req *req;
+ union ena_acq_rsp *rsp;
+ union ena_feature *feature;
+ int rc;
+
+ /* Construct request */
+ req = ena_admin_req ( ena );
+ req->header.opcode = ENA_SET_FEATURE;
+ req->set_feature.id = ENA_AENQ_CONFIG;
+ feature = &req->set_feature.feature;
+ feature->aenq.enabled = cpu_to_le32 ( enabled );
+
+ /* Issue request */
+ if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Create async event notification queue
+ *
+ * @v ena ENA device
+ * @ret rc Return status code
+ */
+static int ena_create_async ( struct ena_nic *ena ) {
+ size_t aenq_len = ( ENA_AENQ_COUNT * sizeof ( ena->aenq.evt[0] ) );
+ int rc;
+
+ /* Allocate async event notification queue */
+ ena->aenq.evt = malloc_phys ( aenq_len, aenq_len );
+ if ( ! ena->aenq.evt ) {
+ rc = -ENOMEM;
+ goto err_alloc_aenq;
+ }
+ memset ( ena->aenq.evt, 0, aenq_len );
+
+ /* Program queue address and capabilities */
+ ena_set_base ( ena, ENA_AENQ_BASE, ena->aenq.evt );
+ ena_set_caps ( ena, ENA_AENQ_CAPS, ENA_AENQ_COUNT,
+ sizeof ( ena->aenq.evt[0] ) );
+
+ DBGC ( ena, "ENA %p AENQ [%08lx,%08lx)\n",
+ ena, virt_to_phys ( ena->aenq.evt ),
+ ( virt_to_phys ( ena->aenq.evt ) + aenq_len ) );
+
+ /* Disable all events */
+ if ( ( rc = ena_set_aenq_config ( ena, 0 ) ) != 0 )
+ goto err_set_aenq_config;
+
+ return 0;
+
+ err_set_aenq_config:
+ ena_clear_caps ( ena, ENA_AENQ_CAPS );
+ free_phys ( ena->aenq.evt, aenq_len );
+ err_alloc_aenq:
+ return rc;
+}
+
+/**
+ * Destroy async event notification queue
+ *
+ * @v ena ENA device
+ */
+static void ena_destroy_async ( struct ena_nic *ena ) {
+ size_t aenq_len = ( ENA_AENQ_COUNT * sizeof ( ena->aenq.evt[0] ) );
+
+ /* Clear queue capabilities */
+ ena_clear_caps ( ena, ENA_AENQ_CAPS );
+ wmb();
+
+ /* Free queue */
+ free_phys ( ena->aenq.evt, aenq_len );
+ DBGC ( ena, "ENA %p AENQ destroyed\n", ena );
+}
+
+/**
* Create submission queue
*
* @v ena ENA device
@@ -1098,6 +1182,10 @@ static int ena_probe ( struct pci_device *pci ) {
if ( ( rc = ena_create_admin ( ena ) ) != 0 )
goto err_create_admin;
+ /* Create async event notification queue */
+ if ( ( rc = ena_create_async ( ena ) ) != 0 )
+ goto err_create_async;
+
/* Set host attributes */
if ( ( rc = ena_set_host_attributes ( ena ) ) != 0 )
goto err_set_host_attributes;
@@ -1121,6 +1209,8 @@ static int ena_probe ( struct pci_device *pci ) {
err_register_netdev:
err_get_device_attributes:
err_set_host_attributes:
+ ena_destroy_async ( ena );
+ err_create_async:
ena_destroy_admin ( ena );
err_create_admin:
ena_reset ( ena );
@@ -1148,6 +1238,9 @@ static void ena_remove ( struct pci_device *pci ) {
/* Unregister network device */
unregister_netdev ( netdev );
+ /* Destroy async event notification queue */
+ ena_destroy_async ( ena );
+
/* Destroy admin queues */
ena_destroy_admin ( ena );
diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h
index 4e1896e86..0f280c700 100644
--- a/src/drivers/net/ena.h
+++ b/src/drivers/net/ena.h
@@ -24,6 +24,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Number of admin completion queue entries */
#define ENA_ACQ_COUNT 2
+/** Number of async event notification queue entries */
+#define ENA_AENQ_COUNT 2
+
/** Number of transmit queue entries */
#define ENA_TX_COUNT 16
@@ -60,6 +63,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Maximum time to wait for admin requests */
#define ENA_ADMIN_MAX_WAIT_MS 5000
+/** Async event notification queue capabilities register */
+#define ENA_AENQ_CAPS 0x34
+
+/** Async event notification queue base address register */
+#define ENA_AENQ_BASE 0x38
+
/** Device control register */
#define ENA_CTRL 0x54
#define ENA_CTRL_RESET 0x00000001UL /**< Reset */
@@ -130,6 +139,17 @@ struct ena_device_attributes {
uint32_t mtu;
} __attribute__ (( packed ));
+/** Async event notification queue config */
+#define ENA_AENQ_CONFIG 26
+
+/** Async event notification queue config */
+struct ena_aenq_config {
+ /** Bitmask of supported AENQ groups (device -> host) */
+ uint32_t supported;
+ /** Bitmask of enabled AENQ groups (host -> device) */
+ uint32_t enabled;
+} __attribute__ (( packed ));
+
/** Host attributes */
#define ENA_HOST_ATTRIBUTES 28
@@ -208,6 +228,8 @@ struct ena_host_info {
union ena_feature {
/** Device attributes */
struct ena_device_attributes device;
+ /** Async event notification queue config */
+ struct ena_aenq_config aenq;
/** Host attributes */
struct ena_host_attributes host;
};
@@ -506,6 +528,28 @@ struct ena_acq {
unsigned int phase;
};
+/** Async event notification queue event */
+struct ena_aenq_event {
+ /** Type of event */
+ uint16_t group;
+ /** ID of event */
+ uint16_t syndrome;
+ /** Phase */
+ uint8_t flags;
+ /** Reserved */
+ uint8_t reserved[3];
+ /** Timestamp */
+ uint64_t timestamp;
+ /** Additional event data */
+ uint8_t data[48];
+} __attribute__ (( packed ));
+
+/** Async event notification queue */
+struct ena_aenq {
+ /** Events */
+ struct ena_aenq_event *evt;
+};
+
/** Transmit submission queue entry */
struct ena_tx_sqe {
/** Length */
@@ -702,6 +746,8 @@ struct ena_nic {
struct ena_aq aq;
/** Admin completion queue */
struct ena_acq acq;
+ /** Async event notification queue */
+ struct ena_aenq aenq;
/** Transmit queue */
struct ena_qp tx;
/** Receive queue */
diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c
index ea3ebf68d..46527bdbb 100644
--- a/src/drivers/net/intel.c
+++ b/src/drivers/net/intel.c
@@ -290,6 +290,18 @@ static int intel_reset ( struct intel_nic *intel ) {
pba, readl ( intel->regs + INTEL_PBA ) );
}
+ /* The Intel I210's packet buffer size registers reset only on
+ * power up. If an operating system changes these but then
+ * the computer recieves a reset signal without losing power,
+ * the registers will stay the same (but be incompatible with
+ * other register defaults), thus making the device unable to
+ * pass traffic.
+ */
+ if ( intel->flags & INTEL_PBSIZE_RST ) {
+ writel ( INTEL_RXPBS_I210, intel->regs + INTEL_RXPBS );
+ writel ( INTEL_TXPBS_I210, intel->regs + INTEL_TXPBS );
+ }
+
/* Always reset MAC. Required to reset the TX and RX rings. */
writel ( ( ctrl | INTEL_CTRL_RST ), intel->regs + INTEL_CTRL );
mdelay ( INTEL_RESET_DELAY_MS );
@@ -1139,7 +1151,7 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x1525, "82567v-4", "82567V-4", 0 ),
PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ),
PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ),
- PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ),
+ PCI_ROM ( 0x8086, 0x1533, "i210", "I210", INTEL_PBSIZE_RST ),
PCI_ROM ( 0x8086, 0x1539, "i211", "I211", 0 ),
PCI_ROM ( 0x8086, 0x153a, "i217lm", "I217-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ),
@@ -1147,7 +1159,7 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x155a, "i218lm", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_I219 ),
- PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", 0 ),
+ PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", INTEL_PBSIZE_RST ),
PCI_ROM ( 0x8086, 0x15a0, "i218lm-2", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", INTEL_NO_PHY_RST ),
@@ -1173,6 +1185,10 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x15fa, "i219v-14", "I219-V (14)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15fb, "i219lm-13", "I219-LM (13)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15fc, "i219v-13", "I219-V (13)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x1a1c, "i219lm-17", "I219-LM (17)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x1a1d, "i219v-17", "I219-V (17)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x1a1e, "i219lm-16", "I219-LM (16)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x1a1f, "i219v-16", "I219-V (16)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h
index 4f51a80f6..29cf3a7d8 100644
--- a/src/drivers/net/intel.h
+++ b/src/drivers/net/intel.h
@@ -138,6 +138,10 @@ struct intel_descriptor {
/** Packet Buffer Size */
#define INTEL_PBS 0x01008UL
+/** Receive packet buffer size */
+#define INTEL_RXPBS 0x02404UL
+#define INTEL_RXPBS_I210 0x000000a2UL /**< I210 power-up default */
+
/** Receive Descriptor register block */
#define INTEL_RD 0x02800UL
@@ -154,6 +158,10 @@ struct intel_descriptor {
/** Receive buffer length */
#define INTEL_RX_MAX_LEN 2048
+/** Transmit packet buffer size */
+#define INTEL_TXPBS 0x03404UL
+#define INTEL_TXPBS_I210 0x04000014UL /**< I210 power-up default */
+
/** Transmit Descriptor register block */
#define INTEL_TD 0x03800UL
@@ -319,6 +327,8 @@ enum intel_flags {
INTEL_NO_ASDE = 0x0008,
/** Reset may cause a complete device hang */
INTEL_RST_HANG = 0x0010,
+ /** PBSIZE registers must be explicitly reset */
+ INTEL_PBSIZE_RST = 0x0020,
};
/** The i219 has a seriously broken reset mechanism */
diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c
index f4dad8859..343d01374 100644
--- a/src/drivers/net/intelx.c
+++ b/src/drivers/net/intelx.c
@@ -473,6 +473,7 @@ static struct pci_device_id intelx_nics[] = {
PCI_ROM ( 0x8086, 0x10f9, "82599-cx4", "82599 (CX4)", 0 ),
PCI_ROM ( 0x8086, 0x10fb, "82599-sfp", "82599 (SFI/SFP+)", 0 ),
PCI_ROM ( 0x8086, 0x10fc, "82599-xaui", "82599 (XAUI/BX4)", 0 ),
+ PCI_ROM ( 0x8086, 0x151c, "82599-tn", "82599 (TN)", 0 ),
PCI_ROM ( 0x8086, 0x1528, "x540t", "X540-AT2/X540-BT2", 0 ),
PCI_ROM ( 0x8086, 0x154d, "82599-sfp-sf2", "82599 (SFI/SFP+)", 0 ),
PCI_ROM ( 0x8086, 0x1557, "82599en-sfp", "82599 (Single Port SFI Only)", 0 ),
diff --git a/src/drivers/net/netfront.c b/src/drivers/net/netfront.c
index 1203e585c..90930a5a3 100644
--- a/src/drivers/net/netfront.c
+++ b/src/drivers/net/netfront.c
@@ -59,6 +59,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
EUNIQ ( EINFO_EIO, ( -(status) & 0x1f ), \
EIO_NETIF_RSP_ERROR, EIO_NETIF_RSP_DROPPED )
+/** List of netfront devices */
+static LIST_HEAD ( netfront_devices );
+
/******************************************************************************
*
* XenStore interface
@@ -952,6 +955,7 @@ static int netfront_probe ( struct xen_device *xendev ) {
netdev->dev = &xendev->dev;
netfront = netdev->priv;
netfront->xendev = xendev;
+ netfront->netdev = netdev;
INIT_LIST_HEAD ( &netfront->rx_partial );
DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n",
xendev->key, xendev->backend, xendev->backend_id );
@@ -991,9 +995,13 @@ static int netfront_probe ( struct xen_device *xendev ) {
/* Set initial link state */
netdev_link_down ( netdev );
+ /* Add to list of netfront devices */
+ list_add_tail ( &netfront->list, &netfront_devices );
+
xen_set_drvdata ( xendev, netdev );
return 0;
+ list_del ( &netfront->list );
unregister_netdev ( netdev );
err_register_netdev:
err_read_mac:
@@ -1015,6 +1023,9 @@ static void netfront_remove ( struct xen_device *xendev ) {
struct netfront_nic *netfront = netdev->priv;
struct xen_hypervisor *xen = xendev->xen;
+ /* Remove from list of netfront devices */
+ list_del ( &netfront->list );
+
/* Unregister network device */
unregister_netdev ( netdev );
@@ -1033,3 +1044,41 @@ struct xen_driver netfront_driver __xen_driver = {
.probe = netfront_probe,
.remove = netfront_remove,
};
+
+/******************************************************************************
+ *
+ * Emulated PCI device inhibitor
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Inhibit emulated PCI devices
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int netfront_net_probe ( struct net_device *netdev ) {
+ struct netfront_nic *netfront;
+
+ /* Inhibit emulated PCI devices matching an existing netfront device */
+ list_for_each_entry ( netfront, &netfront_devices, list ) {
+ if ( ( netdev->dev != netfront->netdev->dev ) &&
+ ( netdev->ll_protocol->ll_addr_len == ETH_ALEN ) &&
+ ( memcmp ( netdev->hw_addr, netfront->netdev->hw_addr,
+ ETH_ALEN ) == 0 ) ) {
+ DBGC ( netfront, "NETFRONT %s inhibiting emulated %s "
+ "%s\n", netfront->xendev->key,
+ netdev->dev->driver_name, netdev->dev->name );
+ return -EEXIST;
+ }
+ }
+
+ return 0;
+}
+
+/** Emulated PCI device inhibitor driver */
+struct net_driver netfront_net_driver __net_driver = {
+ .name = "netfront",
+ .probe = netfront_net_probe,
+};
diff --git a/src/drivers/net/netfront.h b/src/drivers/net/netfront.h
index dca3ff1c5..de16d5291 100644
--- a/src/drivers/net/netfront.h
+++ b/src/drivers/net/netfront.h
@@ -159,6 +159,11 @@ struct netfront_nic {
/** Grant references */
grant_ref_t refs[NETFRONT_REF_COUNT];
+ /** Network device */
+ struct net_device *netdev;
+ /** List of netfront NICs */
+ struct list_head list;
+
/** Transmit ring */
struct netfront_ring tx;
/** Transmit front ring */
diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c
index a43efb68b..80442ab83 100644
--- a/src/drivers/net/realtek.c
+++ b/src/drivers/net/realtek.c
@@ -1067,11 +1067,15 @@ static void realtek_detect ( struct realtek_nic *rtl ) {
* Note that enabling DAC seems to cause bizarre behaviour
* (lockups, garbage data on the wire) on some systems, even
* if only 32-bit addresses are used.
+ *
+ * Disable VLAN offload, since some cards seem to have it
+ * enabled by default.
*/
cpcr = readw ( rtl->regs + RTL_CPCR );
cpcr |= ( RTL_CPCR_MULRW | RTL_CPCR_CPRX | RTL_CPCR_CPTX );
if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
cpcr |= RTL_CPCR_DAC;
+ cpcr &= ~RTL_CPCR_VLAN;
writew ( cpcr, rtl->regs + RTL_CPCR );
check_cpcr = readw ( rtl->regs + RTL_CPCR );
diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h
index d4642fd76..d50e349b0 100644
--- a/src/drivers/net/realtek.h
+++ b/src/drivers/net/realtek.h
@@ -228,8 +228,9 @@ enum realtek_legacy_status {
/** C+ Command Register (word) */
#define RTL_CPCR 0xe0
-#define RTL_CPCR_DAC 0x0010 /**< PCI Dual Address Cycle Enable */
-#define RTL_CPCR_MULRW 0x0008 /**< PCI Multiple Read/Write Enable */
+#define RTL_CPCR_VLAN 0x0040 /**< VLAN tag stripping enable */
+#define RTL_CPCR_DAC 0x0010 /**< PCI Dual Address Cycle enable */
+#define RTL_CPCR_MULRW 0x0008 /**< PCI Multiple Read/Write enable */
#define RTL_CPCR_CPRX 0x0002 /**< C+ receive enable */
#define RTL_CPCR_CPTX 0x0001 /**< C+ transmit enable */