diff options
| author | Simon Rettberg | 2023-04-04 15:12:41 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2023-04-04 15:12:41 +0200 |
| commit | 5ba496dce11d10198a0eae0c8440dccb256fbf32 (patch) | |
| tree | 549903f1dab893870335a6e4767a4530444d2e83 /src/drivers | |
| parent | [vesafb] Map Unicode characters to CP437 if possible (diff) | |
| parent | [tls] Handle fragmented handshake records (diff) | |
| download | ipxe-5ba496dce11d10198a0eae0c8440dccb256fbf32.tar.gz ipxe-5ba496dce11d10198a0eae0c8440dccb256fbf32.tar.xz ipxe-5ba496dce11d10198a0eae0c8440dccb256fbf32.zip | |
Merge branch 'master' into openslx
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/block/scsi.c | 4 | ||||
| -rw-r--r-- | src/drivers/bus/eisa.c | 8 | ||||
| -rw-r--r-- | src/drivers/bus/pci.c | 1 | ||||
| -rw-r--r-- | src/drivers/bus/pcibackup.c | 10 | ||||
| -rw-r--r-- | src/drivers/bus/pciextra.c | 9 | ||||
| -rw-r--r-- | src/drivers/infiniband/arbel.c | 4 | ||||
| -rwxr-xr-x | src/drivers/infiniband/golan.c | 1 | ||||
| -rw-r--r-- | src/drivers/infiniband/hermon.c | 5 | ||||
| -rw-r--r-- | src/drivers/infiniband/qib7322.c | 4 | ||||
| -rw-r--r-- | src/drivers/net/ecm.c | 5 | ||||
| -rw-r--r-- | src/drivers/net/efi/nii.c | 59 | ||||
| -rw-r--r-- | src/drivers/net/efi/snp.c | 66 | ||||
| -rw-r--r-- | src/drivers/net/efi/snponly.c | 2 | ||||
| -rw-r--r-- | src/drivers/net/ena.c | 93 | ||||
| -rw-r--r-- | src/drivers/net/ena.h | 46 | ||||
| -rw-r--r-- | src/drivers/net/intel.c | 20 | ||||
| -rw-r--r-- | src/drivers/net/intel.h | 10 | ||||
| -rw-r--r-- | src/drivers/net/intelx.c | 1 | ||||
| -rw-r--r-- | src/drivers/net/netfront.c | 49 | ||||
| -rw-r--r-- | src/drivers/net/netfront.h | 5 | ||||
| -rw-r--r-- | src/drivers/net/realtek.c | 4 | ||||
| -rw-r--r-- | src/drivers/net/realtek.h | 5 |
22 files changed, 350 insertions, 61 deletions
diff --git a/src/drivers/block/scsi.c b/src/drivers/block/scsi.c index f765c9762..ff415f5c6 100644 --- a/src/drivers/block/scsi.c +++ b/src/drivers/block/scsi.c @@ -609,6 +609,7 @@ static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd, */ static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd, int rc ) { + struct scsi_device *scsidev = scsicmd->scsidev; struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd ); struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16; struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10; @@ -645,6 +646,9 @@ static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd, } capacity.max_count = -1U; + /* Allow transport layer to update capacity */ + block_capacity ( &scsidev->scsi, &capacity ); + /* Return capacity to caller */ block_capacity ( &scsicmd->block, &capacity ); diff --git a/src/drivers/bus/eisa.c b/src/drivers/bus/eisa.c index a4efe2621..68837eb4d 100644 --- a/src/drivers/bus/eisa.c +++ b/src/drivers/bus/eisa.c @@ -98,8 +98,16 @@ static void eisa_remove ( struct eisa_device *eisa ) { static int eisabus_probe ( struct root_device *rootdev ) { struct eisa_device *eisa = NULL; unsigned int slot; + uint8_t system; int rc; + /* Check for EISA system board */ + system = inb ( EISA_VENDOR_ID ); + if ( system & 0x80 ) { + DBG ( "No EISA system board (read %02x)\n", system ); + return -ENODEV; + } + for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) { /* Allocate struct eisa_device */ if ( ! eisa ) diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 7953aaedd..92b389641 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -205,6 +205,7 @@ int pci_read_config ( struct pci_device *pci ) { pci_read_config_dword ( pci, PCI_REVISION, &tmp ); pci->class = ( tmp >> 8 ); pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq ); + pci_read_config_byte ( pci, PCI_HEADER_TYPE, &pci->hdrtype ); pci_read_bases ( pci ); /* Initialise generic device component */ diff --git a/src/drivers/bus/pcibackup.c b/src/drivers/bus/pcibackup.c index fecad8192..4cf126f83 100644 --- a/src/drivers/bus/pcibackup.c +++ b/src/drivers/bus/pcibackup.c @@ -61,14 +61,15 @@ pci_backup_excluded ( struct pci_device *pci, unsigned int offset, * * @v pci PCI device * @v backup PCI configuration space backup + * @v limit Maximum offset in PCI configuration space * @v exclude PCI configuration space backup exclusion list, or NULL */ void pci_backup ( struct pci_device *pci, struct pci_config_backup *backup, - const uint8_t *exclude ) { + unsigned int limit, const uint8_t *exclude ) { unsigned int offset; uint32_t *dword; - for ( offset = 0, dword = backup->dwords ; offset < 0x100 ; + for ( offset = 0, dword = backup->dwords ; offset < limit ; offset += sizeof ( *dword ) , dword++ ) { if ( ! pci_backup_excluded ( pci, offset, exclude ) ) pci_read_config_dword ( pci, offset, dword ); @@ -80,14 +81,15 @@ void pci_backup ( struct pci_device *pci, struct pci_config_backup *backup, * * @v pci PCI device * @v backup PCI configuration space backup + * @v limit Maximum offset in PCI configuration space * @v exclude PCI configuration space backup exclusion list, or NULL */ void pci_restore ( struct pci_device *pci, struct pci_config_backup *backup, - const uint8_t *exclude ) { + unsigned int limit, const uint8_t *exclude ) { unsigned int offset; uint32_t *dword; - for ( offset = 0, dword = backup->dwords ; offset < 0x100 ; + for ( offset = 0, dword = backup->dwords ; offset < limit ; offset += sizeof ( *dword ) , dword++ ) { if ( ! pci_backup_excluded ( pci, offset, exclude ) ) pci_write_config_dword ( pci, offset, *dword ); diff --git a/src/drivers/bus/pciextra.c b/src/drivers/bus/pciextra.c index 23617bc9a..1eeb9b2a0 100644 --- a/src/drivers/bus/pciextra.c +++ b/src/drivers/bus/pciextra.c @@ -3,6 +3,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <ipxe/timer.h> #include <ipxe/pci.h> +#include <ipxe/pcibackup.h> static int pci_find_capability_common ( struct pci_device *pci, uint8_t pos, int cap ) { @@ -121,8 +122,12 @@ unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) { * @v exp PCI Express Capability address */ void pci_reset ( struct pci_device *pci, unsigned int exp ) { + struct pci_config_backup backup; uint16_t control; + /* Back up configuration space */ + pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_STANDARD, NULL ); + /* Perform a PCIe function-level reset */ pci_read_config_word ( pci, ( exp + PCI_EXP_DEVCTL ), &control ); control |= PCI_EXP_DEVCTL_FLR; @@ -131,6 +136,6 @@ void pci_reset ( struct pci_device *pci, unsigned int exp ) { /* Allow time for reset to complete */ mdelay ( PCI_EXP_FLR_DELAY_MS ); - /* Re-enable device */ - adjust_pci_device ( pci ); + /* Restore configuration */ + pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_STANDARD, NULL ); } diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index fbef3f8a6..293c1b647 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -2561,7 +2561,7 @@ static void arbel_reset ( struct arbel *arbel ) { unsigned int i; /* Perform device reset and preserve PCI configuration */ - pci_backup ( pci, &backup, backup_exclude ); + pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_ALL, backup_exclude ); writel ( ARBEL_RESET_MAGIC, ( arbel->config + ARBEL_RESET_OFFSET ) ); for ( i = 0 ; i < ARBEL_RESET_WAIT_TIME_MS ; i++ ) { @@ -2570,7 +2570,7 @@ static void arbel_reset ( struct arbel *arbel ) { if ( vendor != 0xffff ) break; } - pci_restore ( pci, &backup, backup_exclude ); + pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_ALL, backup_exclude ); } /** diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index 2f1ab2357..ce02a867f 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -2647,6 +2647,7 @@ static struct pci_device_id golan_nics[] = { PCI_ROM ( 0x15b3, 0x1021, "ConnectX-7", "ConnectX-7 HCA driver, DevID 4129", 0 ), PCI_ROM ( 0x15b3, 0xa2d2, "BlueField", "BlueField integrated ConnectX-5 network controller HCA driver, DevID 41682", 0 ), PCI_ROM ( 0x15b3, 0xa2d6, "BlueField-2", "BlueField-2 network controller HCA driver, DevID 41686", 0 ), + PCI_ROM ( 0x15b3, 0xa2dc, "BlueField-3", "BlueField-3 network controller HCA driver, DevID 41692", 0 ), }; struct pci_driver golan_driver __pci_driver = { diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 2afaaf991..c09baf7ae 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -2840,7 +2840,7 @@ static int hermon_reset ( struct hermon *hermon ) { hermon->toggle = 0; /* Perform device reset and preserve PCI configuration */ - pci_backup ( pci, &backup, backup_exclude ); + pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_ALL, backup_exclude ); writel ( HERMON_RESET_MAGIC, ( hermon->config + HERMON_RESET_OFFSET ) ); @@ -2852,7 +2852,8 @@ static int hermon_reset ( struct hermon *hermon ) { if ( vendor == pci->vendor ) { /* Restore PCI configuration */ - pci_restore ( pci, &backup, backup_exclude ); + pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_ALL, + backup_exclude ); DBGC ( hermon, "Hermon %p reset after %dms\n", hermon, i ); diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index a4b51db05..da055b744 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -2256,7 +2256,7 @@ static void qib7322_reset ( struct qib7322 *qib7322, struct pci_device *pci ) { struct pci_config_backup backup; /* Back up PCI configuration space */ - pci_backup ( pci, &backup, NULL ); + pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_ALL, NULL ); /* Assert reset */ memset ( &control, 0, sizeof ( control ) ); @@ -2267,7 +2267,7 @@ static void qib7322_reset ( struct qib7322 *qib7322, struct pci_device *pci ) { mdelay ( 1000 ); /* Restore PCI configuration space */ - pci_restore ( pci, &backup, NULL ); + pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_ALL, NULL ); } /** 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 ( ðernet_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 */ |
