summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86/core/pcidirect.c4
-rw-r--r--src/arch/x86/include/bits/pci_io.h1
-rw-r--r--src/arch/x86/include/ipxe/pcibios.h2
-rw-r--r--src/arch/x86/include/ipxe/pcicloud.h18
-rw-r--r--src/arch/x86/include/ipxe/pcidirect.h16
-rw-r--r--src/arch/x86/interface/pcbios/pcibios.c22
-rw-r--r--src/arch/x86/interface/pcbios/pcicloud.c191
-rw-r--r--src/config/cloud/ioapi.h2
-rw-r--r--src/core/acpimac.c37
-rw-r--r--src/core/cachedhcp.c51
-rw-r--r--src/crypto/dhe.c133
-rw-r--r--src/crypto/hmac.c96
-rw-r--r--src/crypto/hmac_drbg.c16
-rw-r--r--src/crypto/mishmash/rsa_aes_cbc_sha1.c2
-rw-r--r--src/crypto/mishmash/rsa_aes_cbc_sha256.c2
-rw-r--r--src/crypto/ntlm.c19
-rw-r--r--src/crypto/sha1extra.c16
-rw-r--r--src/drivers/bus/ecam.c267
-rw-r--r--src/drivers/bus/pci.c54
-rw-r--r--src/drivers/bus/pcibridge.c132
-rw-r--r--src/drivers/bus/pciextra.c22
-rw-r--r--src/drivers/net/ecm.c28
-rw-r--r--src/drivers/net/ecm.h2
-rw-r--r--src/drivers/net/ena.c186
-rw-r--r--src/drivers/net/ena.h137
-rw-r--r--src/drivers/net/ice.c986
-rw-r--r--src/drivers/net/ice.h565
-rw-r--r--src/drivers/net/intelxl.c398
-rw-r--r--src/drivers/net/intelxl.h355
-rw-r--r--src/drivers/net/intelxlvf.c346
-rw-r--r--src/drivers/net/intelxlvf.h335
-rw-r--r--src/drivers/net/ncm.c2
-rw-r--r--src/hci/commands/pci_cmd.c18
-rw-r--r--src/include/ipxe/dhe.h19
-rw-r--r--src/include/ipxe/ecam.h57
-rw-r--r--src/include/ipxe/ecam_io.h139
-rw-r--r--src/include/ipxe/efi/efi_pci_api.h13
-rw-r--r--src/include/ipxe/errfile.h5
-rw-r--r--src/include/ipxe/hmac.h40
-rw-r--r--src/include/ipxe/linux/linux_pci.h16
-rw-r--r--src/include/ipxe/md4.h3
-rw-r--r--src/include/ipxe/md5.h3
-rw-r--r--src/include/ipxe/pci.h21
-rw-r--r--src/include/ipxe/pci_io.h55
-rw-r--r--src/include/ipxe/pcibridge.h43
-rw-r--r--src/include/ipxe/sha1.h3
-rw-r--r--src/include/ipxe/sha256.h3
-rw-r--r--src/include/ipxe/sha512.h3
-rw-r--r--src/include/ipxe/tls.h37
-rw-r--r--src/interface/efi/efi_pci.c2
-rw-r--r--src/interface/linux/linux_pci.c9
-rw-r--r--src/net/80211/wpa_ccmp.c11
-rw-r--r--src/net/80211/wpa_tkip.c9
-rw-r--r--src/net/ipv6.c2
-rw-r--r--src/net/ndp.c36
-rw-r--r--src/net/pccrc.c9
-rw-r--r--src/net/tls.c420
-rw-r--r--src/tests/dhe_test.c782
-rw-r--r--src/tests/hmac_test.c207
-rw-r--r--src/tests/ipv6_test.c101
-rw-r--r--src/tests/pccrc_test.c9
-rw-r--r--src/tests/tests.c2
62 files changed, 5696 insertions, 824 deletions
diff --git a/src/arch/x86/core/pcidirect.c b/src/arch/x86/core/pcidirect.c
index 9b8226fea..f4659a1ac 100644
--- a/src/arch/x86/core/pcidirect.c
+++ b/src/arch/x86/core/pcidirect.c
@@ -45,7 +45,7 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
PCIDIRECT_CONFIG_ADDRESS );
}
-PROVIDE_PCIAPI_INLINE ( direct, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( direct, pci_discover );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
@@ -53,3 +53,5 @@ PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap );
+
+struct pci_api pcidirect_api = PCIAPI_RUNTIME ( direct );
diff --git a/src/arch/x86/include/bits/pci_io.h b/src/arch/x86/include/bits/pci_io.h
index b41e562ee..a074d3370 100644
--- a/src/arch/x86/include/bits/pci_io.h
+++ b/src/arch/x86/include/bits/pci_io.h
@@ -11,5 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
+#include <ipxe/pcicloud.h>
#endif /* _BITS_PCI_IO_H */
diff --git a/src/arch/x86/include/ipxe/pcibios.h b/src/arch/x86/include/ipxe/pcibios.h
index bae4eede1..3caea1cfe 100644
--- a/src/arch/x86/include/ipxe/pcibios.h
+++ b/src/arch/x86/include/ipxe/pcibios.h
@@ -145,4 +145,6 @@ PCIAPI_INLINE ( pcbios, pci_ioremap ) ( struct pci_device *pci __unused,
return ioremap ( bus_addr, len );
}
+extern struct pci_api pcibios_api;
+
#endif /* _IPXE_PCIBIOS_H */
diff --git a/src/arch/x86/include/ipxe/pcicloud.h b/src/arch/x86/include/ipxe/pcicloud.h
new file mode 100644
index 000000000..52268908c
--- /dev/null
+++ b/src/arch/x86/include/ipxe/pcicloud.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_PCICLOUD_H
+#define _IPXE_PCICLOUD_H
+
+/** @file
+ *
+ * Cloud VM PCI configuration space access
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#ifdef PCIAPI_CLOUD
+#define PCIAPI_PREFIX_cloud
+#else
+#define PCIAPI_PREFIX_cloud __cloud_
+#endif
+
+#endif /* _IPXE_PCICLOUD_H */
diff --git a/src/arch/x86/include/ipxe/pcidirect.h b/src/arch/x86/include/ipxe/pcidirect.h
index decdc8100..98c6a2bbb 100644
--- a/src/arch/x86/include/ipxe/pcidirect.h
+++ b/src/arch/x86/include/ipxe/pcidirect.h
@@ -26,14 +26,18 @@ struct pci_device;
extern void pcidirect_prepare ( struct pci_device *pci, int where );
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static inline __always_inline int
-PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
+static inline __always_inline void
+PCIAPI_INLINE ( direct, pci_discover ) ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
+
/* Scan first bus and rely on bridge detection to find higher buses */
- return 1;
+ range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 0, 1, 0, 0 );
}
/**
@@ -151,4 +155,6 @@ PCIAPI_INLINE ( direct, pci_ioremap ) ( struct pci_device *pci __unused,
return ioremap ( bus_addr, len );
}
+extern struct pci_api pcidirect_api;
+
#endif /* _PCIDIRECT_H */
diff --git a/src/arch/x86/interface/pcbios/pcibios.c b/src/arch/x86/interface/pcbios/pcibios.c
index bf812f77f..7b7a769e3 100644
--- a/src/arch/x86/interface/pcbios/pcibios.c
+++ b/src/arch/x86/interface/pcbios/pcibios.c
@@ -34,13 +34,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static int pcibios_num_bus ( void ) {
+static void pcibios_discover ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
int discard_a, discard_D;
- uint8_t max_bus;
+ uint16_t num_bus;
/* We issue this call using flat real mode, to work around a
* bug in some HP BIOSes.
@@ -48,16 +50,20 @@ static int pcibios_num_bus ( void ) {
__asm__ __volatile__ ( REAL_CODE ( "call flatten_real_mode\n\t"
"stc\n\t"
"int $0x1a\n\t"
+ "movzbw %%cl, %%cx\n\t"
+ "incw %%cx\n\t"
"jnc 1f\n\t"
"xorw %%cx, %%cx\n\t"
"\n1:\n\t" )
- : "=c" ( max_bus ), "=a" ( discard_a ),
+ : "=c" ( num_bus ), "=a" ( discard_a ),
"=D" ( discard_D )
: "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 ),
"D" ( 0 )
: "ebx", "edx" );
- return ( max_bus + 1 );
+ /* Populate range */
+ range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 0, num_bus, 0, 0 );
}
/**
@@ -114,7 +120,7 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
return ( status >> 8 );
}
-PROVIDE_PCIAPI ( pcbios, pci_num_bus, pcibios_num_bus );
+PROVIDE_PCIAPI ( pcbios, pci_discover, pcibios_discover );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
@@ -122,3 +128,5 @@ PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap );
+
+struct pci_api pcibios_api = PCIAPI_RUNTIME ( pcbios );
diff --git a/src/arch/x86/interface/pcbios/pcicloud.c b/src/arch/x86/interface/pcbios/pcicloud.c
new file mode 100644
index 000000000..97d7cac1d
--- /dev/null
+++ b/src/arch/x86/interface/pcbios/pcicloud.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/init.h>
+#include <ipxe/pci.h>
+#include <ipxe/ecam.h>
+#include <ipxe/pcibios.h>
+#include <ipxe/pcidirect.h>
+#include <ipxe/pcicloud.h>
+
+/** @file
+ *
+ * Cloud VM PCI configuration space access
+ *
+ */
+
+/** Selected PCI configuration space access API */
+static struct pci_api *pcicloud = &ecam_api;
+
+/**
+ * Find next PCI bus:dev.fn address range in system
+ *
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
+ */
+static void pcicloud_discover ( uint32_t busdevfn, struct pci_range *range ) {
+
+ pcicloud->pci_discover ( busdevfn, range );
+}
+
+/**
+ * Read byte from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static int pcicloud_read_config_byte ( struct pci_device *pci,
+ unsigned int where, uint8_t *value ) {
+
+ return pcicloud->pci_read_config_byte ( pci, where, value );
+}
+
+/**
+ * Read 16-bit word from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static int pcicloud_read_config_word ( struct pci_device *pci,
+ unsigned int where, uint16_t *value ) {
+
+ return pcicloud->pci_read_config_word ( pci, where, value );
+}
+
+/**
+ * Read 32-bit dword from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static int pcicloud_read_config_dword ( struct pci_device *pci,
+ unsigned int where, uint32_t *value ) {
+
+ return pcicloud->pci_read_config_dword ( pci, where, value );
+}
+
+/**
+ * Write byte to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static int pcicloud_write_config_byte ( struct pci_device *pci,
+ unsigned int where, uint8_t value ) {
+
+ return pcicloud->pci_write_config_byte ( pci, where, value );
+}
+
+/**
+ * Write 16-bit word to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static int pcicloud_write_config_word ( struct pci_device *pci,
+ unsigned int where, uint16_t value ) {
+
+ return pcicloud->pci_write_config_word ( pci, where, value );
+}
+
+/**
+ * Write 32-bit dword to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static int pcicloud_write_config_dword ( struct pci_device *pci,
+ unsigned int where, uint32_t value ) {
+
+ return pcicloud->pci_write_config_dword ( pci, where, value );
+}
+
+/**
+ * Map PCI bus address as an I/O address
+ *
+ * @v bus_addr PCI bus address
+ * @v len Length of region
+ * @ret io_addr I/O address, or NULL on error
+ */
+static void * pcicloud_ioremap ( struct pci_device *pci,
+ unsigned long bus_addr, size_t len ) {
+
+ return pcicloud->pci_ioremap ( pci, bus_addr, len );
+}
+
+PROVIDE_PCIAPI ( cloud, pci_discover, pcicloud_discover );
+PROVIDE_PCIAPI ( cloud, pci_read_config_byte, pcicloud_read_config_byte );
+PROVIDE_PCIAPI ( cloud, pci_read_config_word, pcicloud_read_config_word );
+PROVIDE_PCIAPI ( cloud, pci_read_config_dword, pcicloud_read_config_dword );
+PROVIDE_PCIAPI ( cloud, pci_write_config_byte, pcicloud_write_config_byte );
+PROVIDE_PCIAPI ( cloud, pci_write_config_word, pcicloud_write_config_word );
+PROVIDE_PCIAPI ( cloud, pci_write_config_dword, pcicloud_write_config_dword );
+PROVIDE_PCIAPI ( cloud, pci_ioremap, pcicloud_ioremap );
+
+/**
+ * Initialise cloud VM PCI configuration space access
+ *
+ */
+static void pcicloud_init ( void ) {
+ static struct pci_api *apis[] = {
+ &ecam_api, &pcibios_api, &pcidirect_api
+ };
+ struct pci_range range;
+ unsigned int i;
+
+ /* Select first API that successfully discovers an address range */
+ for ( i = 0 ; i < ( sizeof ( apis ) / sizeof ( apis[0] ) ) ; i++ ) {
+ pcicloud = apis[i];
+ pcicloud_discover ( 0, &range );
+ if ( range.count != 0 ) {
+ DBGC ( pcicloud, "PCICLOUD selected %s API\n",
+ pcicloud->name );
+ break;
+ }
+ }
+
+ /* The PCI direct API can never fail discovery since the range
+ * is hardcoded.
+ */
+ assert ( range.count != 0 );
+}
+
+/** Cloud VM PCI configuration space access initialisation function */
+struct init_fn pcicloud_init_fn __init_fn ( INIT_EARLY ) = {
+ .initialise = pcicloud_init,
+};
diff --git a/src/config/cloud/ioapi.h b/src/config/cloud/ioapi.h
index c7c917f2e..ba0896a9a 100644
--- a/src/config/cloud/ioapi.h
+++ b/src/config/cloud/ioapi.h
@@ -3,5 +3,5 @@
*/
#ifdef PLATFORM_pcbios
#undef PCIAPI_PCBIOS
-#define PCIAPI_DIRECT
+#define PCIAPI_CLOUD
#endif
diff --git a/src/core/acpimac.c b/src/core/acpimac.c
index 5920480dd..e0074ba43 100644
--- a/src/core/acpimac.c
+++ b/src/core/acpimac.c
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/base16.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
+#include <ipxe/settings.h>
#include <ipxe/acpimac.h>
/** @file
@@ -249,3 +250,39 @@ int acpi_mac ( uint8_t *hw_addr ) {
return -ENOENT;
}
+
+/**
+ * Fetch system MAC address setting
+ *
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int sysmac_fetch ( void *data, size_t len ) {
+ uint8_t mac[ETH_ALEN];
+ int rc;
+
+ /* Try fetching ACPI MAC address */
+ if ( ( rc = acpi_mac ( mac ) ) != 0 )
+ return rc;
+
+ /* Return MAC address */
+ if ( len > sizeof ( mac ) )
+ len = sizeof ( mac );
+ memcpy ( data, mac, len );
+ return ( sizeof ( mac ) );
+}
+
+/** System MAC address setting */
+const struct setting sysmac_setting __setting ( SETTING_MISC, sysmac ) = {
+ .name = "sysmac",
+ .description = "System MAC",
+ .type = &setting_type_hex,
+ .scope = &builtin_scope,
+};
+
+/** System MAC address built-in setting */
+struct builtin_setting sysmac_builtin_setting __builtin_setting = {
+ .setting = &sysmac_setting,
+ .fetch = sysmac_fetch,
+};
diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c
index 2fa9b0c73..c4ca46e3a 100644
--- a/src/core/cachedhcp.c
+++ b/src/core/cachedhcp.c
@@ -90,29 +90,62 @@ static void cachedhcp_free ( struct cached_dhcp_packet *cache ) {
*/
static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
struct net_device *netdev ) {
- struct settings *settings;
+ struct settings *settings = NULL;
+ struct ll_protocol *ll_protocol;
+ const uint8_t *chaddr;
+ uint8_t *hw_addr;
+ uint8_t *ll_addr;
+ size_t ll_addr_len;
int rc;
/* Do nothing if cache is empty */
if ( ! cache->dhcppkt )
return 0;
+ chaddr = cache->dhcppkt->dhcphdr->chaddr;
- /* Do nothing unless cached packet's MAC address matches this
- * network device, if specified.
- */
+ /* Handle association with network device, if specified */
if ( netdev ) {
- if ( memcmp ( netdev->ll_addr, cache->dhcppkt->dhcphdr->chaddr,
- netdev->ll_protocol->ll_addr_len ) != 0 ) {
+ hw_addr = netdev->hw_addr;
+ ll_addr = netdev->ll_addr;
+ ll_protocol = netdev->ll_protocol;
+ ll_addr_len = ll_protocol->ll_addr_len;
+
+ /* If cached packet's MAC address matches the network
+ * device's permanent MAC address, then assume that
+ * the permanent MAC address ought to be the network
+ * device's current link-layer address.
+ *
+ * This situation can arise when the PXE ROM does not
+ * understand the system-specific mechanism for
+ * overriding the MAC address, and so uses the
+ * permanent MAC address instead. We choose to match
+ * this behaviour in order to minimise surprise.
+ */
+ if ( memcmp ( hw_addr, chaddr, ll_addr_len ) == 0 ) {
+ if ( memcmp ( hw_addr, ll_addr, ll_addr_len ) != 0 ) {
+ DBGC ( colour, "CACHEDHCP %s resetting %s MAC "
+ "%s ", cache->name, netdev->name,
+ ll_protocol->ntoa ( ll_addr ) );
+ DBGC ( colour, "-> %s\n",
+ ll_protocol->ntoa ( hw_addr ) );
+ }
+ memcpy ( ll_addr, hw_addr, ll_addr_len );
+ }
+
+ /* Do nothing unless cached packet's MAC address
+ * matches this network device.
+ */
+ if ( memcmp ( ll_addr, chaddr, ll_addr_len ) != 0 ) {
DBGC ( colour, "CACHEDHCP %s does not match %s\n",
cache->name, netdev->name );
return 0;
}
DBGC ( colour, "CACHEDHCP %s is for %s\n",
cache->name, netdev->name );
- }
- /* Select appropriate parent settings block */
- settings = ( netdev ? netdev_settings ( netdev ) : NULL );
+ /* Use network device's settings block */
+ settings = netdev_settings ( netdev );
+ }
/* Register settings */
if ( ( rc = register_settings ( &cache->dhcppkt->settings, settings,
diff --git a/src/crypto/dhe.c b/src/crypto/dhe.c
new file mode 100644
index 000000000..2da107d24
--- /dev/null
+++ b/src/crypto/dhe.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Ephemeral Diffie-Hellman key exchange
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/bigint.h>
+#include <ipxe/dhe.h>
+
+/**
+ * Calculate Diffie-Hellman key
+ *
+ * @v modulus Prime modulus
+ * @v len Length of prime modulus
+ * @v generator Generator
+ * @v generator_len Length of generator
+ * @v partner Partner public key
+ * @v partner_len Length of partner public key
+ * @v private Private key
+ * @v private_len Length of private key
+ * @ret public Public key (length equal to prime modulus)
+ * @ret shared Shared secret (length equal to prime modulus)
+ * @ret rc Return status code
+ */
+int dhe_key ( const void *modulus, size_t len, const void *generator,
+ size_t generator_len, const void *partner, size_t partner_len,
+ const void *private, size_t private_len, void *public,
+ void *shared ) {
+ unsigned int size = bigint_required_size ( len );
+ unsigned int private_size = bigint_required_size ( private_len );
+ bigint_t ( size ) *mod;
+ bigint_t ( private_size ) *exp;
+ size_t tmp_len = bigint_mod_exp_tmp_len ( mod, exp );
+ struct {
+ bigint_t ( size ) modulus;
+ bigint_t ( size ) generator;
+ bigint_t ( size ) partner;
+ bigint_t ( private_size ) private;
+ bigint_t ( size ) result;
+ uint8_t tmp[tmp_len];
+ } __attribute__ (( packed )) *ctx;
+ int rc;
+
+ DBGC2 ( modulus, "DHE %p modulus:\n", modulus );
+ DBGC2_HDA ( modulus, 0, modulus, len );
+ DBGC2 ( modulus, "DHE %p generator:\n", modulus );
+ DBGC2_HDA ( modulus, 0, generator, generator_len );
+ DBGC2 ( modulus, "DHE %p partner public key:\n", modulus );
+ DBGC2_HDA ( modulus, 0, partner, partner_len );
+ DBGC2 ( modulus, "DHE %p private key:\n", modulus );
+ DBGC2_HDA ( modulus, 0, private, private_len );
+
+ /* Sanity checks */
+ if ( generator_len > len ) {
+ DBGC ( modulus, "DHE %p overlength generator\n", modulus );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+ if ( partner_len > len ) {
+ DBGC ( modulus, "DHE %p overlength partner public key\n",
+ modulus );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+ if ( private_len > len ) {
+ DBGC ( modulus, "DHE %p overlength private key\n", modulus );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+
+ /* Allocate context */
+ ctx = malloc ( sizeof ( *ctx ) );
+ if ( ! ctx ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Initialise context */
+ bigint_init ( &ctx->modulus, modulus, len );
+ bigint_init ( &ctx->generator, generator, generator_len );
+ bigint_init ( &ctx->partner, partner, partner_len );
+ bigint_init ( &ctx->private, private, private_len );
+
+ /* Calculate public key */
+ bigint_mod_exp ( &ctx->generator, &ctx->modulus, &ctx->private,
+ &ctx->result, ctx->tmp );
+ bigint_done ( &ctx->result, public, len );
+ DBGC2 ( modulus, "DHE %p public key:\n", modulus );
+ DBGC2_HDA ( modulus, 0, public, len );
+
+ /* Calculate shared secret */
+ bigint_mod_exp ( &ctx->partner, &ctx->modulus, &ctx->private,
+ &ctx->result, ctx->tmp );
+ bigint_done ( &ctx->result, shared, len );
+ DBGC2 ( modulus, "DHE %p shared secret:\n", modulus );
+ DBGC2_HDA ( modulus, 0, shared, len );
+
+ /* Success */
+ rc = 0;
+
+ free ( ctx );
+ err_alloc:
+ err_sanity:
+ return rc;
+}
diff --git a/src/crypto/hmac.c b/src/crypto/hmac.c
index f898619c8..7109bbf6a 100644
--- a/src/crypto/hmac.c
+++ b/src/crypto/hmac.c
@@ -47,93 +47,61 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/hmac.h>
/**
- * Reduce HMAC key length
- *
- * @v digest Digest algorithm to use
- * @v digest_ctx Digest context
- * @v key Key
- * @v key_len Length of key
- */
-static void hmac_reduce_key ( struct digest_algorithm *digest,
- void *key, size_t *key_len ) {
- uint8_t digest_ctx[digest->ctxsize];
-
- digest_init ( digest, digest_ctx );
- digest_update ( digest, digest_ctx, key, *key_len );
- digest_final ( digest, digest_ctx, key );
- *key_len = digest->digestsize;
-}
-
-/**
* Initialise HMAC
*
* @v digest Digest algorithm to use
- * @v digest_ctx Digest context
+ * @v ctx HMAC context
* @v key Key
* @v key_len Length of key
- *
- * The length of the key should be less than the block size of the
- * digest algorithm being used. (If the key length is greater, it
- * will be replaced with its own digest, and key_len will be updated
- * accordingly).
*/
-void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
- void *key, size_t *key_len ) {
- unsigned char k_ipad[digest->blocksize];
+void hmac_init ( struct digest_algorithm *digest, void *ctx, const void *key,
+ size_t key_len ) {
+ hmac_context_t ( digest ) *hctx = ctx;
unsigned int i;
- /* Reduce key if necessary */
- if ( *key_len > sizeof ( k_ipad ) )
- hmac_reduce_key ( digest, key, key_len );
-
/* Construct input pad */
- memset ( k_ipad, 0, sizeof ( k_ipad ) );
- memcpy ( k_ipad, key, *key_len );
- for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
- k_ipad[i] ^= 0x36;
+ memset ( hctx->pad, 0, sizeof ( hctx->pad ) );
+ if ( key_len <= sizeof ( hctx->pad ) ) {
+ memcpy ( hctx->pad, key, key_len );
+ } else {
+ digest_init ( digest, hctx->ctx );
+ digest_update ( digest, hctx->ctx, key, key_len );
+ digest_final ( digest, hctx->ctx, hctx->pad );
+ }
+ for ( i = 0 ; i < sizeof ( hctx->pad ) ; i++ ) {
+ hctx->pad[i] ^= 0x36;
}
-
+
/* Start inner hash */
- digest_init ( digest, digest_ctx );
- digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
+ digest_init ( digest, hctx->ctx );
+ digest_update ( digest, hctx->ctx, hctx->pad, sizeof ( hctx->pad ) );
}
/**
* Finalise HMAC
*
* @v digest Digest algorithm to use
- * @v digest_ctx Digest context
- * @v key Key
- * @v key_len Length of key
+ * @v ctx HMAC context
* @v hmac HMAC digest to fill in
- *
- * The length of the key should be less than the block size of the
- * digest algorithm being used. (If the key length is greater, it
- * will be replaced with its own digest, and key_len will be updated
- * accordingly).
*/
-void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
- void *key, size_t *key_len, void *hmac ) {
- unsigned char k_opad[digest->blocksize];
+void hmac_final ( struct digest_algorithm *digest, void *ctx, void *hmac ) {
+ hmac_context_t ( digest ) *hctx = ctx;
unsigned int i;
- /* Reduce key if necessary */
- if ( *key_len > sizeof ( k_opad ) )
- hmac_reduce_key ( digest, key, key_len );
-
- /* Construct output pad */
- memset ( k_opad, 0, sizeof ( k_opad ) );
- memcpy ( k_opad, key, *key_len );
- for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
- k_opad[i] ^= 0x5c;
+ /* Construct output pad from input pad */
+ for ( i = 0 ; i < sizeof ( hctx->pad ) ; i++ ) {
+ hctx->pad[i] ^= 0x6a;
}
-
+
/* Finish inner hash */
- digest_final ( digest, digest_ctx, hmac );
+ digest_final ( digest, hctx->ctx, hmac );
/* Perform outer hash */
- digest_init ( digest, digest_ctx );
- digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
- digest_update ( digest, digest_ctx, hmac, digest->digestsize );
- digest_final ( digest, digest_ctx, hmac );
+ digest_init ( digest, hctx->ctx );
+ digest_update ( digest, hctx->ctx, hctx->pad, sizeof ( hctx->pad ) );
+ digest_update ( digest, hctx->ctx, hmac, digest->digestsize );
+ digest_final ( digest, hctx->ctx, hmac );
+
+ /* Erase output pad (from which the key may be derivable) */
+ memset ( hctx->pad, 0, sizeof ( hctx->pad ) );
}
diff --git a/src/crypto/hmac_drbg.c b/src/crypto/hmac_drbg.c
index 098297716..57bde4d1d 100644
--- a/src/crypto/hmac_drbg.c
+++ b/src/crypto/hmac_drbg.c
@@ -79,7 +79,7 @@ static void hmac_drbg_update_key ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *data, size_t len,
const uint8_t single ) {
- uint8_t context[ hash->ctxsize ];
+ uint8_t context[ hmac_ctxsize ( hash ) ];
size_t out_len = hash->digestsize;
DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
@@ -92,13 +92,11 @@ static void hmac_drbg_update_key ( struct digest_algorithm *hash,
assert ( ( single == 0x00 ) || ( single == 0x01 ) );
/* K = HMAC ( K, V || single || provided_data ) */
- hmac_init ( hash, context, state->key, &out_len );
- assert ( out_len == hash->digestsize );
+ hmac_init ( hash, context, state->key, out_len );
hmac_update ( hash, context, state->value, out_len );
hmac_update ( hash, context, &single, sizeof ( single ) );
hmac_update ( hash, context, data, len );
- hmac_final ( hash, context, state->key, &out_len, state->key );
- assert ( out_len == hash->digestsize );
+ hmac_final ( hash, context, state->key );
DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
"provided_data ) :\n", hash->name, state, single );
@@ -122,7 +120,7 @@ static void hmac_drbg_update_key ( struct digest_algorithm *hash,
*/
static void hmac_drbg_update_value ( struct digest_algorithm *hash,
struct hmac_drbg_state *state ) {
- uint8_t context[ hash->ctxsize ];
+ uint8_t context[ hmac_ctxsize ( hash ) ];
size_t out_len = hash->digestsize;
/* Sanity checks */
@@ -130,11 +128,9 @@ static void hmac_drbg_update_value ( struct digest_algorithm *hash,
assert ( state != NULL );
/* V = HMAC ( K, V ) */
- hmac_init ( hash, context, state->key, &out_len );
- assert ( out_len == hash->digestsize );
+ hmac_init ( hash, context, state->key, out_len );
hmac_update ( hash, context, state->value, out_len );
- hmac_final ( hash, context, state->key, &out_len, state->value );
- assert ( out_len == hash->digestsize );
+ hmac_final ( hash, context, state->value );
DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
hash->name, state );
diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/src/crypto/mishmash/rsa_aes_cbc_sha1.c
index 06722c0e1..04b4ce2a7 100644
--- a/src/crypto/mishmash/rsa_aes_cbc_sha1.c
+++ b/src/crypto/mishmash/rsa_aes_cbc_sha1.c
@@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite (03) = {
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
.key_len = ( 128 / 8 ),
+ .exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
@@ -42,6 +43,7 @@ struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite (03) = {
struct tls_cipher_suite tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite (04) = {
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
.key_len = ( 256 / 8 ),
+ .exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/src/crypto/mishmash/rsa_aes_cbc_sha256.c
index c609eacea..1021f76f4 100644
--- a/src/crypto/mishmash/rsa_aes_cbc_sha256.c
+++ b/src/crypto/mishmash/rsa_aes_cbc_sha256.c
@@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite(01)={
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
.key_len = ( 128 / 8 ),
+ .exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
@@ -42,6 +43,7 @@ struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite(01)={
struct tls_cipher_suite tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite(02)={
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
.key_len = ( 256 / 8 ),
+ .exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
diff --git a/src/crypto/ntlm.c b/src/crypto/ntlm.c
index 870af2132..fb120f8db 100644
--- a/src/crypto/ntlm.c
+++ b/src/crypto/ntlm.c
@@ -117,10 +117,9 @@ void ntlm_key ( const char *domain, const char *username,
struct digest_algorithm *md5 = &md5_algorithm;
union {
uint8_t md4[MD4_CTX_SIZE];
- uint8_t md5[MD5_CTX_SIZE];
+ uint8_t md5[ MD5_CTX_SIZE + MD5_BLOCK_SIZE ];
} ctx;
uint8_t digest[MD4_DIGEST_SIZE];
- size_t digest_len;
uint8_t c;
uint16_t wc;
@@ -141,8 +140,7 @@ void ntlm_key ( const char *domain, const char *username,
digest_final ( md4, ctx.md4, digest );
/* Construct HMAC-MD5 of (Unicode) upper-case username */
- digest_len = sizeof ( digest );
- hmac_init ( md5, ctx.md5, digest, &digest_len );
+ hmac_init ( md5, ctx.md5, digest, sizeof ( digest ) );
while ( ( c = *(username++) ) ) {
wc = cpu_to_le16 ( toupper ( c ) );
hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
@@ -151,7 +149,7 @@ void ntlm_key ( const char *domain, const char *username,
wc = cpu_to_le16 ( c );
hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
}
- hmac_final ( md5, ctx.md5, digest, &digest_len, key->raw );
+ hmac_final ( md5, ctx.md5, key->raw );
DBGC ( key, "NTLM key:\n" );
DBGC_HDA ( key, 0, key, sizeof ( *key ) );
}
@@ -170,8 +168,7 @@ void ntlm_response ( struct ntlm_challenge_info *info, struct ntlm_key *key,
struct ntlm_nt_response *nt ) {
struct digest_algorithm *md5 = &md5_algorithm;
struct ntlm_nonce tmp_nonce;
- uint8_t ctx[MD5_CTX_SIZE];
- size_t key_len = sizeof ( *key );
+ uint8_t ctx[ MD5_CTX_SIZE + MD5_BLOCK_SIZE ];
unsigned int i;
/* Generate random nonce, if needed */
@@ -183,10 +180,10 @@ void ntlm_response ( struct ntlm_challenge_info *info, struct ntlm_key *key,
/* Construct LAN Manager response */
memcpy ( &lm->nonce, nonce, sizeof ( lm->nonce ) );
- hmac_init ( md5, ctx, key->raw, &key_len );
+ hmac_init ( md5, ctx, key->raw, sizeof ( *key ) );
hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
hmac_update ( md5, ctx, &lm->nonce, sizeof ( lm->nonce ) );
- hmac_final ( md5, ctx, key->raw, &key_len, lm->digest );
+ hmac_final ( md5, ctx, lm->digest );
DBGC ( key, "NTLM LAN Manager response:\n" );
DBGC_HDA ( key, 0, lm, sizeof ( *lm ) );
@@ -195,14 +192,14 @@ void ntlm_response ( struct ntlm_challenge_info *info, struct ntlm_key *key,
nt->version = NTLM_VERSION_NTLMV2;
nt->high = NTLM_VERSION_NTLMV2;
memcpy ( &nt->nonce, nonce, sizeof ( nt->nonce ) );
- hmac_init ( md5, ctx, key->raw, &key_len );
+ hmac_init ( md5, ctx, key->raw, sizeof ( *key ) );
hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
hmac_update ( md5, ctx, &nt->version,
( sizeof ( *nt ) -
offsetof ( typeof ( *nt ), version ) ) );
hmac_update ( md5, ctx, info->target, info->len );
hmac_update ( md5, ctx, &nt->zero, sizeof ( nt->zero ) );
- hmac_final ( md5, ctx, key->raw, &key_len, nt->digest );
+ hmac_final ( md5, ctx, nt->digest );
DBGC ( key, "NTLM NT response prefix:\n" );
DBGC_HDA ( key, 0, nt, sizeof ( *nt ) );
}
diff --git a/src/crypto/sha1extra.c b/src/crypto/sha1extra.c
index cec0d35e5..9e296eb2c 100644
--- a/src/crypto/sha1extra.c
+++ b/src/crypto/sha1extra.c
@@ -49,7 +49,7 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
u8 *in_blknr; /* pointer to last byte of in, block number */
u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */
- u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
+ u8 ctx[SHA1_CTX_SIZE + SHA1_BLOCK_SIZE]; /* HMAC-SHA1 context */
const size_t label_len = strlen ( label );
/* The HMAC-SHA-1 is calculated using the given key on the
@@ -65,9 +65,9 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
for ( blk = 0 ;; blk++ ) {
*in_blknr = blk;
- hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len );
- hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
- hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
+ hmac_init ( &sha1_algorithm, ctx, keym, key_len );
+ hmac_update ( &sha1_algorithm, ctx, in, sizeof ( in ) );
+ hmac_final ( &sha1_algorithm, ctx, out );
if ( prf_len <= sizeof ( out ) ) {
memcpy ( prf, out, prf_len );
@@ -100,7 +100,7 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
u8 pass[pass_len]; /* modifiable passphrase */
u8 in[salt_len + 4]; /* input buffer to first round */
u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */
- u8 sha1_ctx[SHA1_CTX_SIZE];
+ u8 ctx[SHA1_CTX_SIZE + SHA1_BLOCK_SIZE];
u8 *next_in = in; /* changed to `last' after first round */
int next_size = sizeof ( in );
int i;
@@ -114,9 +114,9 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
memset ( block, 0, sizeof ( last ) );
for ( i = 0; i < iterations; i++ ) {
- hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
- hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
- hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
+ hmac_init ( &sha1_algorithm, ctx, pass, pass_len );
+ hmac_update ( &sha1_algorithm, ctx, next_in, next_size );
+ hmac_final ( &sha1_algorithm, ctx, last );
for ( j = 0; j < sizeof ( last ); j++ ) {
block[j] ^= last[j];
diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c
new file mode 100644
index 000000000..1d57bd2a0
--- /dev/null
+++ b/src/drivers/bus/ecam.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <errno.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/ecam.h>
+
+/** @file
+ *
+ * PCI Enhanced Configuration Access Mechanism (ECAM)
+ *
+ */
+
+/** Cached mapped ECAM allocation */
+static struct ecam_mapping ecam;
+
+/**
+ * Find lowest ECAM allocation not below a given PCI bus:dev.fn address
+ *
+ * @v busdevfn PCI bus:dev.fn address
+ * @v range PCI device address range to fill in
+ * @v alloc ECAM allocation to fill in, or NULL
+ * @ret rc Return status code
+ */
+static int ecam_find ( uint32_t busdevfn, struct pci_range *range,
+ struct ecam_allocation *alloc ) {
+ struct ecam_allocation tmp;
+ unsigned int best = 0;
+ unsigned int offset;
+ unsigned int count;
+ unsigned int index;
+ userptr_t mcfg;
+ uint32_t length;
+ uint32_t start;
+
+ /* Return empty range on error */
+ range->count = 0;
+
+ /* Locate MCFG table */
+ mcfg = acpi_table ( ECAM_SIGNATURE, 0 );
+ if ( ! mcfg ) {
+ DBGC ( &ecam, "ECAM found no MCFG table\n" );
+ return -ENOTSUP;
+ }
+
+ /* Get length of table */
+ copy_from_user ( &length, mcfg,
+ offsetof ( struct ecam_table, acpi.length ),
+ sizeof ( length ) );
+
+ /* Iterate over allocations */
+ for ( offset = offsetof ( struct ecam_table, alloc ) ;
+ ( offset + sizeof ( tmp ) ) <= le32_to_cpu ( length ) ;
+ offset += sizeof ( tmp ) ) {
+
+ /* Read allocation */
+ copy_from_user ( &tmp, mcfg, offset, sizeof ( tmp ) );
+ DBGC2 ( &ecam, "ECAM %04x:[%02x-%02x] has base %08llx\n",
+ le16_to_cpu ( tmp.segment ), tmp.start, tmp.end,
+ ( ( unsigned long long ) le64_to_cpu ( tmp.base ) ) );
+ start = PCI_BUSDEVFN ( le16_to_cpu ( tmp.segment ),
+ tmp.start, 0, 0 );
+ count = PCI_BUSDEVFN ( 0, ( tmp.end - tmp.start + 1 ), 0, 0 );
+
+ /* Check for a matching or new closest allocation */
+ index = ( busdevfn - start );
+ if ( ( index < count ) || ( index > best ) ) {
+ if ( alloc )
+ memcpy ( alloc, &tmp, sizeof ( *alloc ) );
+ range->start = start;
+ range->count = count;
+ best = index;
+ }
+
+ /* Stop if this range contains the target bus:dev.fn address */
+ if ( index < count )
+ return 0;
+ }
+
+ return ( best ? 0 : -ENOENT );
+}
+
+/**
+ * Find next PCI bus:dev.fn address range in system
+ *
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
+ */
+static void ecam_discover ( uint32_t busdevfn, struct pci_range *range ) {
+
+ /* Find new range, if any */
+ ecam_find ( busdevfn, range, NULL );
+}
+
+/**
+ * Access configuration space for PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int ecam_access ( struct pci_device *pci ) {
+ uint64_t base;
+ size_t len;
+ int rc;
+
+ /* Reuse mapping if possible */
+ if ( ( pci->busdevfn - ecam.range.start ) < ecam.range.count )
+ return 0;
+
+ /* Clear any existing mapping */
+ if ( ecam.regs ) {
+ iounmap ( ecam.regs );
+ ecam.regs = NULL;
+ }
+
+ /* Find allocation for this PCI device */
+ if ( ( rc = ecam_find ( pci->busdevfn, &ecam.range,
+ &ecam.alloc ) ) != 0 ) {
+ DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT ": %s\n",
+ PCI_ARGS ( pci ), strerror ( rc ) );
+ goto err_find;
+ }
+ if ( ecam.range.start > pci->busdevfn ) {
+ DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT "\n",
+ PCI_ARGS ( pci ) );
+ goto err_find;
+ }
+
+ /* Map configuration space for this allocation */
+ base = le64_to_cpu ( ecam.alloc.base );
+ len = ( ecam.range.count * ECAM_SIZE );
+ ecam.regs = ioremap ( base, len );
+ if ( ! ecam.regs ) {
+ DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map "
+ "[%08llx,%08llx)\n", le16_to_cpu ( ecam.alloc.segment ),
+ ecam.alloc.start, ecam.alloc.end, base, ( base + len ) );
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Populate cached mapping */
+ DBGC ( &ecam, "ECAM %04x:[%02x-%02x] mapped [%08llx,%08llx) -> %p\n",
+ le16_to_cpu ( ecam.alloc.segment ), ecam.alloc.start,
+ ecam.alloc.end, base, ( base + len ), ecam.regs );
+ return 0;
+
+ iounmap ( ecam.regs );
+ err_ioremap:
+ err_find:
+ ecam.range.count = 0;
+ return rc;
+}
+
+/**
+ * Read from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v location Offset and length within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int ecam_read ( struct pci_device *pci, unsigned int location, void *value ) {
+ unsigned int where = ECAM_WHERE ( location );
+ unsigned int len = ECAM_LEN ( location );
+ unsigned int index;
+ void *addr;
+ int rc;
+
+ /* Return all-ones on error */
+ memset ( value, 0xff, len );
+
+ /* Access configuration space */
+ if ( ( rc = ecam_access ( pci ) ) != 0 )
+ return rc;
+
+ /* Read from address */
+ index = ( pci->busdevfn - ecam.range.start );
+ addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
+ switch ( len ) {
+ case 4:
+ *( ( uint32_t *) value ) = readl ( addr );
+ break;
+ case 2:
+ *( ( uint16_t *) value ) = readw ( addr );
+ break;
+ case 1:
+ *( ( uint8_t *) value ) = readb ( addr );
+ break;
+ default:
+ assert ( 0 );
+ }
+
+ return 0;
+}
+
+/**
+ * Write to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v location Offset and length within PCI configuration space
+ * @v value Value to write
+ * @ret rc Return status code
+ */
+int ecam_write ( struct pci_device *pci, unsigned int location,
+ unsigned long value ) {
+ unsigned int where = ECAM_WHERE ( location );
+ unsigned int len = ECAM_LEN ( location );
+ unsigned int index;
+ void *addr;
+ int rc;
+
+ /* Access configuration space */
+ if ( ( rc = ecam_access ( pci ) ) != 0 )
+ return rc;
+
+ /* Read from address */
+ index = ( pci->busdevfn - ecam.range.start );
+ addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
+ switch ( len ) {
+ case 4:
+ writel ( value, addr );
+ break;
+ case 2:
+ writew ( value, addr );
+ break;
+ case 1:
+ writeb ( value, addr );
+ break;
+ default:
+ assert ( 0 );
+ }
+
+ return 0;
+}
+
+PROVIDE_PCIAPI ( ecam, pci_discover, ecam_discover );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_dword );
+PROVIDE_PCIAPI_INLINE ( ecam, pci_ioremap );
+
+struct pci_api ecam_api = PCIAPI_RUNTIME ( ecam );
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index 5891e42ff..7953aaedd 100644
--- a/src/drivers/bus/pci.c
+++ b/src/drivers/bus/pci.c
@@ -229,46 +229,55 @@ int pci_read_config ( struct pci_device *pci ) {
*
* @v pci PCI device to fill in
* @v busdevfn Starting bus:dev.fn address
- * @ret busdevfn Bus:dev.fn address of next PCI device, or negative error
+ * @ret busdevfn Bus:dev.fn address of next PCI device
+ * @ret rc Return status code
*/
-int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
- static unsigned int end;
- unsigned int sub_end;
+int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn ) {
+ static struct pci_range range;
uint8_t hdrtype;
uint8_t sub;
+ uint32_t end;
+ unsigned int count;
int rc;
- /* Determine number of PCI buses */
- if ( ! end )
- end = PCI_BUSDEVFN ( 0, pci_num_bus(), 0, 0 );
-
/* Find next PCI device, if any */
- for ( ; busdevfn < end ; busdevfn++ ) {
+ do {
+ /* Find next PCI bus:dev.fn address range, if necessary */
+ if ( ( *busdevfn - range.start ) >= range.count ) {
+ pci_discover ( *busdevfn, &range );
+ if ( *busdevfn < range.start )
+ *busdevfn = range.start;
+ if ( ( *busdevfn - range.start ) >= range.count )
+ break;
+ }
/* Check for PCI device existence */
memset ( pci, 0, sizeof ( *pci ) );
- pci_init ( pci, busdevfn );
+ pci_init ( pci, *busdevfn );
if ( ( rc = pci_read_config ( pci ) ) != 0 )
continue;
- /* If device is a bridge, expand the number of PCI
- * buses as needed.
+ /* If device is a bridge, expand the PCI bus:dev.fn
+ * address range as needed.
*/
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
hdrtype &= PCI_HEADER_TYPE_MASK;
if ( hdrtype == PCI_HEADER_TYPE_BRIDGE ) {
pci_read_config_byte ( pci, PCI_SUBORDINATE, &sub );
- sub_end = PCI_BUSDEVFN ( 0, ( sub + 1 ), 0, 0 );
- if ( end < sub_end ) {
+ end = PCI_BUSDEVFN ( PCI_SEG ( *busdevfn ),
+ ( sub + 1 ), 0, 0 );
+ count = ( end - range.start );
+ if ( count > range.count ) {
DBGC ( pci, PCI_FMT " found subordinate bus "
"%#02x\n", PCI_ARGS ( pci ), sub );
- end = sub_end;
+ range.count = count;
}
}
/* Return this device */
- return busdevfn;
- }
+ return 0;
+
+ } while ( ++(*busdevfn) );
return -ENODEV;
}
@@ -348,11 +357,10 @@ void pci_remove ( struct pci_device *pci ) {
*/
static int pcibus_probe ( struct root_device *rootdev ) {
struct pci_device *pci = NULL;
- int busdevfn = 0;
+ uint32_t busdevfn = 0;
int rc;
- for ( busdevfn = 0 ; 1 ; busdevfn++ ) {
-
+ do {
/* Allocate struct pci_device */
if ( ! pci )
pci = malloc ( sizeof ( *pci ) );
@@ -362,8 +370,7 @@ static int pcibus_probe ( struct root_device *rootdev ) {
}
/* Find next PCI device, if any */
- busdevfn = pci_find_next ( pci, busdevfn );
- if ( busdevfn < 0 )
+ if ( ( rc = pci_find_next ( pci, &busdevfn ) ) != 0 )
break;
/* Look for a driver */
@@ -386,7 +393,8 @@ static int pcibus_probe ( struct root_device *rootdev ) {
/* Not registered; re-use struct pci_device */
list_del ( &pci->dev.siblings );
}
- }
+
+ } while ( ++busdevfn );
free ( pci );
return 0;
diff --git a/src/drivers/bus/pcibridge.c b/src/drivers/bus/pcibridge.c
new file mode 100644
index 000000000..d2763faf9
--- /dev/null
+++ b/src/drivers/bus/pcibridge.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/pcibridge.h>
+
+/** @file
+ *
+ * PCI-to-PCI bridge
+ *
+ */
+
+/** List of all PCI bridges */
+static LIST_HEAD ( pcibridges );
+
+/**
+ * Find bridge attached to a PCI device
+ *
+ * @v pci PCI device
+ * @ret bridge PCI bridge, or NULL
+ */
+struct pci_bridge * pcibridge_find ( struct pci_device *pci ) {
+ unsigned int bus = PCI_BUS ( pci->busdevfn );
+ struct pci_bridge *bridge;
+
+ /* Find matching bridge */
+ list_for_each_entry ( bridge, &pcibridges, list ) {
+ if ( bus == bridge->secondary )
+ return bridge;
+ }
+
+ return NULL;
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int pcibridge_probe ( struct pci_device *pci ) {
+ struct pci_bridge *bridge;
+ uint16_t base;
+ uint16_t limit;
+ int rc;
+
+ /* Allocate and initialise structure */
+ bridge = zalloc ( sizeof ( *bridge ) );
+ if ( ! bridge ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ bridge->pci = pci;
+
+ /* Read configuration */
+ pci_read_config_dword ( pci, PCI_PRIMARY, &bridge->buses );
+ cpu_to_le32s ( &buses );
+ pci_read_config_word ( pci, PCI_MEM_BASE, &base );
+ bridge->membase = ( ( base & ~PCI_MEM_MASK ) << 16 );
+ pci_read_config_word ( pci, PCI_MEM_LIMIT, &limit );
+ bridge->memlimit = ( ( ( ( limit | PCI_MEM_MASK ) + 1 ) << 16 ) - 1 );
+ DBGC ( bridge, "BRIDGE " PCI_FMT " bus %02x to [%02x,%02x) mem "
+ "[%08x,%08x)\n", PCI_ARGS ( pci ), bridge->primary,
+ bridge->secondary, bridge->subordinate, bridge->membase,
+ bridge->memlimit );
+
+ /* Add to list of PCI bridges */
+ list_add ( &bridge->list, &pcibridges );
+
+ pci_set_drvdata ( pci, bridge );
+ return 0;
+
+ free ( bridge );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void pcibridge_remove ( struct pci_device *pci ) {
+ struct pci_bridge *bridge = pci_get_drvdata ( pci );
+
+ /* Remove from list of bridges */
+ list_del ( &bridge->list );
+
+ /* Free device */
+ free ( bridge );
+}
+
+/** Bridge PCI device IDs */
+static struct pci_device_id pcibridge_ids[] = {
+ PCI_ROM ( 0xffff, 0xffff, "bridge", "Bridge", 0 ),
+};
+
+/** Bridge PCI driver */
+struct pci_driver pcibridge_driver __pci_driver = {
+ .ids = pcibridge_ids,
+ .id_count = ( sizeof ( pcibridge_ids ) / sizeof ( pcibridge_ids[0] ) ),
+ .class = PCI_CLASS_ID ( PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_PCI,
+ PCI_ANY_ID ),
+ .probe = pcibridge_probe,
+ .remove = pcibridge_remove,
+};
diff --git a/src/drivers/bus/pciextra.c b/src/drivers/bus/pciextra.c
index 3082d8a3d..23617bc9a 100644
--- a/src/drivers/bus/pciextra.c
+++ b/src/drivers/bus/pciextra.c
@@ -1,6 +1,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
+#include <ipxe/timer.h>
#include <ipxe/pci.h>
static int pci_find_capability_common ( struct pci_device *pci,
@@ -112,3 +113,24 @@ unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
size = size & ~( size - 1 );
return size;
}
+
+/**
+ * Perform PCI Express function-level reset (FLR)
+ *
+ * @v pci PCI device
+ * @v exp PCI Express Capability address
+ */
+void pci_reset ( struct pci_device *pci, unsigned int exp ) {
+ uint16_t control;
+
+ /* Perform a PCIe function-level reset */
+ pci_read_config_word ( pci, ( exp + PCI_EXP_DEVCTL ), &control );
+ control |= PCI_EXP_DEVCTL_FLR;
+ pci_write_config_word ( pci, ( exp + PCI_EXP_DEVCTL ), control );
+
+ /* Allow time for reset to complete */
+ mdelay ( PCI_EXP_FLR_DELAY_MS );
+
+ /* Re-enable device */
+ adjust_pci_device ( pci );
+}
diff --git a/src/drivers/net/ecm.c b/src/drivers/net/ecm.c
index 826b3b16d..68ac962ab 100644
--- a/src/drivers/net/ecm.c
+++ b/src/drivers/net/ecm.c
@@ -84,24 +84,18 @@ ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
*
* @v func USB function
* @v desc Ethernet functional descriptor
- * @v hw_addr Hardware address to fill in
+ * @v netdev Network device
* @ret rc Return status code
*/
int ecm_fetch_mac ( struct usb_function *func,
- struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
+ struct ecm_ethernet_descriptor *desc,
+ struct net_device *netdev ) {
struct usb_device *usb = func->usb;
char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
+ uint8_t amac[ETH_ALEN];
int len;
int rc;
- /* Use system-specific MAC address, if present and not already used */
- if ( ( ( rc = acpi_mac ( hw_addr ) ) == 0 ) &&
- ! find_netdev_by_ll_addr ( &ethernet_protocol, hw_addr ) ) {
- DBGC ( usb, "USB %s using system-specific MAC %s\n",
- func->name, eth_ntoa ( hw_addr ) );
- return 0;
- }
-
/* Fetch MAC address string */
len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
sizeof ( buf ) );
@@ -118,7 +112,7 @@ int ecm_fetch_mac ( struct usb_function *func,
}
/* Decode MAC address */
- len = base16_decode ( buf, hw_addr, ETH_ALEN );
+ len = base16_decode ( buf, netdev->hw_addr, ETH_ALEN );
if ( len < 0 ) {
rc = len;
DBGC ( usb, "USB %s could not decode ECM MAC \"%s\": %s\n",
@@ -126,6 +120,16 @@ int ecm_fetch_mac ( struct usb_function *func,
return rc;
}
+ /* Apply system-specific MAC address as current link-layer
+ * address, if present and not already used.
+ */
+ if ( ( ( rc = acpi_mac ( amac ) ) == 0 ) &&
+ ! find_netdev_by_ll_addr ( &ethernet_protocol, amac ) ) {
+ memcpy ( netdev->ll_addr, amac, ETH_ALEN );
+ DBGC ( usb, "USB %s using system-specific MAC %s\n",
+ func->name, eth_ntoa ( netdev->ll_addr ) );
+ }
+
return 0;
}
@@ -474,7 +478,7 @@ static int ecm_probe ( struct usb_function *func,
}
/* Fetch MAC address */
- if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
+ if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev ) ) != 0 ) {
DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
ecm, strerror ( rc ) );
goto err_fetch_mac;
diff --git a/src/drivers/net/ecm.h b/src/drivers/net/ecm.h
index 0ad3ddb95..a7d03cf94 100644
--- a/src/drivers/net/ecm.h
+++ b/src/drivers/net/ecm.h
@@ -88,6 +88,6 @@ ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
struct usb_interface_descriptor *interface );
extern int ecm_fetch_mac ( struct usb_function *func,
struct ecm_ethernet_descriptor *desc,
- uint8_t *hw_addr );
+ struct net_device *netdev );
#endif /* _ECM_H */
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c
index 85da1c090..22e7e1e30 100644
--- a/src/drivers/net/ena.c
+++ b/src/drivers/net/ena.c
@@ -24,6 +24,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@@ -34,6 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/pci.h>
+#include <ipxe/pcibridge.h>
+#include <ipxe/version.h>
#include "ena.h"
/** @file
@@ -359,6 +362,7 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq,
struct ena_cq *cq ) {
union ena_aq_req *req;
union ena_acq_rsp *rsp;
+ unsigned int i;
int rc;
/* Allocate submission queue entries */
@@ -391,11 +395,20 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq,
sq->prod = 0;
sq->phase = ENA_SQE_PHASE;
- DBGC ( ena, "ENA %p %s SQ%d at [%08lx,%08lx) db +%04x CQ%d\n",
+ /* Calculate fill level */
+ sq->fill = sq->max;
+ if ( sq->fill > cq->actual )
+ sq->fill = cq->actual;
+
+ /* Initialise buffer ID ring */
+ for ( i = 0 ; i < sq->count ; i++ )
+ sq->ids[i] = i;
+
+ DBGC ( ena, "ENA %p %s SQ%d at [%08lx,%08lx) fill %d db +%04x CQ%d\n",
ena, ena_direction ( sq->direction ), sq->id,
virt_to_phys ( sq->sqe.raw ),
( virt_to_phys ( sq->sqe.raw ) + sq->len ),
- sq->doorbell, cq->id );
+ sq->fill, sq->doorbell, cq->id );
return 0;
err_admin:
@@ -459,6 +472,7 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) {
req->header.opcode = ENA_CREATE_CQ;
req->create_cq.size = cq->size;
req->create_cq.count = cpu_to_le16 ( cq->requested );
+ req->create_cq.vector = cpu_to_le32 ( ENA_MSIX_NONE );
req->create_cq.address = cpu_to_le64 ( virt_to_bus ( cq->cqe.raw ) );
/* Issue request */
@@ -597,6 +611,32 @@ static int ena_get_device_attributes ( struct net_device *netdev ) {
}
/**
+ * Set host attributes
+ *
+ * @v ena ENA device
+ * @ret rc Return status code
+ */
+static int ena_set_host_attributes ( struct ena_nic *ena ) {
+ 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_HOST_ATTRIBUTES;
+ feature = &req->set_feature.feature;
+ feature->host.info = cpu_to_le64 ( virt_to_bus ( ena->info ) );
+
+ /* Issue request */
+ if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
* Get statistics (for debugging)
*
* @v ena ENA device
@@ -652,13 +692,14 @@ static void ena_refill_rx ( struct net_device *netdev ) {
struct ena_nic *ena = netdev->priv;
struct io_buffer *iobuf;
struct ena_rx_sqe *sqe;
- unsigned int index;
physaddr_t address;
size_t len = netdev->max_pkt_len;
unsigned int refilled = 0;
+ unsigned int index;
+ unsigned int id;
/* Refill queue */
- while ( ( ena->rx.sq.prod - ena->rx.cq.cons ) < ENA_RX_COUNT ) {
+ while ( ( ena->rx.sq.prod - ena->rx.cq.cons ) < ena->rx.sq.fill ) {
/* Allocate I/O buffer */
iobuf = alloc_iob ( len );
@@ -667,14 +708,15 @@ static void ena_refill_rx ( struct net_device *netdev ) {
break;
}
- /* Get next submission queue entry */
+ /* Get next submission queue entry and buffer ID */
index = ( ena->rx.sq.prod % ENA_RX_COUNT );
sqe = &ena->rx.sq.sqe.rx[index];
+ id = ena->rx_ids[index];
/* Construct submission queue entry */
address = virt_to_bus ( iobuf->data );
sqe->len = cpu_to_le16 ( len );
- sqe->id = cpu_to_le16 ( ena->rx.sq.prod );
+ sqe->id = cpu_to_le16 ( id );
sqe->address = cpu_to_le64 ( address );
wmb();
sqe->flags = ( ENA_SQE_FIRST | ENA_SQE_LAST | ENA_SQE_CPL |
@@ -686,10 +728,10 @@ static void ena_refill_rx ( struct net_device *netdev ) {
ena->rx.sq.phase ^= ENA_SQE_PHASE;
/* Record I/O buffer */
- assert ( ena->rx_iobuf[index] == NULL );
- ena->rx_iobuf[index] = iobuf;
+ assert ( ena->rx_iobuf[id] == NULL );
+ ena->rx_iobuf[id] = iobuf;
- DBGC2 ( ena, "ENA %p RX %d at [%08llx,%08llx)\n", ena, sqe->id,
+ DBGC2 ( ena, "ENA %p RX %d at [%08llx,%08llx)\n", ena, id,
( ( unsigned long long ) address ),
( ( unsigned long long ) address + len ) );
refilled++;
@@ -778,23 +820,25 @@ static void ena_close ( struct net_device *netdev ) {
static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
struct ena_nic *ena = netdev->priv;
struct ena_tx_sqe *sqe;
- unsigned int index;
physaddr_t address;
+ unsigned int index;
+ unsigned int id;
size_t len;
/* Get next submission queue entry */
- if ( ( ena->tx.sq.prod - ena->tx.cq.cons ) >= ENA_TX_COUNT ) {
+ if ( ( ena->tx.sq.prod - ena->tx.cq.cons ) >= ena->tx.sq.fill ) {
DBGC ( ena, "ENA %p out of transmit descriptors\n", ena );
return -ENOBUFS;
}
index = ( ena->tx.sq.prod % ENA_TX_COUNT );
sqe = &ena->tx.sq.sqe.tx[index];
+ id = ena->tx_ids[index];
/* Construct submission queue entry */
address = virt_to_bus ( iobuf->data );
len = iob_len ( iobuf );
sqe->len = cpu_to_le16 ( len );
- sqe->id = ena->tx.sq.prod;
+ sqe->id = cpu_to_le16 ( id );
sqe->address = cpu_to_le64 ( address );
wmb();
sqe->flags = ( ENA_SQE_FIRST | ENA_SQE_LAST | ENA_SQE_CPL |
@@ -806,10 +850,14 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
if ( ( ena->tx.sq.prod % ENA_TX_COUNT ) == 0 )
ena->tx.sq.phase ^= ENA_SQE_PHASE;
+ /* Record I/O buffer */
+ assert ( ena->tx_iobuf[id] == NULL );
+ ena->tx_iobuf[id] = iobuf;
+
/* Ring doorbell */
writel ( ena->tx.sq.prod, ( ena->regs + ena->tx.sq.doorbell ) );
- DBGC2 ( ena, "ENA %p TX %d at [%08llx,%08llx)\n", ena, sqe->id,
+ DBGC2 ( ena, "ENA %p TX %d at [%08llx,%08llx)\n", ena, id,
( ( unsigned long long ) address ),
( ( unsigned long long ) address + len ) );
return 0;
@@ -823,7 +871,9 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
static void ena_poll_tx ( struct net_device *netdev ) {
struct ena_nic *ena = netdev->priv;
struct ena_tx_cqe *cqe;
+ struct io_buffer *iobuf;
unsigned int index;
+ unsigned int id;
/* Check for completed packets */
while ( ena->tx.cq.cons != ena->tx.sq.prod ) {
@@ -835,16 +885,24 @@ static void ena_poll_tx ( struct net_device *netdev ) {
/* Stop if completion queue entry is empty */
if ( ( cqe->flags ^ ena->tx.cq.phase ) & ENA_CQE_PHASE )
return;
- DBGC2 ( ena, "ENA %p TX %d complete\n", ena,
- ( le16_to_cpu ( cqe->id ) >> 2 /* Don't ask */ ) );
/* Increment consumer counter */
ena->tx.cq.cons++;
if ( ! ( ena->tx.cq.cons & ena->tx.cq.mask ) )
ena->tx.cq.phase ^= ENA_CQE_PHASE;
+ /* Identify and free buffer ID */
+ id = ENA_TX_CQE_ID ( le16_to_cpu ( cqe->id ) );
+ ena->tx_ids[index] = id;
+
+ /* Identify I/O buffer */
+ iobuf = ena->tx_iobuf[id];
+ assert ( iobuf != NULL );
+ ena->tx_iobuf[id] = NULL;
+
/* Complete transmit */
- netdev_tx_complete_next ( netdev );
+ DBGC2 ( ena, "ENA %p TX %d complete\n", ena, id );
+ netdev_tx_complete ( netdev, iobuf );
}
}
@@ -858,13 +916,14 @@ static void ena_poll_rx ( struct net_device *netdev ) {
struct ena_rx_cqe *cqe;
struct io_buffer *iobuf;
unsigned int index;
+ unsigned int id;
size_t len;
/* Check for received packets */
while ( ena->rx.cq.cons != ena->rx.sq.prod ) {
/* Get next completion queue entry */
- index = ( ena->rx.cq.cons % ENA_RX_COUNT );
+ index = ( ena->rx.cq.cons & ena->rx.cq.mask );
cqe = &ena->rx.cq.cqe.rx[index];
/* Stop if completion queue entry is empty */
@@ -876,15 +935,20 @@ static void ena_poll_rx ( struct net_device *netdev ) {
if ( ! ( ena->rx.cq.cons & ena->rx.cq.mask ) )
ena->rx.cq.phase ^= ENA_CQE_PHASE;
+ /* Identify and free buffer ID */
+ id = le16_to_cpu ( cqe->id );
+ ena->rx_ids[index] = id;
+
/* Populate I/O buffer */
- iobuf = ena->rx_iobuf[index];
- ena->rx_iobuf[index] = NULL;
+ iobuf = ena->rx_iobuf[id];
+ assert ( iobuf != NULL );
+ ena->rx_iobuf[id] = NULL;
len = le16_to_cpu ( cqe->len );
iob_put ( iobuf, len );
/* Hand off to network stack */
DBGC2 ( ena, "ENA %p RX %d complete (length %zd)\n",
- ena, le16_to_cpu ( cqe->id ), len );
+ ena, id, len );
netdev_rx ( netdev, iobuf );
}
}
@@ -922,6 +986,45 @@ static struct net_device_operations ena_operations = {
*/
/**
+ * Assign memory BAR
+ *
+ * @v ena ENA device
+ * @v pci PCI device
+ * @ret rc Return status code
+ *
+ * Some BIOSes in AWS EC2 are observed to fail to assign a base
+ * address to the ENA device. The device is the only device behind
+ * its bridge, and the BIOS does assign a memory window to the bridge.
+ * We therefore place the device at the start of the memory window.
+ */
+static int ena_membase ( struct ena_nic *ena, struct pci_device *pci ) {
+ struct pci_bridge *bridge;
+
+ /* Locate PCI bridge */
+ bridge = pcibridge_find ( pci );
+ if ( ! bridge ) {
+ DBGC ( ena, "ENA %p found no PCI bridge\n", ena );
+ return -ENOTCONN;
+ }
+
+ /* Sanity check */
+ if ( PCI_SLOT ( pci->busdevfn ) || PCI_FUNC ( pci->busdevfn ) ) {
+ DBGC ( ena, "ENA %p at " PCI_FMT " may not be only device "
+ "on bus\n", ena, PCI_ARGS ( pci ) );
+ return -ENOTSUP;
+ }
+
+ /* Place device at start of memory window */
+ pci_write_config_dword ( pci, PCI_BASE_ADDRESS_0, bridge->membase );
+ pci->membase = bridge->membase;
+ DBGC ( ena, "ENA %p at " PCI_FMT " claiming bridge " PCI_FMT " mem "
+ "%08x\n", ena, PCI_ARGS ( pci ), PCI_ARGS ( bridge->pci ),
+ bridge->membase );
+
+ return 0;
+}
+
+/**
* Probe PCI device
*
* @v pci PCI device
@@ -930,6 +1033,7 @@ static struct net_device_operations ena_operations = {
static int ena_probe ( struct pci_device *pci ) {
struct net_device *netdev;
struct ena_nic *ena;
+ struct ena_host_info *info;
int rc;
/* Allocate and initialise net device */
@@ -946,16 +1050,20 @@ static int ena_probe ( struct pci_device *pci ) {
ena->acq.phase = ENA_ACQ_PHASE;
ena_cq_init ( &ena->tx.cq, ENA_TX_COUNT,
sizeof ( ena->tx.cq.cqe.tx[0] ) );
- ena_sq_init ( &ena->tx.sq, ENA_SQ_TX, ENA_TX_COUNT,
- sizeof ( ena->tx.sq.sqe.tx[0] ) );
+ ena_sq_init ( &ena->tx.sq, ENA_SQ_TX, ENA_TX_COUNT, ENA_TX_COUNT,
+ sizeof ( ena->tx.sq.sqe.tx[0] ), ena->tx_ids );
ena_cq_init ( &ena->rx.cq, ENA_RX_COUNT,
sizeof ( ena->rx.cq.cqe.rx[0] ) );
- ena_sq_init ( &ena->rx.sq, ENA_SQ_RX, ENA_RX_COUNT,
- sizeof ( ena->rx.sq.sqe.rx[0] ) );
+ ena_sq_init ( &ena->rx.sq, ENA_SQ_RX, ENA_RX_COUNT, ENA_RX_FILL,
+ sizeof ( ena->rx.sq.sqe.rx[0] ), ena->rx_ids );
/* Fix up PCI device */
adjust_pci_device ( pci );
+ /* Fix up PCI BAR if left unassigned by BIOS */
+ if ( ( ! pci->membase ) && ( ( rc = ena_membase ( ena, pci ) ) != 0 ) )
+ goto err_membase;
+
/* Map registers */
ena->regs = pci_ioremap ( pci, pci->membase, ENA_BAR_SIZE );
if ( ! ena->regs ) {
@@ -963,6 +1071,25 @@ static int ena_probe ( struct pci_device *pci ) {
goto err_ioremap;
}
+ /* Allocate and initialise host info */
+ info = malloc_phys ( PAGE_SIZE, PAGE_SIZE );
+ if ( ! info ) {
+ rc = -ENOMEM;
+ goto err_info;
+ }
+ ena->info = info;
+ memset ( info, 0, PAGE_SIZE );
+ info->type = cpu_to_le32 ( ENA_HOST_INFO_TYPE_LINUX );
+ snprintf ( info->dist_str, sizeof ( info->dist_str ), "%s",
+ ( product_name[0] ? product_name : product_short_name ) );
+ snprintf ( info->kernel_str, sizeof ( info->kernel_str ), "%s",
+ product_version );
+ info->version = cpu_to_le32 ( ENA_HOST_INFO_VERSION_WTF );
+ info->spec = cpu_to_le16 ( ENA_HOST_INFO_SPEC_2_0 );
+ info->busdevfn = cpu_to_le16 ( pci->busdevfn );
+ DBGC2 ( ena, "ENA %p host info:\n", ena );
+ DBGC2_HDA ( ena, virt_to_phys ( info ), info, sizeof ( *info ) );
+
/* Reset the NIC */
if ( ( rc = ena_reset ( ena ) ) != 0 )
goto err_reset;
@@ -971,6 +1098,10 @@ static int ena_probe ( struct pci_device *pci ) {
if ( ( rc = ena_create_admin ( ena ) ) != 0 )
goto err_create_admin;
+ /* Set host attributes */
+ if ( ( rc = ena_set_host_attributes ( ena ) ) != 0 )
+ goto err_set_host_attributes;
+
/* Fetch MAC address */
if ( ( rc = ena_get_device_attributes ( netdev ) ) != 0 )
goto err_get_device_attributes;
@@ -989,12 +1120,16 @@ static int ena_probe ( struct pci_device *pci ) {
unregister_netdev ( netdev );
err_register_netdev:
err_get_device_attributes:
+ err_set_host_attributes:
ena_destroy_admin ( ena );
err_create_admin:
ena_reset ( ena );
err_reset:
+ free_phys ( ena->info, PAGE_SIZE );
+ err_info:
iounmap ( ena->regs );
err_ioremap:
+ err_membase:
netdev_nullify ( netdev );
netdev_put ( netdev );
err_alloc:
@@ -1019,6 +1154,9 @@ static void ena_remove ( struct pci_device *pci ) {
/* Reset card */
ena_reset ( ena );
+ /* Free host info */
+ free_phys ( ena->info, PAGE_SIZE );
+
/* Free network device */
iounmap ( ena->regs );
netdev_nullify ( netdev );
diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h
index 676c5b878..4e1896e86 100644
--- a/src/drivers/net/ena.h
+++ b/src/drivers/net/ena.h
@@ -28,7 +28,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ENA_TX_COUNT 16
/** Number of receive queue entries */
-#define ENA_RX_COUNT 16
+#define ENA_RX_COUNT 128
+
+/** Receive queue maximum fill level */
+#define ENA_RX_FILL 16
/** Base address low register offset */
#define ENA_BASE_LO 0x0
@@ -127,10 +130,86 @@ struct ena_device_attributes {
uint32_t mtu;
} __attribute__ (( packed ));
+/** Host attributes */
+#define ENA_HOST_ATTRIBUTES 28
+
+/** Host attributes */
+struct ena_host_attributes {
+ /** Host info base address */
+ uint64_t info;
+ /** Debug area base address */
+ uint64_t debug;
+ /** Debug area size */
+ uint32_t debug_len;
+} __attribute__ (( packed ));
+
+/** Host information */
+struct ena_host_info {
+ /** Operating system type */
+ uint32_t type;
+ /** Operating system distribution (string) */
+ char dist_str[128];
+ /** Operating system distribution (numeric) */
+ uint32_t dist;
+ /** Kernel version (string) */
+ char kernel_str[32];
+ /** Kernel version (numeric) */
+ uint32_t kernel;
+ /** Driver version */
+ uint32_t version;
+ /** Linux network device features */
+ uint64_t linux_features;
+ /** ENA specification version */
+ uint16_t spec;
+ /** PCI bus:dev.fn address */
+ uint16_t busdevfn;
+ /** Number of CPUs */
+ uint16_t cpus;
+ /** Reserved */
+ uint8_t reserved_a[2];
+ /** Supported features */
+ uint32_t features;
+} __attribute__ (( packed ));
+
+/** Linux operating system type
+ *
+ * There is a defined "iPXE" operating system type (with value 5).
+ * However, some very broken versions of the ENA firmware will refuse
+ * to allow a completion queue to be created if the "iPXE" type is
+ * used.
+ */
+#define ENA_HOST_INFO_TYPE_LINUX 1
+
+/** Driver version
+ *
+ * The driver version field is nominally used to report a version
+ * number outside of the VM for consumption by humans (and potentially
+ * by automated monitoring tools that could e.g. check for outdated
+ * versions with known security flaws).
+ *
+ * However, at some point in the development of the ENA firmware, some
+ * unknown person at AWS thought it would be sensible to apply a
+ * machine interpretation to this field and adjust the behaviour of
+ * the firmware based on its value, thereby creating a maintenance and
+ * debugging nightmare for all existing and future drivers.
+ *
+ * Hint to engineers: if you ever find yourself writing code of the
+ * form "if (version == SOME_MAGIC_NUMBER)" then something has gone
+ * very, very wrong. This *always* indicates that something is
+ * broken, either in your own code or in the code with which you are
+ * forced to interact.
+ */
+#define ENA_HOST_INFO_VERSION_WTF 0x00000002UL
+
+/** ENA specification version */
+#define ENA_HOST_INFO_SPEC_2_0 0x0200
+
/** Feature */
union ena_feature {
/** Device attributes */
struct ena_device_attributes device;
+ /** Host attributes */
+ struct ena_host_attributes host;
};
/** Submission queue direction */
@@ -230,6 +309,14 @@ struct ena_create_cq_req {
uint64_t address;
} __attribute__ (( packed ));
+/** Empty MSI-X vector
+ *
+ * Some versions of the ENA firmware will complain if the completion
+ * queue's MSI-X vector field is left empty, even though the queue
+ * configuration specifies that interrupts are not used.
+ */
+#define ENA_MSIX_NONE 0xffffffffUL
+
/** Create completion queue response */
struct ena_create_cq_rsp {
/** Header */
@@ -292,6 +379,27 @@ struct ena_get_feature_rsp {
union ena_feature feature;
} __attribute__ (( packed ));
+/** Set feature */
+#define ENA_SET_FEATURE 9
+
+/** Set feature request */
+struct ena_set_feature_req {
+ /** Header */
+ struct ena_aq_header header;
+ /** Length */
+ uint32_t len;
+ /** Address */
+ uint64_t address;
+ /** Flags */
+ uint8_t flags;
+ /** Feature identifier */
+ uint8_t id;
+ /** Reserved */
+ uint8_t reserved[2];
+ /** Feature */
+ union ena_feature feature;
+} __attribute__ (( packed ));
+
/** Get statistics */
#define ENA_GET_STATS 11
@@ -352,6 +460,8 @@ union ena_aq_req {
struct ena_destroy_cq_req destroy_cq;
/** Get feature */
struct ena_get_feature_req get_feature;
+ /** Set feature */
+ struct ena_set_feature_req set_feature;
/** Get statistics */
struct ena_get_stats_req get_stats;
/** Padding */
@@ -454,6 +564,9 @@ struct ena_tx_cqe {
uint16_t cons;
} __attribute__ (( packed ));
+/** Transmit completion request identifier */
+#define ENA_TX_CQE_ID(id) ( (id) >> 2 )
+
/** Receive completion queue entry */
struct ena_rx_cqe {
/** Reserved */
@@ -482,6 +595,8 @@ struct ena_sq {
/** Raw data */
void *raw;
} sqe;
+ /** Buffer IDs */
+ uint8_t *ids;
/** Doorbell register offset */
unsigned int doorbell;
/** Total length of entries */
@@ -496,6 +611,10 @@ struct ena_sq {
uint8_t direction;
/** Number of entries */
uint8_t count;
+ /** Maximum fill level */
+ uint8_t max;
+ /** Fill level (limited to completion queue size) */
+ uint8_t fill;
};
/**
@@ -504,15 +623,19 @@ struct ena_sq {
* @v sq Submission queue
* @v direction Direction
* @v count Number of entries
+ * @v max Maximum fill level
* @v size Size of each entry
+ * @v ids Buffer IDs
*/
static inline __attribute__ (( always_inline )) void
ena_sq_init ( struct ena_sq *sq, unsigned int direction, unsigned int count,
- size_t size ) {
+ unsigned int max, size_t size, uint8_t *ids ) {
sq->len = ( count * size );
sq->direction = direction;
sq->count = count;
+ sq->max = max;
+ sq->ids = ids;
}
/** Completion queue */
@@ -573,6 +696,8 @@ struct ena_qp {
struct ena_nic {
/** Registers */
void *regs;
+ /** Host info */
+ struct ena_host_info *info;
/** Admin queue */
struct ena_aq aq;
/** Admin completion queue */
@@ -581,7 +706,13 @@ struct ena_nic {
struct ena_qp tx;
/** Receive queue */
struct ena_qp rx;
- /** Receive I/O buffers */
+ /** Transmit buffer IDs */
+ uint8_t tx_ids[ENA_TX_COUNT];
+ /** Transmit I/O buffers, indexed by buffer ID */
+ struct io_buffer *tx_iobuf[ENA_TX_COUNT];
+ /** Receive buffer IDs */
+ uint8_t rx_ids[ENA_RX_COUNT];
+ /** Receive I/O buffers, indexed by buffer ID */
struct io_buffer *rx_iobuf[ENA_RX_COUNT];
};
diff --git a/src/drivers/net/ice.c b/src/drivers/net/ice.c
new file mode 100644
index 000000000..b5d66f1bb
--- /dev/null
+++ b/src/drivers/net/ice.c
@@ -0,0 +1,986 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/pci.h>
+#include "ice.h"
+
+/** @file
+ *
+ * Intel 100 Gigabit Ethernet network card driver
+ *
+ */
+
+/**
+ * Magic MAC address
+ *
+ * Used as the source address and promiscuous unicast destination
+ * address in the "add switch rules" command.
+ */
+static uint8_t ice_magic_mac[ETH_HLEN] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/******************************************************************************
+ *
+ * Admin queue
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get firmware version
+ *
+ * @v intelxl Intel device
+ * @ret rc Return status code
+ */
+static int ice_admin_version ( struct intelxl_nic *intelxl ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_version_params *version;
+ unsigned int api;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_VERSION );
+ version = &cmd->params.version;
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+ api = version->api.major;
+ DBGC ( intelxl, "ICE %p firmware v%d/%d.%d.%d API v%d/%d.%d.%d\n",
+ intelxl, version->firmware.branch, version->firmware.major,
+ version->firmware.minor, version->firmware.patch,
+ version->api.branch, version->api.major, version->api.minor,
+ version->api.patch );
+
+ /* Check for API compatibility */
+ if ( api > INTELXL_ADMIN_API_MAJOR ) {
+ DBGC ( intelxl, "ICE %p unsupported API v%d\n", intelxl, api );
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/**
+ * Get MAC address
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int ice_admin_mac_read ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_mac_read_params *read;
+ struct ice_admin_mac_read_address *mac;
+ union ice_admin_buffer *buf;
+ unsigned int i;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_MAC_READ );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->mac_read ) );
+ read = &cmd->params.mac_read;
+ buf = ice_admin_command_buffer ( intelxl );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ /* Check that MAC address is present in response */
+ if ( ! ( read->valid & INTELXL_ADMIN_MAC_READ_VALID_LAN ) ) {
+ DBGC ( intelxl, "ICE %p has no MAC address\n", intelxl );
+ return -ENOENT;
+ }
+
+ /* Identify MAC address */
+ for ( i = 0 ; i < read->count ; i++ ) {
+
+ /* Check for a LAN MAC address */
+ mac = &buf->mac_read.mac[i];
+ if ( mac->type != ICE_ADMIN_MAC_READ_TYPE_LAN )
+ continue;
+
+ /* Check that address is valid */
+ if ( ! is_valid_ether_addr ( mac->mac ) ) {
+ DBGC ( intelxl, "ICE %p has invalid MAC address "
+ "(%s)\n", intelxl, eth_ntoa ( mac->mac ) );
+ return -EINVAL;
+ }
+
+ /* Copy MAC address */
+ DBGC ( intelxl, "ICE %p has MAC address %s\n",
+ intelxl, eth_ntoa ( mac->mac ) );
+ memcpy ( netdev->hw_addr, mac->mac, ETH_ALEN );
+
+ return 0;
+ }
+
+ /* Missing LAN MAC address */
+ DBGC ( intelxl, "ICE %p has no LAN MAC address\n",
+ intelxl );
+ return -ENOENT;
+}
+
+/**
+ * Set MAC address
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int ice_admin_mac_write ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_mac_write_params *write;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_MAC_WRITE );
+ write = &cmd->params.mac_write;
+ memcpy ( write->mac, netdev->ll_addr, ETH_ALEN );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Get switch configuration
+ *
+ * @v intelxl Intel device
+ * @ret rc Return status code
+ */
+static int ice_admin_switch ( struct intelxl_nic *intelxl ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_switch_params *sw;
+ union ice_admin_buffer *buf;
+ uint16_t next = 0;
+ uint16_t seid;
+ uint16_t type;
+ int rc;
+
+ /* Get each configuration in turn */
+ do {
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->sw ) );
+ sw = &cmd->params.sw;
+ sw->next = next;
+ buf = ice_admin_command_buffer ( intelxl );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+ seid = le16_to_cpu ( buf->sw.cfg[0].seid );
+
+ /* Dump raw configuration */
+ DBGC2 ( intelxl, "ICE %p SEID %#04x:\n", intelxl, seid );
+ DBGC2_HDA ( intelxl, 0, &buf->sw.cfg[0],
+ sizeof ( buf->sw.cfg[0] ) );
+
+ /* Parse response */
+ type = ( seid & ICE_ADMIN_SWITCH_TYPE_MASK );
+ if ( type == ICE_ADMIN_SWITCH_TYPE_VSI ) {
+ intelxl->vsi = ( seid & ~ICE_ADMIN_SWITCH_TYPE_MASK );
+ DBGC ( intelxl, "ICE %p VSI %#04x uplink %#04x func "
+ "%#04x\n", intelxl, intelxl->vsi,
+ le16_to_cpu ( buf->sw.cfg[0].uplink ),
+ le16_to_cpu ( buf->sw.cfg[0].func ) );
+ }
+
+ } while ( ( next = sw->next ) );
+
+ /* Check that we found a VSI */
+ if ( ! intelxl->vsi ) {
+ DBGC ( intelxl, "ICE %p has no VSI\n", intelxl );
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+/**
+ * Add switch rules
+ *
+ * @v intelxl Intel device
+ * @v mac MAC address
+ * @ret rc Return status code
+ */
+static int ice_admin_rules ( struct intelxl_nic *intelxl, uint8_t *mac ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_rules_params *rules;
+ union ice_admin_buffer *buf;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( ICE_ADMIN_ADD_RULES );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF | INTELXL_ADMIN_FL_RD );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->rules ) );
+ rules = &cmd->params.rules;
+ rules->count = cpu_to_le16 ( 1 );
+ buf = ice_admin_command_buffer ( intelxl );
+ buf->rules.recipe = cpu_to_le16 ( ICE_ADMIN_RULES_RECIPE_PROMISC );
+ buf->rules.port = cpu_to_le16 ( intelxl->port );
+ buf->rules.action =
+ cpu_to_le32 ( ICE_ADMIN_RULES_ACTION_VALID |
+ ICE_ADMIN_RULES_ACTION_VSI ( intelxl->vsi ) );
+ buf->rules.len = cpu_to_le16 ( sizeof ( buf->rules.hdr ) );
+ memcpy ( buf->rules.hdr.eth.h_dest, mac, ETH_ALEN );
+ memcpy ( buf->rules.hdr.eth.h_source, ice_magic_mac, ETH_ALEN );
+ buf->rules.hdr.eth.h_protocol = htons ( ETH_P_8021Q );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Check if scheduler node is a parent (i.e. non-leaf) node
+ *
+ * @v branch Scheduler topology branch
+ * @v node Scheduler topology node
+ * @ret child Any child node, or NULL if not found
+ */
+static struct ice_admin_schedule_node *
+ice_admin_schedule_is_parent ( struct ice_admin_schedule_branch *branch,
+ struct ice_admin_schedule_node *node ) {
+ unsigned int count = le16_to_cpu ( branch->count );
+ struct ice_admin_schedule_node *child;
+ unsigned int i;
+
+ /* Find a child element, if any */
+ for ( i = 0 ; i < count ; i++ ) {
+ child = &branch->node[i];
+ if ( child->parent == node->teid )
+ return child;
+ }
+
+ return NULL;
+}
+
+/**
+ * Query default scheduling tree topology
+ *
+ * @v intelxl Intel device
+ * @ret rc Return status code
+ */
+static int ice_admin_schedule ( struct intelxl_nic *intelxl ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_schedule_params *sched;
+ struct ice_admin_schedule_branch *branch;
+ struct ice_admin_schedule_node *node;
+ union ice_admin_buffer *buf;
+ int i;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( ICE_ADMIN_SCHEDULE );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->sched ) );
+ sched = &cmd->params.sched;
+ buf = ice_admin_command_buffer ( intelxl );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ /* Sanity checks */
+ if ( ! sched->branches ) {
+ DBGC ( intelxl, "ICE %p topology has no branches\n", intelxl );
+ return -EINVAL;
+ }
+ branch = buf->sched.branch;
+
+ /* Identify leaf node */
+ for ( i = ( le16_to_cpu ( branch->count ) - 1 ) ; i >= 0 ; i-- ) {
+ node = &branch->node[i];
+ if ( ! ice_admin_schedule_is_parent ( branch, node ) ) {
+ intelxl->teid = le32_to_cpu ( node->teid );
+ DBGC2 ( intelxl, "ICE %p TEID %#08x type %d\n",
+ intelxl, intelxl->teid, node->config.type );
+ break;
+ }
+ }
+ if ( ! intelxl->teid ) {
+ DBGC ( intelxl, "ICE %p found no leaf TEID\n", intelxl );
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Restart autonegotiation
+ *
+ * @v intelxl Intel device
+ * @ret rc Return status code
+ */
+static int ice_admin_autoneg ( struct intelxl_nic *intelxl ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_autoneg_params *autoneg;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_AUTONEG );
+ autoneg = &cmd->params.autoneg;
+ autoneg->flags = ( INTELXL_ADMIN_AUTONEG_FL_RESTART |
+ INTELXL_ADMIN_AUTONEG_FL_ENABLE );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Get link status
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int ice_admin_link ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_link_params *link;
+ union ice_admin_buffer *buf;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_LINK );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->link ) );
+ link = &cmd->params.link;
+ link->notify = INTELXL_ADMIN_LINK_NOTIFY;
+ buf = ice_admin_command_buffer ( intelxl );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+ DBGC ( intelxl, "ICE %p speed %#02x status %#02x\n",
+ intelxl, le16_to_cpu ( buf->link.speed ), buf->link.status );
+
+ /* Update network device */
+ if ( buf->link.status & INTELXL_ADMIN_LINK_UP ) {
+ netdev_link_up ( netdev );
+ } else {
+ netdev_link_down ( netdev );
+ }
+
+ return 0;
+}
+
+/**
+ * Handle admin event
+ *
+ * @v netdev Network device
+ * @v xlevt Event descriptor
+ * @v xlbuf Data buffer
+ */
+static void ice_admin_event ( struct net_device *netdev,
+ struct intelxl_admin_descriptor *xlevt,
+ union intelxl_admin_buffer *xlbuf __unused ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct ice_admin_descriptor *evt =
+ container_of ( xlevt, struct ice_admin_descriptor, xl );
+
+ /* Ignore unrecognised events */
+ if ( evt->opcode != cpu_to_le16 ( INTELXL_ADMIN_LINK ) ) {
+ DBGC ( intelxl, "INTELXL %p unrecognised event opcode "
+ "%#04x\n", intelxl, le16_to_cpu ( evt->opcode ) );
+ return;
+ }
+
+ /* Update link status */
+ ice_admin_link ( netdev );
+}
+
+/**
+ * Add transmit queue
+ *
+ * @v intelxl Intel device
+ * @v ring Descriptor ring
+ * @ret rc Return status code
+ */
+static int ice_admin_add_txq ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_add_txq_params *add_txq;
+ union ice_admin_buffer *buf;
+ struct ice_context_tx *ctx;
+ struct ice_schedule_tx *sched;
+ physaddr_t address;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( ICE_ADMIN_ADD_TXQ );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->add_txq ) );
+ add_txq = &cmd->params.add_txq;
+ add_txq->count = 1;
+ buf = ice_admin_command_buffer ( intelxl );
+ buf->add_txq.parent = cpu_to_le32 ( intelxl->teid );
+ buf->add_txq.count = 1;
+ ctx = &buf->add_txq.ctx;
+ address = dma ( &ring->map, ring->desc.raw );
+ ctx->base_port =
+ cpu_to_le64 ( ICE_TXQ_BASE_PORT ( address, intelxl->port ) );
+ ctx->pf_type = cpu_to_le16 ( ICE_TXQ_PF_TYPE ( intelxl->pf ) );
+ ctx->vsi = cpu_to_le16 ( intelxl->vsi );
+ ctx->len = cpu_to_le16 ( ICE_TXQ_LEN ( INTELXL_TX_NUM_DESC ) );
+ ctx->flags = cpu_to_le16 ( ICE_TXQ_FL_TSO | ICE_TXQ_FL_LEGACY );
+ sched = &buf->add_txq.sched;
+ sched->sections = ( ICE_SCHEDULE_GENERIC | ICE_SCHEDULE_COMMIT |
+ ICE_SCHEDULE_EXCESS );
+ sched->commit_weight = cpu_to_le16 ( ICE_SCHEDULE_WEIGHT );
+ sched->excess_weight = cpu_to_le16 ( ICE_SCHEDULE_WEIGHT );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+ DBGC ( intelxl, "ICE %p added TEID %#04x\n",
+ intelxl, le32_to_cpu ( buf->add_txq.teid ) );
+
+ return 0;
+}
+
+/**
+ * Disable transmit queue
+ *
+ * @v intelxl Intel device
+ * @v ring Descriptor ring
+ * @ret rc Return status code
+ */
+static int ice_admin_disable_txq ( struct intelxl_nic *intelxl ) {
+ struct ice_admin_descriptor *cmd;
+ struct ice_admin_disable_txq_params *disable_txq;
+ union ice_admin_buffer *buf;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = ice_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( ICE_ADMIN_DISABLE_TXQ );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->disable_txq ) );
+ disable_txq = &cmd->params.disable_txq;
+ disable_txq->flags = ICE_TXQ_FL_FLUSH;
+ disable_txq->count = 1;
+ disable_txq->timeout = ICE_TXQ_TIMEOUT;
+ buf = ice_admin_command_buffer ( intelxl );
+ buf->disable_txq.parent = cpu_to_le32 ( intelxl->teid );
+ buf->disable_txq.count = 1;
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Dump transmit queue context (for debugging)
+ *
+ * @v intelxl Intel device
+ */
+static void ice_dump_tx ( struct intelxl_nic *intelxl ) {
+ uint32_t ctx[ sizeof ( struct ice_context_tx ) / sizeof ( uint32_t ) ];
+ uint32_t stat;
+ unsigned int i;
+
+ /* Do nothing unless debug output is enabled */
+ if ( ! DBG_EXTRA )
+ return;
+
+ /* Trigger reading of transmit context */
+ writel ( ( ICE_GLCOMM_QTX_CNTX_CTL_CMD_READ |
+ ICE_GLCOMM_QTX_CNTX_CTL_EXEC ),
+ intelxl->regs + ICE_GLCOMM_QTX_CNTX_CTL );
+
+ /* Wait for operation to complete */
+ for ( i = 0 ; i < INTELXL_CTX_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if operation is complete */
+ stat = readl ( intelxl->regs + ICE_GLCOMM_QTX_CNTX_STAT );
+ if ( ! ( stat & ICE_GLCOMM_QTX_CNTX_BUSY ) )
+ break;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ /* Read context registers */
+ for ( i = 0 ; i < ( sizeof ( ctx ) / sizeof ( ctx[0] ) ) ; i++ ) {
+ ctx[i] = cpu_to_le32 ( readl ( intelxl->regs +
+ ICE_GLCOMM_QTX_CNTX_DATA ( i )));
+ }
+
+ /* Dump context */
+ DBGC2 ( intelxl, "ICE %p TX context:\n", intelxl );
+ DBGC2_HDA ( intelxl, 0, ctx, sizeof ( ctx ) );
+}
+
+/**
+ * Dump receive queue context (for debugging)
+ *
+ * @v intelxl Intel device
+ */
+static void ice_dump_rx ( struct intelxl_nic *intelxl ) {
+ uint32_t ctx[ sizeof ( struct intelxl_context_rx ) /
+ sizeof ( uint32_t ) ];
+ unsigned int i;
+
+ /* Do nothing unless debug output is enabled */
+ if ( ! DBG_EXTRA )
+ return;
+
+ /* Read context registers */
+ for ( i = 0 ; i < ( sizeof ( ctx ) / sizeof ( ctx[0] ) ) ; i++ ) {
+ ctx[i] = cpu_to_le32 ( readl ( intelxl->regs +
+ ICE_QRX_CONTEXT ( i ) ) );
+ }
+
+ /* Dump context */
+ DBGC2 ( intelxl, "ICE %p RX context:\n", intelxl );
+ DBGC2_HDA ( intelxl, 0, ctx, sizeof ( ctx ) );
+}
+
+/**
+ * Create transmit queue
+ *
+ * @v intelxl Intel device
+ * @v ring Descriptor ring
+ * @ret rc Return status code
+ */
+static int ice_create_tx ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring ) {
+ int rc;
+
+ /* Allocate descriptor ring */
+ if ( ( rc = intelxl_alloc_ring ( intelxl, ring ) ) != 0 )
+ goto err_alloc;
+
+ /* Add transmit queue */
+ if ( ( rc = ice_admin_add_txq ( intelxl, ring ) ) != 0 )
+ goto err_add_txq;
+
+ return 0;
+
+ err_add_txq:
+ intelxl_free_ring ( intelxl, ring );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Destroy transmit queue
+ *
+ * @v intelxl Intel device
+ * @v ring Descriptor ring
+ * @ret rc Return status code
+ */
+static void ice_destroy_tx ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring ) {
+ int rc;
+
+ /* Disable transmit queue */
+ if ( ( rc = ice_admin_disable_txq ( intelxl ) ) != 0 ) {
+ /* Leak memory; there's nothing else we can do */
+ return;
+ }
+
+ /* Free descriptor ring */
+ intelxl_free_ring ( intelxl, ring );
+}
+
+/**
+ * Program receive queue context
+ *
+ * @v intelxl Intel device
+ * @v address Descriptor ring base address
+ * @ret rc Return status code
+ */
+static int ice_context_rx ( struct intelxl_nic *intelxl,
+ physaddr_t address ) {
+ union {
+ struct intelxl_context_rx rx;
+ uint32_t raw[ sizeof ( struct intelxl_context_rx ) /
+ sizeof ( uint32_t ) ];
+ } ctx;
+ uint64_t base_count;
+ unsigned int i;
+
+ /* Initialise context */
+ memset ( &ctx, 0, sizeof ( ctx ) );
+ base_count = INTELXL_CTX_RX_BASE_COUNT ( address, INTELXL_RX_NUM_DESC );
+ ctx.rx.base_count = cpu_to_le64 ( base_count );
+ ctx.rx.len = cpu_to_le16 ( INTELXL_CTX_RX_LEN ( intelxl->mfs ) );
+ ctx.rx.flags = ( INTELXL_CTX_RX_FL_DSIZE | INTELXL_CTX_RX_FL_CRCSTRIP );
+ ctx.rx.mfs = cpu_to_le16 ( INTELXL_CTX_RX_MFS ( intelxl->mfs ) );
+
+ /* Write context registers */
+ for ( i = 0 ; i < ( sizeof ( ctx ) / sizeof ( ctx.raw[0] ) ) ; i++ ) {
+ writel ( le32_to_cpu ( ctx.raw[i] ),
+ ( intelxl->regs + ICE_QRX_CONTEXT ( i ) ) );
+ }
+
+ return 0;
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int ice_open ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ int rc;
+
+ /* Calculate maximum frame size */
+ intelxl->mfs = ( ( ETH_HLEN + netdev->mtu + 4 /* CRC */ +
+ INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
+
+ /* Set MAC address */
+ if ( ( rc = ice_admin_mac_write ( netdev ) ) != 0 )
+ goto err_mac_write;
+
+ /* Set maximum frame size */
+ if ( ( rc = intelxl_admin_mac_config ( intelxl ) ) != 0 )
+ goto err_mac_config;
+
+ /* Create receive descriptor ring */
+ if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 )
+ goto err_create_rx;
+
+ /* Create transmit descriptor ring */
+ if ( ( rc = ice_create_tx ( intelxl, &intelxl->tx ) ) != 0 )
+ goto err_create_tx;
+
+ /* Restart autonegotiation */
+ ice_admin_autoneg ( intelxl );
+
+ /* Update link state */
+ ice_admin_link ( netdev );
+
+ return 0;
+
+ ice_destroy_tx ( intelxl, &intelxl->tx );
+ err_create_tx:
+ intelxl_destroy_ring ( intelxl, &intelxl->rx );
+ err_create_rx:
+ err_mac_config:
+ err_mac_write:
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void ice_close ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+
+ /* Dump contexts (for debugging) */
+ ice_dump_tx ( intelxl );
+ ice_dump_rx ( intelxl );
+
+ /* Destroy transmit descriptor ring */
+ ice_destroy_tx ( intelxl, &intelxl->tx );
+
+ /* Destroy receive descriptor ring */
+ intelxl_destroy_ring ( intelxl, &intelxl->rx );
+
+ /* Discard any unused receive buffers */
+ intelxl_empty_rx ( intelxl );
+}
+
+/** Network device operations */
+static struct net_device_operations ice_operations = {
+ .open = ice_open,
+ .close = ice_close,
+ .transmit = intelxl_transmit,
+ .poll = intelxl_poll,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int ice_probe ( struct pci_device *pci ) {
+ struct net_device *netdev;
+ struct intelxl_nic *intelxl;
+ uint32_t pffunc_rid;
+ uint32_t pfgen_portnum;
+ int rc;
+
+ /* Allocate and initialise net device */
+ netdev = alloc_etherdev ( sizeof ( *intelxl ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &ice_operations );
+ netdev->max_pkt_len = INTELXL_MAX_PKT_LEN;
+ intelxl = netdev->priv;
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( intelxl, 0, sizeof ( *intelxl ) );
+ intelxl->intr = ICE_GLINT_DYN_CTL;
+ intelxl->handle = ice_admin_event;
+ intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD,
+ &intelxl_admin_offsets );
+ intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT,
+ &intelxl_admin_offsets );
+ intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC,
+ sizeof ( intelxl->tx.desc.tx[0] ), NULL );
+ intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC,
+ sizeof ( intelxl->rx.desc.rx[0] ),
+ ice_context_rx );
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Map registers */
+ intelxl->regs = pci_ioremap ( pci, pci->membase, ICE_BAR_SIZE );
+ if ( ! intelxl->regs ) {
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Configure DMA */
+ intelxl->dma = &pci->dma;
+ dma_set_mask_64bit ( intelxl->dma );
+ netdev->dma = intelxl->dma;
+
+ /* Locate PCI Express capability */
+ intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP );
+ if ( ! intelxl->exp ) {
+ DBGC ( intelxl, "ICE %p missing PCIe capability\n",
+ intelxl );
+ rc = -ENXIO;
+ goto err_exp;
+ }
+
+ /* Reset the function via PCIe FLR */
+ pci_reset ( pci, intelxl->exp );
+
+ /* Get function and port number */
+ pffunc_rid = readl ( intelxl->regs + ICE_PFFUNC_RID );
+ intelxl->pf = ICE_PFFUNC_RID_FUNC_NUM ( pffunc_rid );
+ pfgen_portnum = readl ( intelxl->regs + ICE_PFGEN_PORTNUM );
+ intelxl->port = ICE_PFGEN_PORTNUM_PORT_NUM ( pfgen_portnum );
+ DBGC ( intelxl, "ICE %p PF %d using port %d\n",
+ intelxl, intelxl->pf, intelxl->port );
+
+ /* Enable MSI-X dummy interrupt */
+ if ( ( rc = intelxl_msix_enable ( intelxl, pci,
+ INTELXL_MSIX_VECTOR ) ) != 0 )
+ goto err_msix;
+
+ /* Open admin queues */
+ if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
+ goto err_open_admin;
+
+ /* Get firmware version */
+ if ( ( rc = ice_admin_version ( intelxl ) ) != 0 )
+ goto err_admin_version;
+
+ /* Clear PXE mode */
+ if ( ( rc = intelxl_admin_clear_pxe ( intelxl ) ) != 0 )
+ goto err_admin_clear_pxe;
+
+ /* Get switch configuration */
+ if ( ( rc = ice_admin_switch ( intelxl ) ) != 0 )
+ goto err_admin_switch;
+
+ /* Add broadcast address */
+ if ( ( rc = ice_admin_rules ( intelxl, eth_broadcast ) ) != 0 )
+ goto err_admin_rules_broadcast;
+
+ /* Add promiscuous unicast address */
+ if ( ( rc = ice_admin_rules ( intelxl, ice_magic_mac ) ) != 0 )
+ goto err_admin_rules_magic;
+
+ /* Query scheduler topology */
+ if ( ( rc = ice_admin_schedule ( intelxl ) ) != 0 )
+ goto err_admin_schedule;
+
+ /* Get MAC address */
+ if ( ( rc = ice_admin_mac_read ( netdev ) ) != 0 )
+ goto err_admin_mac_read;
+
+ /* Configure queue register addresses */
+ intelxl->tx.tail = ICE_QTX_COMM_DBELL;
+ intelxl->rx.reg = ICE_QRX_CTRL;
+ intelxl->rx.tail = ICE_QRX_TAIL;
+
+ /* Configure interrupt causes */
+ writel ( ( ICE_QINT_TQCTL_ITR_INDX_NONE | ICE_QINT_TQCTL_CAUSE_ENA ),
+ intelxl->regs + ICE_QINT_TQCTL );
+ writel ( ( ICE_QINT_RQCTL_ITR_INDX_NONE | ICE_QINT_RQCTL_CAUSE_ENA ),
+ intelxl->regs + ICE_QINT_RQCTL );
+
+ /* Set a default value for the queue context flex extension,
+ * since this register erroneously retains its value across at
+ * least a PCIe FLR.
+ */
+ writel ( ( ICE_QRX_FLXP_CNTXT_RXDID_IDX_LEGACY_32 |
+ ICE_QRX_FLXP_CNTXT_RXDID_PRIO_MAX ),
+ intelxl->regs + ICE_QRX_FLXP_CNTXT );
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register_netdev;
+
+ /* Set initial link state */
+ ice_admin_link ( netdev );
+
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register_netdev:
+ err_admin_mac_read:
+ err_admin_schedule:
+ err_admin_rules_magic:
+ err_admin_rules_broadcast:
+ err_admin_switch:
+ err_admin_clear_pxe:
+ err_admin_version:
+ intelxl_close_admin ( intelxl );
+ err_open_admin:
+ intelxl_msix_disable ( intelxl, pci, INTELXL_MSIX_VECTOR );
+ err_msix:
+ pci_reset ( pci, intelxl->exp );
+ err_exp:
+ iounmap ( intelxl->regs );
+ err_ioremap:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void ice_remove ( struct pci_device *pci ) {
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct intelxl_nic *intelxl = netdev->priv;
+
+ /* Unregister network device */
+ unregister_netdev ( netdev );
+
+ /* Close admin queues */
+ intelxl_close_admin ( intelxl );
+
+ /* Disable MSI-X dummy interrupt */
+ intelxl_msix_disable ( intelxl, pci, INTELXL_MSIX_VECTOR );
+
+ /* Reset the NIC */
+ pci_reset ( pci, intelxl->exp );
+
+ /* Free network device */
+ iounmap ( intelxl->regs );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** PCI device IDs */
+static struct pci_device_id ice_nics[] = {
+ PCI_ROM ( 0x8086, 0x124c, "e823l-bp", "E823-L backplane", 0 ),
+ PCI_ROM ( 0x8086, 0x124d, "e823l-sfp", "E823-L SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x124e, "e823l-10gt", "E823-L 10GBASE-T", 0 ),
+ PCI_ROM ( 0x8086, 0x124f, "e823l-1g", "E823-L 1GbE", 0 ),
+ PCI_ROM ( 0x8086, 0x151d, "e823l-qsfp", "E823-L QSFP", 0 ),
+ PCI_ROM ( 0x8086, 0x1591, "e810c-bp", "E810-C backplane", 0 ),
+ PCI_ROM ( 0x8086, 0x1592, "e810c-qsfp", "E810-C QSFP", 0 ),
+ PCI_ROM ( 0x8086, 0x1593, "e810c-sfp", "E810-C SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x1599, "e810-xxv-bp", "E810-XXV backplane", 0 ),
+ PCI_ROM ( 0x8086, 0x159a, "e810-xxv-qsfp", "E810-XXV QSFP", 0 ),
+ PCI_ROM ( 0x8086, 0x159b, "e810-xxv-sfp", "E810-XXV SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x188a, "e823c-bp", "E823-C backplane", 0 ),
+ PCI_ROM ( 0x8086, 0x188b, "e823c-qsfp", "E823-C QSFP", 0 ),
+ PCI_ROM ( 0x8086, 0x188c, "e823c-sfp", "E823-C SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x188d, "e823c-10gt", "E823-C 10GBASE-T", 0 ),
+ PCI_ROM ( 0x8086, 0x188e, "e823c-1g", "E823-C 1GbE", 0 ),
+ PCI_ROM ( 0x8086, 0x1890, "e822c-bp", "E822-C backplane", 0 ),
+ PCI_ROM ( 0x8086, 0x1891, "e822c-qsfp", "E822-C QSFP", 0 ),
+ PCI_ROM ( 0x8086, 0x1892, "e822c-sfp", "E822-C SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x1893, "e822c-10gt", "E822-C 10GBASE-T", 0 ),
+ PCI_ROM ( 0x8086, 0x1894, "e822c-1g", "E822-C 1GbE", 0 ),
+ PCI_ROM ( 0x8086, 0x1897, "e822l-bp", "E822-L backplane", 0 ),
+ PCI_ROM ( 0x8086, 0x1898, "e822l-sfp", "E822-L SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x1899, "e822l-10gt", "E822-L 10GBASE-T", 0 ),
+ PCI_ROM ( 0x8086, 0x189a, "e822l-1g", "E822-L 1GbE", 0 ),
+};
+
+/** PCI driver */
+struct pci_driver ice_driver __pci_driver = {
+ .ids = ice_nics,
+ .id_count = ( sizeof ( ice_nics ) / sizeof ( ice_nics[0] ) ),
+ .probe = ice_probe,
+ .remove = ice_remove,
+};
diff --git a/src/drivers/net/ice.h b/src/drivers/net/ice.h
new file mode 100644
index 000000000..26291a7a1
--- /dev/null
+++ b/src/drivers/net/ice.h
@@ -0,0 +1,565 @@
+#ifndef _ICE_H
+#define _ICE_H
+
+/** @file
+ *
+ * Intel 100 Gigabit Ethernet network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/if_ether.h>
+#include "intelxl.h"
+
+/** BAR size */
+#define ICE_BAR_SIZE 0x800000
+
+/******************************************************************************
+ *
+ * Transmit and receive datapaths
+ *
+ ******************************************************************************
+ */
+
+/** Transmit queue context */
+struct ice_context_tx {
+ /** Base address */
+ uint64_t base_port;
+ /** PF number and queue type */
+ uint16_t pf_type;
+ /** Source VSI */
+ uint16_t vsi;
+ /** Reserved */
+ uint8_t reserved_c[5];
+ /** Queue length */
+ uint16_t len;
+ /** Flags */
+ uint16_t flags;
+ /** Reserved */
+ uint8_t reserved_d[3];
+} __attribute__ (( packed ));
+
+/** Transmit scheduler configuration */
+struct ice_schedule_tx {
+ /** Node type */
+ uint8_t type;
+ /** Valid sections */
+ uint8_t sections;
+ /** Generic information */
+ uint8_t generic;
+ /** Flags */
+ uint8_t flags;
+ /** Committed bandwidth profile ID */
+ uint16_t commit_id;
+ /** Committeed bandwidth weight */
+ uint16_t commit_weight;
+ /** Excess bandwidth profile ID */
+ uint16_t excess_id;
+ /** Excess bandwidth weight */
+ uint16_t excess_weight;
+ /** Shared rate limit profile ID */
+ uint16_t shared;
+ /** Reserved */
+ uint16_t reserved;
+} __attribute__ (( packed ));
+
+/** Global Receive Queue Control Register */
+#define ICE_QRX_CTRL 0x120000
+
+/** Receive Queue Context Registers */
+#define ICE_QRX_CONTEXT(x) ( 0x280000 + ( 0x2000 * (x) ) )
+
+/** Receive Queue Tail Register */
+#define ICE_QRX_TAIL 0x290000
+
+/** Transmit Comm Scheduler Queue Doorbell Register */
+#define ICE_QTX_COMM_DBELL 0x2c0000
+
+/** Transmit Comm Scheduler Queue Context Data Registers */
+#define ICE_GLCOMM_QTX_CNTX_DATA(x) ( 0x2d2d40 + ( 0x4 * (x) ) )
+
+/** Transmit Comm Scheduler Queue Context Control Register */
+#define ICE_GLCOMM_QTX_CNTX_CTL 0x2d2dc8
+#define ICE_GLCOMM_QTX_CNTX_CTL_CMD(x) ( (x) << 16 ) /**< Command */
+#define ICE_GLCOMM_QTX_CNTX_CTL_CMD_READ \
+ ICE_GLCOMM_QTX_CNTX_CTL_CMD ( 0 ) /**< Read context */
+#define ICE_GLCOMM_QTX_CNTX_CTL_EXEC 0x00080000UL /**< Execute */
+
+/** Transmit Comm Scheduler Queue Context Status Register */
+#define ICE_GLCOMM_QTX_CNTX_STAT 0x2d2dcc
+#define ICE_GLCOMM_QTX_CNTX_BUSY 0x00000001UL /**< In progress */
+
+/** Queue Context Flex Extension Register */
+#define ICE_QRX_FLXP_CNTXT 0x480000
+#define ICE_QRX_FLXP_CNTXT_RXDID_IDX(x) ( (x) << 0 ) /**< RX profile */
+#define ICE_QRX_FLXP_CNTXT_RXDID_IDX_LEGACY_32 \
+ ICE_QRX_FLXP_CNTXT_RXDID_IDX ( 1 ) /**< 32-byte legacy */
+#define ICE_QRX_FLXP_CNTXT_RXDID_PRIO(x) ( (x) << 8 ) /**< Priority */
+#define ICE_QRX_FLXP_CNTXT_RXDID_PRIO_MAX \
+ ICE_QRX_FLXP_CNTXT_RXDID_PRIO ( 7 ) /**< Maximum priority */
+
+/******************************************************************************
+ *
+ * Admin queue
+ *
+ ******************************************************************************
+ */
+
+/** Admin queue version number */
+struct ice_admin_version {
+ /** Branch identifier */
+ uint8_t branch;
+ /** Major version number */
+ uint8_t major;
+ /** Minor version number */
+ uint8_t minor;
+ /** Patch level */
+ uint8_t patch;
+} __attribute__ (( packed ));
+
+/** Admin queue Get Version command parameters */
+struct ice_admin_version_params {
+ /** ROM version */
+ uint32_t rom;
+ /** Firmware build ID */
+ uint32_t build;
+ /** Firmware version */
+ struct ice_admin_version firmware;
+ /** API version */
+ struct ice_admin_version api;
+} __attribute__ (( packed ));
+
+/** Admin queue Manage MAC Address Read command parameters */
+struct ice_admin_mac_read_params {
+ /** Valid addresses */
+ uint8_t valid;
+ /** Reserved */
+ uint8_t reserved_a[3];
+ /** Number of addresses in response */
+ uint8_t count;
+ /** Reserved */
+ uint8_t reserved_b[11];
+} __attribute__ (( packed ));
+
+/** MAC Address description */
+struct ice_admin_mac_read_address {
+ /** Port number */
+ uint8_t port;
+ /** Address type */
+ uint8_t type;
+ /** MAC address */
+ uint8_t mac[ETH_ALEN];
+} __attribute__ (( packed ));
+
+/** LAN MAC address type */
+#define ICE_ADMIN_MAC_READ_TYPE_LAN 0
+
+/** Admin queue Manage MAC Address Read data buffer */
+struct ice_admin_mac_read_buffer {
+ /** MAC addresses */
+ struct ice_admin_mac_read_address mac[4];
+} __attribute__ (( packed ));
+
+/** Admin queue Manage MAC Address Write command parameters */
+struct ice_admin_mac_write_params {
+ /** Reserved */
+ uint8_t reserved_a[1];
+ /** Write type */
+ uint8_t type;
+ /** MAC address */
+ uint8_t mac[ETH_ALEN];
+ /** Reserved */
+ uint8_t reserved_b[8];
+} __attribute__ (( packed ));
+
+/** Admin queue Get Switch Configuration command parameters */
+struct ice_admin_switch_params {
+ /** Reserved */
+ uint8_t reserved_a[2];
+ /** Starting switching element identifier */
+ uint16_t next;
+ /** Reserved */
+ uint8_t reserved[4];
+ /** Data buffer address */
+ uint64_t address;
+} __attribute__ (( packed ));
+
+/** Switching element configuration */
+struct ice_admin_switch_config {
+ /** Switching element ID and flags */
+ uint16_t seid;
+ /** Uplink switching element ID */
+ uint16_t uplink;
+ /** PF/VF number */
+ uint16_t func;
+} __attribute__ (( packed ));
+
+/** Switching element ID type mask */
+#define ICE_ADMIN_SWITCH_TYPE_MASK 0xc000
+
+/** Virtual Station Interface element type */
+#define ICE_ADMIN_SWITCH_TYPE_VSI 0x8000
+
+/** Admin queue Get Switch Configuration data buffer */
+struct ice_admin_switch_buffer {
+ /** Switch configuration */
+ struct ice_admin_switch_config cfg[1];
+};
+
+/** Admin queue Add Switch Rules command */
+#define ICE_ADMIN_ADD_RULES 0x02a0
+
+/** Admin queue Add Switch Rules command parameters */
+struct ice_admin_rules_params {
+ /** Number of rules */
+ uint16_t count;
+ /** Reserved */
+ uint8_t reserved[6];
+} __attribute__ (( packed ));
+
+/** Admin queue Add Switch Rules data buffer */
+struct ice_admin_rules_buffer {
+ /** Type */
+ uint16_t type;
+ /** Return status */
+ uint16_t status;
+ /** Receipt ID */
+ uint16_t recipe;
+ /** Source port */
+ uint16_t port;
+ /** Action */
+ uint32_t action;
+ /** Lookup table index */
+ uint16_t index;
+ /** Header length */
+ uint16_t len;
+ /** Header data */
+ union {
+ /** Ethernet header */
+ struct ethhdr eth;
+ /** Raw data */
+ uint8_t raw[16];
+ } __attribute__ (( packed )) hdr;
+} __attribute__ (( packed ));
+
+/** Switch rule promiscuous recipe ID */
+#define ICE_ADMIN_RULES_RECIPE_PROMISC 0x0003
+
+/** Switch rule action valid */
+#define ICE_ADMIN_RULES_ACTION_VALID 0x00020000UL
+
+/** Switch rule VSI number */
+#define ICE_ADMIN_RULES_ACTION_VSI(x) ( (x) << 4 )
+
+/** Admin queue Query Default Scheduling Tree Topology command */
+#define ICE_ADMIN_SCHEDULE 0x0400
+
+/** Admin queue Query Default Scheduling Tree Topology command parameters */
+struct ice_admin_schedule_params {
+ /** Reserved */
+ uint8_t reserved_a;
+ /** Total branches */
+ uint8_t branches;
+ /** Reserved */
+ uint8_t reserved_b[6];
+} __attribute__ (( packed ));
+
+/** Transmit scheduler configuration generic section is valid */
+#define ICE_SCHEDULE_GENERIC 0x01
+
+/** Transmit scheduler configuration committed bandwidth section is valid */
+#define ICE_SCHEDULE_COMMIT 0x02
+
+/** Transmit scheduler configuration excess bandwidth section is valid */
+#define ICE_SCHEDULE_EXCESS 0x04
+
+/** Transmit scheduler configuration default weight */
+#define ICE_SCHEDULE_WEIGHT 0x0004
+
+/** Admin queue Query Default Scheduling Tree Topology node */
+struct ice_admin_schedule_node {
+ /** Parent TEID */
+ uint32_t parent;
+ /** Node TEID */
+ uint32_t teid;
+ /** Scheduler configuration */
+ struct ice_schedule_tx config;
+} __attribute__ (( packed ));
+
+/** Admin queue Query Default Scheduling Tree Topology branch */
+struct ice_admin_schedule_branch {
+ /** Reserved */
+ uint8_t reserved_a[4];
+ /** Number of nodes */
+ uint16_t count;
+ /** Reserved */
+ uint8_t reserved_b[2];
+ /** Nodes */
+ struct ice_admin_schedule_node node[0];
+} __attribute__ (( packed ));
+
+/** Admin queue Query Default Scheduling Tree Topology data buffer */
+union ice_admin_schedule_buffer {
+ /** Branches */
+ struct ice_admin_schedule_branch branch[0];
+ /** Padding */
+ uint8_t pad[INTELXL_ADMIN_BUFFER_SIZE];
+} __attribute__ (( packed ));
+
+/** Admin queue Restart Autonegotiation command parameters */
+struct ice_admin_autoneg_params {
+ /** Reserved */
+ uint8_t reserved_a[2];
+ /** Flags */
+ uint8_t flags;
+ /** Reserved */
+ uint8_t reserved_b[13];
+} __attribute__ (( packed ));
+
+/** Admin queue Get Link Status command parameters */
+struct ice_admin_link_params {
+ /** Logical port number */
+ uint8_t port;
+ /** Reserved */
+ uint8_t reserved_a;
+ /** Link status notification */
+ uint8_t notify;
+ /** Reserved */
+ uint8_t reserved_b[13];
+} __attribute__ (( packed ));
+
+/** Admin queue Get Link Status data buffer */
+struct ice_admin_link_buffer {
+ /** Topology conflicts */
+ uint8_t conflict;
+ /** Configuration errors */
+ uint8_t error;
+ /** Link status */
+ uint8_t status;
+ /** Reserved */
+ uint8_t reserved_a[7];
+ /** Link speed */
+ uint16_t speed;
+ /** Reserved */
+ uint8_t reserved_b[20];
+} __attribute__ (( packed ));
+
+/** Admin queue Add Transmit Queues command */
+#define ICE_ADMIN_ADD_TXQ 0x0c30
+
+/** Admin queue Add Transmit Queues command parameters */
+struct ice_admin_add_txq_params {
+ /** Number of queue groups */
+ uint8_t count;
+ /** Reserved */
+ uint8_t reserved[7];
+} __attribute__ (( packed ));
+
+/** Admin queue Add Transmit Queues data buffer */
+struct ice_admin_add_txq_buffer {
+ /** Parent TEID */
+ uint32_t parent;
+ /** Number of queues */
+ uint8_t count;
+ /** Reserved */
+ uint8_t reserved_a[3];
+ /** Transmit queue ID */
+ uint16_t id;
+ /** Reserved */
+ uint8_t reserved_b[2];
+ /** Queue TEID */
+ uint32_t teid;
+ /** Transmit queue context */
+ struct ice_context_tx ctx;
+ /** Scheduler configuration */
+ struct ice_schedule_tx sched;
+} __attribute__ (( packed ));
+
+/** Transmit queue base address and port number */
+#define ICE_TXQ_BASE_PORT( addr, port ) \
+ ( ( (addr) >> 7 ) | ( ( ( uint64_t ) (port) ) << 57 ) )
+
+/** Transmit queue PF number */
+#define ICE_TXQ_PF_TYPE( pf ) ( ( (pf) << 1 ) | ( 0x2 << 14 ) )
+
+/** Transmit queue length */
+#define ICE_TXQ_LEN( count ) ( (count) >> 1 )
+
+/** Transmit queue uses TSO */
+#define ICE_TXQ_FL_TSO 0x0001
+
+/** Transmit queue uses legacy mode*/
+#define ICE_TXQ_FL_LEGACY 0x1000
+
+/** Admin queue Disable Transmit Queues command */
+#define ICE_ADMIN_DISABLE_TXQ 0x0c31
+
+/** Admin queue Disable Transmit Queues command parameters */
+struct ice_admin_disable_txq_params {
+ /** Flags */
+ uint8_t flags;
+ /** Number of queue groups */
+ uint8_t count;
+ /** Reserved */
+ uint8_t reserved_a;
+ /** Timeout */
+ uint8_t timeout;
+ /** Reserved */
+ uint8_t reserved_b[4];
+} __attribute__ (( packed ));
+
+/** Disable queue and flush pipe */
+#define ICE_TXQ_FL_FLUSH 0x08
+
+/** Disable queue timeout */
+#define ICE_TXQ_TIMEOUT 0xc8
+
+/** Admin queue Disable Transmit Queues data buffer */
+struct ice_admin_disable_txq_buffer {
+ /** Parent TEID */
+ uint32_t parent;
+ /** Number of queues */
+ uint8_t count;
+ /** Reserved */
+ uint8_t reserved;
+ /** Transmit queue ID */
+ uint16_t id;
+} __attribute__ (( packed ));
+
+/** Admin queue command parameters */
+union ice_admin_params {
+ /** Additional data buffer command parameters */
+ struct intelxl_admin_buffer_params buffer;
+ /** Get Version command parameters */
+ struct ice_admin_version_params version;
+ /** Manage MAC Address Read command parameters */
+ struct ice_admin_mac_read_params mac_read;
+ /** Manage MAC Address Write command parameters */
+ struct ice_admin_mac_write_params mac_write;
+ /** Get Switch Configuration command parameters */
+ struct ice_admin_switch_params sw;
+ /** Add Switch Rules command parameters */
+ struct ice_admin_rules_params rules;
+ /** Query Default Scheduling Tree Topology command parameters */
+ struct ice_admin_schedule_params sched;
+ /** Restart Autonegotiation command parameters */
+ struct ice_admin_autoneg_params autoneg;
+ /** Get Link Status command parameters */
+ struct ice_admin_link_params link;
+ /** Add Transmit Queue command parameters */
+ struct ice_admin_add_txq_params add_txq;
+ /** Disable Transmit Queue command parameters */
+ struct ice_admin_disable_txq_params disable_txq;
+} __attribute__ (( packed ));
+
+
+/** Admin queue data buffer */
+union ice_admin_buffer {
+ /** Original 40 Gigabit Ethernet data buffer */
+ union intelxl_admin_buffer xl;
+ /** Manage MAC Address Read data buffer */
+ struct ice_admin_mac_read_buffer mac_read;
+ /** Get Switch Configuration data buffer */
+ struct ice_admin_switch_buffer sw;
+ /** Add Switch Rules data buffer */
+ struct ice_admin_rules_buffer rules;
+ /** Query Default Scheduling Tree Topology data buffer */
+ union ice_admin_schedule_buffer sched;
+ /** Get Link Status data buffer */
+ struct ice_admin_link_buffer link;
+ /** Add Transmit Queue data buffer */
+ struct ice_admin_add_txq_buffer add_txq;
+ /** Disable Transmit Queue data buffer */
+ struct ice_admin_disable_txq_buffer disable_txq;
+} __attribute__ (( packed ));
+
+/** Admin queue descriptor */
+struct ice_admin_descriptor {
+ /** Transparent union */
+ union {
+ /** Original 40 Gigabit Ethernet descriptor */
+ struct intelxl_admin_descriptor xl;
+ /** Transparent struct */
+ struct {
+ /** Flags */
+ uint16_t flags;
+ /** Opcode */
+ uint16_t opcode;
+ /** Data length */
+ uint16_t len;
+ /** Return value */
+ uint16_t ret;
+ /** Opaque cookie */
+ uint32_t cookie;
+ /** Reserved */
+ uint8_t reserved[4];
+ /** Parameters */
+ union ice_admin_params params;
+ } __attribute__ (( packed ));
+ } __attribute__ (( packed ));
+} __attribute__ (( packed ));
+
+/**
+ * Get next admin command queue descriptor
+ *
+ * @v intelxl Intel device
+ * @ret cmd Command descriptor
+ */
+struct ice_admin_descriptor *
+ice_admin_command_descriptor ( struct intelxl_nic *intelxl ) {
+ struct intelxl_admin_descriptor *xlcmd =
+ intelxl_admin_command_descriptor ( intelxl );
+
+ return container_of ( xlcmd, struct ice_admin_descriptor, xl );
+}
+
+/**
+ * Get next admin command queue data buffer
+ *
+ * @v intelxl Intel device
+ * @ret buf Data buffer
+ */
+static inline __attribute__ (( always_inline )) union ice_admin_buffer *
+ice_admin_command_buffer ( struct intelxl_nic *intelxl ) {
+ union intelxl_admin_buffer *xlbuf =
+ intelxl_admin_command_buffer ( intelxl );
+
+ return container_of ( xlbuf, union ice_admin_buffer, xl );
+}
+
+/******************************************************************************
+ *
+ * Top level
+ *
+ ******************************************************************************
+ */
+
+/** Function Requester ID Information Register */
+#define ICE_PFFUNC_RID 0x09e880
+#define ICE_PFFUNC_RID_FUNC_NUM(x) \
+ ( ( (x) >> 0 ) & 0x7 ) /**< Function number */
+
+/** PF LAN Port Number Register */
+#define ICE_PFGEN_PORTNUM 0x1d2400
+#define ICE_PFGEN_PORTNUM_PORT_NUM(x) \
+ ( ( (x) >> 0 ) & 0x7 ) /**< Port number */
+
+/** Transmit Queue Interrupt Cause Control Register */
+#define ICE_QINT_TQCTL 0x140000
+#define ICE_QINT_TQCTL_ITR_INDX(x) ( (x) << 11 ) /**< Throttling */
+#define ICE_QINT_TQCTL_ITR_INDX_NONE \
+ ICE_QINT_TQCTL_ITR_INDX ( 0x3 ) /**< No throttling */
+#define ICE_QINT_TQCTL_CAUSE_ENA 0x40000000UL /**< Enable */
+
+/** Receive Queue Interrupt Cause Control Register */
+#define ICE_QINT_RQCTL 0x150000
+#define ICE_QINT_RQCTL_ITR_INDX(x) ( (x) << 11 ) /**< Throttling */
+#define ICE_QINT_RQCTL_ITR_INDX_NONE \
+ ICE_QINT_RQCTL_ITR_INDX ( 0x3 ) /**< No throttling */
+#define ICE_QINT_RQCTL_CAUSE_ENA 0x40000000UL /**< Enable */
+
+/** Global Interrupt Dynamic Control Register */
+#define ICE_GLINT_DYN_CTL 0x160000
+
+#endif /* _ICE_H */
diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c
index ac9e37c5a..82b07833c 100644
--- a/src/drivers/net/intelxl.c
+++ b/src/drivers/net/intelxl.c
@@ -46,79 +46,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/******************************************************************************
*
- * Device reset
- *
- ******************************************************************************
- */
-
-/**
- * Reset hardware
- *
- * @v intelxl Intel device
- * @ret rc Return status code
- */
-static int intelxl_reset ( struct intelxl_nic *intelxl ) {
- uint32_t pfgen_ctrl;
-
- /* Perform a global software reset */
- pfgen_ctrl = readl ( intelxl->regs + INTELXL_PFGEN_CTRL );
- writel ( ( pfgen_ctrl | INTELXL_PFGEN_CTRL_PFSWR ),
- intelxl->regs + INTELXL_PFGEN_CTRL );
- mdelay ( INTELXL_RESET_DELAY_MS );
-
- return 0;
-}
-
-/******************************************************************************
- *
- * MAC address
- *
- ******************************************************************************
- */
-
-/**
- * Fetch initial MAC address and maximum frame size
- *
- * @v intelxl Intel device
- * @v netdev Network device
- * @ret rc Return status code
- */
-static int intelxl_fetch_mac ( struct intelxl_nic *intelxl,
- struct net_device *netdev ) {
- union intelxl_receive_address mac;
- uint32_t prtpm_sal;
- uint32_t prtpm_sah;
- uint32_t prtgl_sah;
- size_t mfs;
-
- /* Read NVM-loaded address */
- prtpm_sal = readl ( intelxl->regs + INTELXL_PRTPM_SAL );
- prtpm_sah = readl ( intelxl->regs + INTELXL_PRTPM_SAH );
- mac.reg.low = cpu_to_le32 ( prtpm_sal );
- mac.reg.high = cpu_to_le32 ( prtpm_sah );
-
- /* Check that address is valid */
- if ( ! is_valid_ether_addr ( mac.raw ) ) {
- DBGC ( intelxl, "INTELXL %p has invalid MAC address (%s)\n",
- intelxl, eth_ntoa ( mac.raw ) );
- return -ENOENT;
- }
-
- /* Copy MAC address */
- DBGC ( intelxl, "INTELXL %p has autoloaded MAC address %s\n",
- intelxl, eth_ntoa ( mac.raw ) );
- memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
-
- /* Get maximum frame size */
- prtgl_sah = readl ( intelxl->regs + INTELXL_PRTGL_SAH );
- mfs = INTELXL_PRTGL_SAH_MFS_GET ( prtgl_sah );
- netdev->max_pkt_len = ( mfs - 4 /* CRC */ );
-
- return 0;
-}
-
-/******************************************************************************
- *
* MSI-X interrupts
*
******************************************************************************
@@ -129,10 +56,11 @@ static int intelxl_fetch_mac ( struct intelxl_nic *intelxl,
*
* @v intelxl Intel device
* @v pci PCI device
+ * @v vector MSI-X vector
* @ret rc Return status code
*/
int intelxl_msix_enable ( struct intelxl_nic *intelxl,
- struct pci_device *pci ) {
+ struct pci_device *pci, unsigned int vector ) {
int rc;
/* Map dummy target location */
@@ -151,12 +79,12 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl,
goto err_enable;
}
- /* Configure interrupt zero to write to dummy location */
- pci_msix_map ( &intelxl->msix.cap, 0,
+ /* Configure interrupt to write to dummy location */
+ pci_msix_map ( &intelxl->msix.cap, vector,
dma ( &intelxl->msix.map, &intelxl->msix.msg ), 0 );
- /* Enable dummy interrupt zero */
- pci_msix_unmask ( &intelxl->msix.cap, 0 );
+ /* Enable dummy interrupt */
+ pci_msix_unmask ( &intelxl->msix.cap, vector );
return 0;
@@ -172,12 +100,13 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl,
*
* @v intelxl Intel device
* @v pci PCI device
+ * @v vector MSI-X vector
*/
void intelxl_msix_disable ( struct intelxl_nic *intelxl,
- struct pci_device *pci ) {
+ struct pci_device *pci, unsigned int vector ) {
- /* Disable dummy interrupt zero */
- pci_msix_mask ( &intelxl->msix.cap, 0 );
+ /* Disable dummy interrupts */
+ pci_msix_mask ( &intelxl->msix.cap, vector );
/* Disable MSI-X capability */
pci_msix_disable ( pci, &intelxl->msix.cap );
@@ -194,7 +123,7 @@ void intelxl_msix_disable ( struct intelxl_nic *intelxl,
*/
/** Admin queue register offsets */
-static const struct intelxl_admin_offsets intelxl_admin_offsets = {
+const struct intelxl_admin_offsets intelxl_admin_offsets = {
.bal = INTELXL_ADMIN_BAL,
.bah = INTELXL_ADMIN_BAH,
.len = INTELXL_ADMIN_LEN,
@@ -371,6 +300,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
union intelxl_admin_buffer *buf;
uint64_t address;
uint32_t cookie;
+ uint16_t silence;
unsigned int index;
unsigned int tail;
unsigned int i;
@@ -383,15 +313,18 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ];
DBGC2 ( intelxl, "INTELXL %p admin command %#x opcode %#04x",
intelxl, index, le16_to_cpu ( cmd->opcode ) );
- if ( cmd->vopcode )
- DBGC2 ( intelxl, "/%#08x", le32_to_cpu ( cmd->vopcode ) );
+ if ( cmd->cookie )
+ DBGC2 ( intelxl, "/%#08x", le32_to_cpu ( cmd->cookie ) );
DBGC2 ( intelxl, ":\n" );
+ /* Allow expected errors to be silenced */
+ silence = cmd->ret;
+ cmd->ret = 0;
+
/* Sanity checks */
assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_DD ) ) );
assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_CMP ) ) );
assert ( ! ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_ERR ) ) );
- assert ( cmd->ret == 0 );
/* Populate data buffer address if applicable */
if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
@@ -401,7 +334,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
}
/* Populate cookie, if not being (ab)used for VF opcode */
- if ( ! cmd->vopcode )
+ if ( ! cmd->cookie )
cmd->cookie = cpu_to_le32 ( index );
/* Record cookie */
@@ -409,7 +342,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
/* Post command descriptor */
DBGC2_HDA ( intelxl, virt_to_phys ( cmd ), cmd, sizeof ( *cmd ) );
- if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
+ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_RD ) ) {
DBGC2_HDA ( intelxl, virt_to_phys ( buf ), buf,
le16_to_cpu ( cmd->len ) );
}
@@ -428,6 +361,10 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
intelxl, index );
DBGC2_HDA ( intelxl, virt_to_phys ( cmd ), cmd,
sizeof ( *cmd ) );
+ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
+ DBGC2_HDA ( intelxl, virt_to_phys ( buf ), buf,
+ le16_to_cpu ( cmd->len ) );
+ }
/* Check for cookie mismatch */
if ( cmd->cookie != cookie ) {
@@ -438,8 +375,8 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
goto err;
}
- /* Check for errors */
- if ( cmd->ret != 0 ) {
+ /* Check for unexpected errors */
+ if ( ( cmd->ret != 0 ) && ( cmd->ret != silence ) ) {
DBGC ( intelxl, "INTELXL %p admin command %#x error "
"%d\n", intelxl, index,
le16_to_cpu ( cmd->ret ) );
@@ -551,28 +488,102 @@ static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
}
/**
+ * Get MAC address
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int intelxl_admin_mac_read ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct intelxl_admin_descriptor *cmd;
+ struct intelxl_admin_mac_read_params *read;
+ union intelxl_admin_buffer *buf;
+ uint8_t *mac;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxl_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_MAC_READ );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->mac_read ) );
+ read = &cmd->params.mac_read;
+ buf = intelxl_admin_command_buffer ( intelxl );
+ mac = buf->mac_read.pf;
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ /* Check that MAC address is present in response */
+ if ( ! ( read->valid & INTELXL_ADMIN_MAC_READ_VALID_LAN ) ) {
+ DBGC ( intelxl, "INTELXL %p has no MAC address\n", intelxl );
+ return -ENOENT;
+ }
+
+ /* Check that address is valid */
+ if ( ! is_valid_ether_addr ( mac ) ) {
+ DBGC ( intelxl, "INTELXL %p has invalid MAC address (%s)\n",
+ intelxl, eth_ntoa ( mac ) );
+ return -ENOENT;
+ }
+
+ /* Copy MAC address */
+ DBGC ( intelxl, "INTELXL %p has MAC address %s\n",
+ intelxl, eth_ntoa ( mac ) );
+ memcpy ( netdev->hw_addr, mac, ETH_ALEN );
+
+ return 0;
+}
+
+/**
+ * Set MAC address
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int intelxl_admin_mac_write ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct intelxl_admin_descriptor *cmd;
+ struct intelxl_admin_mac_write_params *write;
+ union {
+ uint8_t raw[ETH_ALEN];
+ struct {
+ uint16_t high;
+ uint32_t low;
+ } __attribute__ (( packed ));
+ } mac;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxl_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_MAC_WRITE );
+ write = &cmd->params.mac_write;
+ memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
+ write->high = bswap_16 ( mac.high );
+ write->low = bswap_32 ( mac.low );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
* Clear PXE mode
*
* @v intelxl Intel device
* @ret rc Return status code
*/
-static int intelxl_admin_clear_pxe ( struct intelxl_nic *intelxl ) {
+int intelxl_admin_clear_pxe ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_clear_pxe_params *pxe;
- uint32_t gllan_rctl_0;
int rc;
- /* Do nothing if device is already out of PXE mode */
- gllan_rctl_0 = readl ( intelxl->regs + INTELXL_GLLAN_RCTL_0 );
- if ( ! ( gllan_rctl_0 & INTELXL_GLLAN_RCTL_0_PXE_MODE ) ) {
- DBGC2 ( intelxl, "INTELXL %p already in non-PXE mode\n",
- intelxl );
- return 0;
- }
-
/* Populate descriptor */
cmd = intelxl_admin_command_descriptor ( intelxl );
cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_CLEAR_PXE );
+ cmd->ret = cpu_to_le16 ( INTELXL_ADMIN_EEXIST );
pxe = &cmd->params.pxe;
pxe->magic = INTELXL_ADMIN_CLEAR_PXE_MAGIC;
@@ -580,6 +591,13 @@ static int intelxl_admin_clear_pxe ( struct intelxl_nic *intelxl ) {
if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc;
+ /* Check for expected errors */
+ if ( cmd->ret == cpu_to_le16 ( INTELXL_ADMIN_EEXIST ) ) {
+ DBGC ( intelxl, "INTELXL %p already in non-PXE mode\n",
+ intelxl );
+ return 0;
+ }
+
return 0;
}
@@ -593,18 +611,20 @@ static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_switch_params *sw;
union intelxl_admin_buffer *buf;
+ uint16_t next = 0;
int rc;
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
- cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
- cmd->len = cpu_to_le16 ( sizeof ( buf->sw ) );
- sw = &cmd->params.sw;
- buf = intelxl_admin_command_buffer ( intelxl );
-
/* Get each configuration in turn */
do {
+ /* Populate descriptor */
+ cmd = intelxl_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->sw ) );
+ sw = &cmd->params.sw;
+ sw->next = next;
+ buf = intelxl_admin_command_buffer ( intelxl );
+
/* Issue command */
if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
return rc;
@@ -624,7 +644,7 @@ static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
buf->sw.cfg.connection );
}
- } while ( sw->next );
+ } while ( ( next = sw->next ) );
/* Check that we found a VSI */
if ( ! intelxl->vsi ) {
@@ -701,6 +721,31 @@ static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
}
/**
+ * Set MAC configuration
+ *
+ * @v intelxl Intel device
+ * @ret rc Return status code
+ */
+int intelxl_admin_mac_config ( struct intelxl_nic *intelxl ) {
+ struct intelxl_admin_descriptor *cmd;
+ struct intelxl_admin_mac_config_params *config;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxl_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_MAC_CONFIG );
+ config = &cmd->params.mac_config;
+ config->mfs = cpu_to_le16 ( intelxl->mfs );
+ config->flags = INTELXL_ADMIN_MAC_CONFIG_FL_CRC;
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
* Restart autonegotiation
*
* @v intelxl Intel device
@@ -760,18 +805,26 @@ static int intelxl_admin_link ( struct net_device *netdev ) {
}
/**
- * Handle virtual function event (when VF driver is not present)
+ * Handle admin event
*
* @v netdev Network device
- * @v evt Admin queue event descriptor
- * @v buf Admin queue event data buffer
+ * @v evt Event descriptor
+ * @v buf Data buffer
*/
-__weak void
-intelxlvf_admin_event ( struct net_device *netdev __unused,
- struct intelxl_admin_descriptor *evt __unused,
- union intelxl_admin_buffer *buf __unused ) {
+static void intelxl_admin_event ( struct net_device *netdev,
+ struct intelxl_admin_descriptor *evt,
+ union intelxl_admin_buffer *buf __unused ) {
+ struct intelxl_nic *intelxl = netdev->priv;
- /* Nothing to do */
+ /* Ignore unrecognised events */
+ if ( evt->opcode != cpu_to_le16 ( INTELXL_ADMIN_LINK ) ) {
+ DBGC ( intelxl, "INTELXL %p unrecognised event opcode "
+ "%#04x\n", intelxl, le16_to_cpu ( evt->opcode ) );
+ return;
+ }
+
+ /* Update link status */
+ intelxl_admin_link ( netdev );
}
/**
@@ -823,19 +876,7 @@ void intelxl_poll_admin ( struct net_device *netdev ) {
}
/* Handle event */
- switch ( evt->opcode ) {
- case cpu_to_le16 ( INTELXL_ADMIN_LINK ):
- intelxl_admin_link ( netdev );
- break;
- case cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_VF ):
- intelxlvf_admin_event ( netdev, evt, buf );
- break;
- default:
- DBGC ( intelxl, "INTELXL %p admin event %#x "
- "unrecognised opcode %#04x\n", intelxl,
- admin->index, le16_to_cpu ( evt->opcode ) );
- break;
- }
+ intelxl->handle ( netdev, evt, buf );
/* Reset descriptor and refill queue */
intelxl_admin_event_init ( intelxl, admin->index );
@@ -864,18 +905,8 @@ int intelxl_open_admin ( struct intelxl_nic *intelxl ) {
/* (Re)open admin queues */
intelxl_reopen_admin ( intelxl );
- /* Get firmware version */
- if ( ( rc = intelxl_admin_version ( intelxl ) ) != 0 )
- goto err_version;
-
- /* Report driver version */
- if ( ( rc = intelxl_admin_driver ( intelxl ) ) != 0 )
- goto err_driver;
-
return 0;
- err_driver:
- err_version:
intelxl_disable_admin ( intelxl, &intelxl->command );
intelxl_disable_admin ( intelxl, &intelxl->event );
intelxl_free_admin ( intelxl, &intelxl->command );
@@ -963,8 +994,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl,
ring->cons = 0;
DBGC ( intelxl, "INTELXL %p ring %06x is at [%08lx,%08lx)\n",
- intelxl, ( ring->reg + ring->tail ),
- virt_to_phys ( ring->desc.raw ),
+ intelxl, ring->tail, virt_to_phys ( ring->desc.raw ),
( virt_to_phys ( ring->desc.raw ) + ring->len ) );
return 0;
@@ -1203,7 +1233,7 @@ static int intelxl_enable_ring ( struct intelxl_nic *intelxl,
qxx_ena = readl ( ring_regs + INTELXL_QXX_ENA );
if ( ! ( qxx_ena & INTELXL_QXX_ENA_STAT ) ) {
DBGC ( intelxl, "INTELXL %p ring %06x failed to enable: "
- "%#08x\n", intelxl, ring->reg, qxx_ena );
+ "%#08x\n", intelxl, ring->tail, qxx_ena );
return -EIO;
}
@@ -1239,7 +1269,7 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl,
}
DBGC ( intelxl, "INTELXL %p ring %06x timed out waiting for disable: "
- "%#08x\n", intelxl, ring->reg, qxx_ena );
+ "%#08x\n", intelxl, ring->tail, qxx_ena );
return -ETIMEDOUT;
}
@@ -1250,8 +1280,8 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl,
* @v ring Descriptor ring
* @ret rc Return status code
*/
-static int intelxl_create_ring ( struct intelxl_nic *intelxl,
- struct intelxl_ring *ring ) {
+int intelxl_create_ring ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring ) {
physaddr_t address;
int rc;
@@ -1284,8 +1314,8 @@ static int intelxl_create_ring ( struct intelxl_nic *intelxl,
* @v intelxl Intel device
* @v ring Descriptor ring
*/
-static void intelxl_destroy_ring ( struct intelxl_nic *intelxl,
- struct intelxl_ring *ring ) {
+void intelxl_destroy_ring ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring ) {
int rc;
/* Disable ring */
@@ -1377,24 +1407,20 @@ void intelxl_empty_rx ( struct intelxl_nic *intelxl ) {
*/
static int intelxl_open ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
- union intelxl_receive_address mac;
unsigned int queue;
- uint32_t prtgl_sal;
- uint32_t prtgl_sah;
int rc;
/* Calculate maximum frame size */
intelxl->mfs = ( ( ETH_HLEN + netdev->mtu + 4 /* CRC */ +
INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
- /* Program MAC address and maximum frame size */
- memset ( &mac, 0, sizeof ( mac ) );
- memcpy ( mac.raw, netdev->ll_addr, sizeof ( mac.raw ) );
- prtgl_sal = le32_to_cpu ( mac.reg.low );
- prtgl_sah = ( le32_to_cpu ( mac.reg.high ) |
- INTELXL_PRTGL_SAH_MFS_SET ( intelxl->mfs ) );
- writel ( prtgl_sal, intelxl->regs + INTELXL_PRTGL_SAL );
- writel ( prtgl_sah, intelxl->regs + INTELXL_PRTGL_SAH );
+ /* Set MAC address */
+ if ( ( rc = intelxl_admin_mac_write ( netdev ) ) != 0 )
+ goto err_mac_write;
+
+ /* Set maximum frame size */
+ if ( ( rc = intelxl_admin_mac_config ( intelxl ) ) != 0 )
+ goto err_mac_config;
/* Associate transmit queue to PF */
writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF |
@@ -1437,6 +1463,8 @@ static int intelxl_open ( struct net_device *netdev ) {
err_create_tx:
intelxl_destroy_ring ( intelxl, &intelxl->rx );
err_create_rx:
+ err_mac_config:
+ err_mac_write:
return rc;
}
@@ -1668,11 +1696,13 @@ static int intelxl_probe ( struct pci_device *pci ) {
goto err_alloc;
}
netdev_init ( netdev, &intelxl_operations );
+ netdev->max_pkt_len = INTELXL_MAX_PKT_LEN;
intelxl = netdev->priv;
pci_set_drvdata ( pci, netdev );
netdev->dev = &pci->dev;
memset ( intelxl, 0, sizeof ( *intelxl ) );
intelxl->intr = INTELXL_PFINT_DYN_CTL0;
+ intelxl->handle = intelxl_admin_event;
intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD,
&intelxl_admin_offsets );
intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT,
@@ -1699,9 +1729,17 @@ static int intelxl_probe ( struct pci_device *pci ) {
dma_set_mask_64bit ( intelxl->dma );
netdev->dma = intelxl->dma;
- /* Reset the NIC */
- if ( ( rc = intelxl_reset ( intelxl ) ) != 0 )
- goto err_reset;
+ /* Locate PCI Express capability */
+ intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP );
+ if ( ! intelxl->exp ) {
+ DBGC ( intelxl, "INTELXL %p missing PCIe capability\n",
+ intelxl );
+ rc = -ENXIO;
+ goto err_exp;
+ }
+
+ /* Reset the function via PCIe FLR */
+ pci_reset ( pci, intelxl->exp );
/* Get function number, port number and base queue number */
pffunc_rid = readl ( intelxl->regs + INTELXL_PFFUNC_RID );
@@ -1714,18 +1752,23 @@ static int intelxl_probe ( struct pci_device *pci ) {
intelxl, intelxl->pf, intelxl->port, intelxl->base,
INTELXL_PFLAN_QALLOC_LASTQ ( pflan_qalloc ) );
- /* Fetch MAC address and maximum frame size */
- if ( ( rc = intelxl_fetch_mac ( intelxl, netdev ) ) != 0 )
- goto err_fetch_mac;
-
/* Enable MSI-X dummy interrupt */
- if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
+ if ( ( rc = intelxl_msix_enable ( intelxl, pci,
+ INTELXL_MSIX_VECTOR ) ) != 0 )
goto err_msix;
/* Open admin queues */
if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
goto err_open_admin;
+ /* Get firmware version */
+ if ( ( rc = intelxl_admin_version ( intelxl ) ) != 0 )
+ goto err_admin_version;
+
+ /* Report driver version */
+ if ( ( rc = intelxl_admin_driver ( intelxl ) ) != 0 )
+ goto err_admin_driver;
+
/* Clear PXE mode */
if ( ( rc = intelxl_admin_clear_pxe ( intelxl ) ) != 0 )
goto err_admin_clear_pxe;
@@ -1742,6 +1785,10 @@ static int intelxl_probe ( struct pci_device *pci ) {
if ( ( rc = intelxl_admin_promisc ( intelxl ) ) != 0 )
goto err_admin_promisc;
+ /* Get MAC address */
+ if ( ( rc = intelxl_admin_mac_read ( netdev ) ) != 0 )
+ goto err_admin_mac_read;
+
/* Configure queue register addresses */
intelxl->tx.reg = INTELXL_QTX ( intelxl->queue );
intelxl->tx.tail = ( intelxl->tx.reg + INTELXL_QXX_TAIL );
@@ -1773,17 +1820,19 @@ static int intelxl_probe ( struct pci_device *pci ) {
unregister_netdev ( netdev );
err_register_netdev:
+ err_admin_mac_read:
err_admin_promisc:
err_admin_vsi:
err_admin_switch:
err_admin_clear_pxe:
+ err_admin_driver:
+ err_admin_version:
intelxl_close_admin ( intelxl );
err_open_admin:
- intelxl_msix_disable ( intelxl, pci );
+ intelxl_msix_disable ( intelxl, pci, INTELXL_MSIX_VECTOR );
err_msix:
- err_fetch_mac:
- intelxl_reset ( intelxl );
- err_reset:
+ pci_reset ( pci, intelxl->exp );
+ err_exp:
iounmap ( intelxl->regs );
err_ioremap:
netdev_nullify ( netdev );
@@ -1808,10 +1857,10 @@ static void intelxl_remove ( struct pci_device *pci ) {
intelxl_close_admin ( intelxl );
/* Disable MSI-X dummy interrupt */
- intelxl_msix_disable ( intelxl, pci );
+ intelxl_msix_disable ( intelxl, pci, INTELXL_MSIX_VECTOR );
/* Reset the NIC */
- intelxl_reset ( intelxl );
+ pci_reset ( pci, intelxl->exp );
/* Free network device */
iounmap ( intelxl->regs );
@@ -1821,6 +1870,10 @@ static void intelxl_remove ( struct pci_device *pci ) {
/** PCI device IDs */
static struct pci_device_id intelxl_nics[] = {
+ PCI_ROM ( 0x8086, 0x0cf8, "x710-n3000", "X710 FPGA N3000", 0 ),
+ PCI_ROM ( 0x8086, 0x0d58, "xxv710-n3000", "XXV710 FPGA N3000", 0 ),
+ PCI_ROM ( 0x8086, 0x104e, "x710-sfp-b", "X710 10GbE SFP+", 0 ),
+ PCI_ROM ( 0x8086, 0x104f, "x710-kx-b", "X710 10GbE backplane", 0 ),
PCI_ROM ( 0x8086, 0x1572, "x710-sfp", "X710 10GbE SFP+", 0 ),
PCI_ROM ( 0x8086, 0x1574, "xl710-qemu", "Virtual XL710", 0 ),
PCI_ROM ( 0x8086, 0x1580, "xl710-kx-b", "XL710 40GbE backplane", 0 ),
@@ -1834,6 +1887,7 @@ static struct pci_device_id intelxl_nics[] = {
PCI_ROM ( 0x8086, 0x1589, "x710-10gt4", "X710 10GBASE-T4", 0 ),
PCI_ROM ( 0x8086, 0x158a, "xxv710", "XXV710 25GbE backplane", 0 ),
PCI_ROM ( 0x8086, 0x158b, "xxv710-sfp28", "XXV710 25GbE SFP28", 0 ),
+ PCI_ROM ( 0x8086, 0x15ff, "x710-10gt-b", "X710 10GBASE-T", 0 ),
PCI_ROM ( 0x8086, 0x37ce, "x722-kx", "X722 10GbE backplane", 0 ),
PCI_ROM ( 0x8086, 0x37cf, "x722-qsfp", "X722 10GbE QSFP+", 0 ),
PCI_ROM ( 0x8086, 0x37d0, "x722-sfp", "X722 10GbE SFP+", 0 ),
diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h
index a4a776d28..6c7865aa2 100644
--- a/src/drivers/net/intelxl.h
+++ b/src/drivers/net/intelxl.h
@@ -145,6 +145,49 @@ struct intelxl_admin_shutdown_params {
/** Driver is unloading */
#define INTELXL_ADMIN_SHUTDOWN_UNLOADING 0x01
+/** Admin queue Manage MAC Address Read command */
+#define INTELXL_ADMIN_MAC_READ 0x0107
+
+/** Admin queue Manage MAC Address Read command parameters */
+struct intelxl_admin_mac_read_params {
+ /** Valid addresses */
+ uint8_t valid;
+ /** Reserved */
+ uint8_t reserved[15];
+} __attribute__ (( packed ));
+
+/** LAN MAC address is valid */
+#define INTELXL_ADMIN_MAC_READ_VALID_LAN 0x10
+
+/** Admin queue Manage MAC Address Read data buffer */
+struct intelxl_admin_mac_read_buffer {
+ /** Physical function MAC address */
+ uint8_t pf[ETH_ALEN];
+ /** Reserved */
+ uint8_t reserved[ETH_ALEN];
+ /** Port MAC address */
+ uint8_t port[ETH_ALEN];
+ /** Physical function wake-on-LAN MAC address */
+ uint8_t wol[ETH_ALEN];
+} __attribute__ (( packed ));
+
+/** Admin queue Manage MAC Address Write command */
+#define INTELXL_ADMIN_MAC_WRITE 0x0108
+
+/** Admin queue Manage MAC Address Write command parameters */
+struct intelxl_admin_mac_write_params {
+ /** Reserved */
+ uint8_t reserved_a[1];
+ /** Write type */
+ uint8_t type;
+ /** MAC address first 16 bits, byte-swapped */
+ uint16_t high;
+ /** MAC address last 32 bits, byte-swapped */
+ uint32_t low;
+ /** Reserved */
+ uint8_t reserved_b[8];
+} __attribute__ (( packed ));
+
/** Admin queue Clear PXE Mode command */
#define INTELXL_ADMIN_CLEAR_PXE 0x0110
@@ -263,6 +306,22 @@ struct intelxl_admin_promisc_params {
/** Promiscuous VLAN mode */
#define INTELXL_ADMIN_PROMISC_FL_VLAN 0x0010
+/** Admin queue Set MAC Configuration command */
+#define INTELXL_ADMIN_MAC_CONFIG 0x0603
+
+/** Admin queue Set MAC Configuration command parameters */
+struct intelxl_admin_mac_config_params {
+ /** Maximum frame size */
+ uint16_t mfs;
+ /** Flags */
+ uint8_t flags;
+ /** Reserved */
+ uint8_t reserved[13];
+} __attribute__ (( packed ));
+
+/** Append CRC on transmit */
+#define INTELXL_ADMIN_MAC_CONFIG_FL_CRC 0x04
+
/** Admin queue Restart Autonegotiation command */
#define INTELXL_ADMIN_AUTONEG 0x0605
@@ -305,172 +364,6 @@ struct intelxl_admin_link_params {
/** Link is up */
#define INTELXL_ADMIN_LINK_UP 0x01
-/** Admin queue Send Message to PF command */
-#define INTELXL_ADMIN_SEND_TO_PF 0x0801
-
-/** Admin queue Send Message to VF command */
-#define INTELXL_ADMIN_SEND_TO_VF 0x0802
-
-/** Admin Queue VF Reset opcode */
-#define INTELXL_ADMIN_VF_RESET 0x00000002
-
-/** Admin Queue VF Get Resources opcode */
-#define INTELXL_ADMIN_VF_GET_RESOURCES 0x00000003
-
-/** Admin Queue VF Get Resources data buffer */
-struct intelxl_admin_vf_get_resources_buffer {
- /** Reserved */
- uint8_t reserved_a[20];
- /** VSI switching element ID */
- uint16_t vsi;
- /** Reserved */
- uint8_t reserved_b[8];
- /** MAC address */
- uint8_t mac[ETH_ALEN];
-} __attribute__ (( packed ));
-
-/** Admin Queue VF Status Change Event opcode */
-#define INTELXL_ADMIN_VF_STATUS 0x00000011
-
-/** Link status change event type */
-#define INTELXL_ADMIN_VF_STATUS_LINK 0x00000001
-
-/** Link status change event data */
-struct intelxl_admin_vf_status_link {
- /** Link speed */
- uint32_t speed;
- /** Link status */
- uint8_t status;
- /** Reserved */
- uint8_t reserved[3];
-} __attribute__ (( packed ));
-
-/** Admin Queue VF Status Change Event data buffer */
-struct intelxl_admin_vf_status_buffer {
- /** Event type */
- uint32_t event;
- /** Event data */
- union {
- /** Link change event data */
- struct intelxl_admin_vf_status_link link;
- } data;
- /** Reserved */
- uint8_t reserved[4];
-} __attribute__ (( packed ));
-
-/** Admin Queue VF Configure Queues opcode */
-#define INTELXL_ADMIN_VF_CONFIGURE 0x00000006
-
-/** Admin Queue VF Configure Queues data buffer */
-struct intelxl_admin_vf_configure_buffer {
- /** VSI switching element ID */
- uint16_t vsi;
- /** Number of queue pairs */
- uint16_t count;
- /** Reserved */
- uint8_t reserved_a[4];
- /** Transmit queue */
- struct {
- /** VSI switching element ID */
- uint16_t vsi;
- /** Queue ID */
- uint16_t id;
- /** Queue count */
- uint16_t count;
- /** Reserved */
- uint8_t reserved_a[2];
- /** Base address */
- uint64_t base;
- /** Reserved */
- uint8_t reserved_b[8];
- } __attribute__ (( packed )) tx;
- /** Receive queue */
- struct {
- /** VSI switching element ID */
- uint16_t vsi;
- /** Queue ID */
- uint16_t id;
- /** Queue count */
- uint32_t count;
- /** Reserved */
- uint8_t reserved_a[4];
- /** Data buffer length */
- uint32_t len;
- /** Maximum frame size */
- uint32_t mfs;
- /** Reserved */
- uint8_t reserved_b[4];
- /** Base address */
- uint64_t base;
- /** Reserved */
- uint8_t reserved_c[8];
- } __attribute__ (( packed )) rx;
- /** Reserved
- *
- * This field exists only due to a bug in the PF driver's
- * message validation logic, which causes it to miscalculate
- * the expected message length.
- */
- uint8_t reserved_b[64];
-} __attribute__ (( packed ));
-
-/** Admin Queue VF IRQ Map opcode */
-#define INTELXL_ADMIN_VF_IRQ_MAP 0x00000007
-
-/** Admin Queue VF IRQ Map data buffer */
-struct intelxl_admin_vf_irq_map_buffer {
- /** Number of interrupt vectors */
- uint16_t count;
- /** VSI switching element ID */
- uint16_t vsi;
- /** Interrupt vector ID */
- uint16_t vec;
- /** Receive queue bitmap */
- uint16_t rxmap;
- /** Transmit queue bitmap */
- uint16_t txmap;
- /** Receive interrupt throttling index */
- uint16_t rxitr;
- /** Transmit interrupt throttling index */
- uint16_t txitr;
- /** Reserved
- *
- * This field exists only due to a bug in the PF driver's
- * message validation logic, which causes it to miscalculate
- * the expected message length.
- */
- uint8_t reserved[12];
-} __attribute__ (( packed ));
-
-/** Admin Queue VF Enable Queues opcode */
-#define INTELXL_ADMIN_VF_ENABLE 0x00000008
-
-/** Admin Queue VF Disable Queues opcode */
-#define INTELXL_ADMIN_VF_DISABLE 0x00000009
-
-/** Admin Queue VF Enable/Disable Queues data buffer */
-struct intelxl_admin_vf_queues_buffer {
- /** VSI switching element ID */
- uint16_t vsi;
- /** Reserved */
- uint8_t reserved[2];
- /** Receive queue bitmask */
- uint32_t rx;
- /** Transmit queue bitmask */
- uint32_t tx;
-} __attribute__ (( packed ));
-
-/** Admin Queue VF Configure Promiscuous Mode opcode */
-#define INTELXL_ADMIN_VF_PROMISC 0x0000000e
-
-/** Admin Queue VF Configure Promiscuous Mode data buffer */
-struct intelxl_admin_vf_promisc_buffer {
- /** VSI switching element ID */
- uint16_t vsi;
- /** Flags */
- uint16_t flags;
-} __attribute__ (( packed ));
-
/** Admin queue command parameters */
union intelxl_admin_params {
/** Additional data buffer command parameters */
@@ -481,6 +374,10 @@ union intelxl_admin_params {
struct intelxl_admin_driver_params driver;
/** Shutdown command parameters */
struct intelxl_admin_shutdown_params shutdown;
+ /** Manage MAC Address Read command parameters */
+ struct intelxl_admin_mac_read_params mac_read;
+ /** Manage MAC Address Write command parameters */
+ struct intelxl_admin_mac_write_params mac_write;
/** Clear PXE Mode command parameters */
struct intelxl_admin_clear_pxe_params pxe;
/** Get Switch Configuration command parameters */
@@ -489,34 +386,29 @@ union intelxl_admin_params {
struct intelxl_admin_vsi_params vsi;
/** Set VSI Promiscuous Modes command parameters */
struct intelxl_admin_promisc_params promisc;
+ /** Set MAC Configuration command parameters */
+ struct intelxl_admin_mac_config_params mac_config;
/** Restart Autonegotiation command parameters */
struct intelxl_admin_autoneg_params autoneg;
/** Get Link Status command parameters */
struct intelxl_admin_link_params link;
} __attribute__ (( packed ));
+/** Maximum size of a data buffer */
+#define INTELXL_ADMIN_BUFFER_SIZE 0x1000
+
/** Admin queue data buffer */
union intelxl_admin_buffer {
/** Driver Version data buffer */
struct intelxl_admin_driver_buffer driver;
+ /** Manage MAC Address Read data buffer */
+ struct intelxl_admin_mac_read_buffer mac_read;
/** Get Switch Configuration data buffer */
struct intelxl_admin_switch_buffer sw;
/** Get VSI Parameters data buffer */
struct intelxl_admin_vsi_buffer vsi;
- /** VF Get Resources data buffer */
- struct intelxl_admin_vf_get_resources_buffer res;
- /** VF Status Change Event data buffer */
- struct intelxl_admin_vf_status_buffer stat;
- /** VF Configure Queues data buffer */
- struct intelxl_admin_vf_configure_buffer cfg;
- /** VF Enable/Disable Queues data buffer */
- struct intelxl_admin_vf_queues_buffer queues;
- /** VF Configure Promiscuous Mode data buffer */
- struct intelxl_admin_vf_promisc_buffer promisc;
- /*** VF IRQ Map data buffer */
- struct intelxl_admin_vf_irq_map_buffer irq;
- /** Alignment padding */
- uint8_t pad[INTELXL_ALIGN];
+ /** Maximum buffer size */
+ uint8_t pad[INTELXL_ADMIN_BUFFER_SIZE];
} __attribute__ (( packed ));
/** Admin queue descriptor */
@@ -529,15 +421,10 @@ struct intelxl_admin_descriptor {
uint16_t len;
/** Return value */
uint16_t ret;
- /** Opaque cookie / VF opcode */
- union {
- /** Cookie */
- uint32_t cookie;
- /** VF opcode */
- uint32_t vopcode;
- };
- /** VF return value */
- int32_t vret;
+ /** Opaque cookie */
+ uint32_t cookie;
+ /** Reserved */
+ uint8_t reserved[4];
/** Parameters */
union intelxl_admin_params params;
} __attribute__ (( packed ));
@@ -557,6 +444,9 @@ struct intelxl_admin_descriptor {
/** Admin descriptor uses data buffer */
#define INTELXL_ADMIN_FL_BUF 0x1000
+/** Error: attempt to create something that already exists */
+#define INTELXL_ADMIN_EEXIST 13
+
/** Admin queue */
struct intelxl_admin {
/** Descriptors */
@@ -685,6 +575,8 @@ struct intelxl_context_rx {
uint8_t reserved_b[7];
/** Maximum frame size */
uint16_t mfs;
+ /** Reserved */
+ uint8_t reserved_c[8];
} __attribute__ (( packed ));
/** Receive queue base address and queue count */
@@ -755,10 +647,6 @@ struct intelxl_context_rx {
/** Queue Tail Pointer Register (offset) */
#define INTELXL_QXX_TAIL 0x8000
-/** Global RLAN Control 0 register */
-#define INTELXL_GLLAN_RCTL_0 0x12a500
-#define INTELXL_GLLAN_RCTL_0_PXE_MODE 0x00000001UL /**< PXE mode */
-
/** Transmit data descriptor */
struct intelxl_tx_data_descriptor {
/** Buffer address */
@@ -919,9 +807,9 @@ intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count, size_t len,
/** Number of receive descriptors
*
- * Must be a multiple of 32.
+ * Must be a multiple of 32 and greater than or equal to 64.
*/
-#define INTELXL_RX_NUM_DESC 32
+#define INTELXL_RX_NUM_DESC 64
/** Receive descriptor ring fill level
*
@@ -929,6 +817,9 @@ intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count, size_t len,
*/
#define INTELXL_RX_FILL 16
+/** Maximum packet length (excluding CRC) */
+#define INTELXL_MAX_PKT_LEN ( 9728 - 4 /* CRC */ )
+
/******************************************************************************
*
* Top level
@@ -983,17 +874,10 @@ intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count, size_t len,
INTELXL_QINT_TQCTL_NEXTQ_TYPE ( 0x1 ) /**< Transmit queue */
#define INTELXL_QINT_TQCTL_CAUSE_ENA 0x40000000UL /**< Enable */
-/** PF Control Register */
-#define INTELXL_PFGEN_CTRL 0x092400
-#define INTELXL_PFGEN_CTRL_PFSWR 0x00000001UL /**< Software Reset */
-
-/** Time to delay for device reset, in milliseconds */
-#define INTELXL_RESET_DELAY_MS 100
-
/** Function Requester ID Information Register */
#define INTELXL_PFFUNC_RID 0x09c000
#define INTELXL_PFFUNC_RID_FUNC_NUM(x) \
- ( ( (x) >> 0 ) & 0x3 ) /**< Function number */
+ ( ( (x) >> 0 ) & 0x7 ) /**< Function number */
/** PF Queue Allocation Register */
#define INTELXL_PFLAN_QALLOC 0x1c0400
@@ -1007,29 +891,6 @@ intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count, size_t len,
#define INTELXL_PFGEN_PORTNUM_PORT_NUM(x) \
( ( (x) >> 0 ) & 0x3 ) /**< Port number */
-/** Port MAC Address Low Register */
-#define INTELXL_PRTGL_SAL 0x1e2120
-
-/** Port MAC Address High Register */
-#define INTELXL_PRTGL_SAH 0x1e2140
-#define INTELXL_PRTGL_SAH_MFS_GET(x) ( (x) >> 16 ) /**< Max frame size */
-#define INTELXL_PRTGL_SAH_MFS_SET(x) ( (x) << 16 ) /**< Max frame size */
-
-/** Physical Function MAC Address Low Register */
-#define INTELXL_PRTPM_SAL 0x1e4440
-
-/** Physical Function MAC Address High Register */
-#define INTELXL_PRTPM_SAH 0x1e44c0
-
-/** Receive address */
-union intelxl_receive_address {
- struct {
- uint32_t low;
- uint32_t high;
- } __attribute__ (( packed )) reg;
- uint8_t raw[ETH_ALEN];
-};
-
/** MSI-X interrupt */
struct intelxl_msix {
/** PCI capability */
@@ -1040,7 +901,10 @@ struct intelxl_msix {
struct dma_mapping map;
};
-/** An Intel 40Gigabit network card */
+/** MSI-X interrupt vector */
+#define INTELXL_MSIX_VECTOR 0
+
+/** An Intel 40 Gigabit network card */
struct intelxl_nic {
/** Registers */
void *regs;
@@ -1061,6 +925,10 @@ struct intelxl_nic {
unsigned int vsi;
/** Queue set handle */
unsigned int qset;
+ /** Transmit element ID */
+ uint32_t teid;
+ /** Device capabilities */
+ uint32_t caps;
/** Interrupt control register */
unsigned int intr;
/** PCI Express capability offset */
@@ -1075,10 +943,6 @@ struct intelxl_nic {
/** Current VF opcode */
unsigned int vopcode;
- /** Current VF return value */
- int vret;
- /** Current VF event data buffer */
- union intelxl_admin_buffer vbuf;
/** Transmit descriptor ring */
struct intelxl_ring tx;
@@ -1086,17 +950,34 @@ struct intelxl_nic {
struct intelxl_ring rx;
/** Receive I/O buffers */
struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC];
+
+ /**
+ * Handle admin event
+ *
+ * @v netdev Network device
+ * @v evt Event descriptor
+ * @v buf Data buffer
+ */
+ void ( * handle ) ( struct net_device *netdev,
+ struct intelxl_admin_descriptor *evt,
+ union intelxl_admin_buffer *buf );
};
+extern const struct intelxl_admin_offsets intelxl_admin_offsets;
+
extern int intelxl_msix_enable ( struct intelxl_nic *intelxl,
- struct pci_device *pci );
+ struct pci_device *pci,
+ unsigned int vector );
extern void intelxl_msix_disable ( struct intelxl_nic *intelxl,
- struct pci_device *pci );
+ struct pci_device *pci,
+ unsigned int vector );
extern struct intelxl_admin_descriptor *
intelxl_admin_command_descriptor ( struct intelxl_nic *intelxl );
extern union intelxl_admin_buffer *
intelxl_admin_command_buffer ( struct intelxl_nic *intelxl );
extern int intelxl_admin_command ( struct intelxl_nic *intelxl );
+extern int intelxl_admin_clear_pxe ( struct intelxl_nic *intelxl );
+extern int intelxl_admin_mac_config ( struct intelxl_nic *intelxl );
extern void intelxl_poll_admin ( struct net_device *netdev );
extern int intelxl_open_admin ( struct intelxl_nic *intelxl );
extern void intelxl_reopen_admin ( struct intelxl_nic *intelxl );
@@ -1105,13 +986,13 @@ extern int intelxl_alloc_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring );
extern void intelxl_free_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring );
+extern int intelxl_create_ring ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring );
+extern void intelxl_destroy_ring ( struct intelxl_nic *intelxl,
+ struct intelxl_ring *ring );
extern void intelxl_empty_rx ( struct intelxl_nic *intelxl );
extern int intelxl_transmit ( struct net_device *netdev,
struct io_buffer *iobuf );
extern void intelxl_poll ( struct net_device *netdev );
-extern void intelxlvf_admin_event ( struct net_device *netdev,
- struct intelxl_admin_descriptor *evt,
- union intelxl_admin_buffer *buf );
-
#endif /* _INTELXL_H */
diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c
index 752de7815..083195513 100644
--- a/src/drivers/net/intelxlvf.c
+++ b/src/drivers/net/intelxlvf.c
@@ -46,23 +46,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/**
- * Reset hardware via PCIe function-level reset
- *
- * @v intelxl Intel device
- */
-static void intelxlvf_reset_flr ( struct intelxl_nic *intelxl,
- struct pci_device *pci ) {
- uint16_t control;
-
- /* Perform a PCIe function-level reset */
- pci_read_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
- &control );
- pci_write_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
- ( control | PCI_EXP_DEVCTL_FLR ) );
- mdelay ( INTELXL_RESET_DELAY_MS );
-}
-
-/**
* Wait for admin event queue to be torn down
*
* @v intelxl Intel device
@@ -120,26 +103,16 @@ static int intelxlvf_reset_wait_active ( struct intelxl_nic *intelxl ) {
}
/**
- * Reset hardware via admin queue
+ * Wait for reset to complete
*
* @v intelxl Intel device
* @ret rc Return status code
*/
-static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
- struct intelxl_admin_descriptor *cmd;
+static int intelxlvf_reset_wait ( struct intelxl_nic *intelxl ) {
int rc;
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_RESET );
-
- /* Issue command */
- if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
- goto err_command;
-
/* Wait for minimum reset time */
- mdelay ( INTELXL_RESET_DELAY_MS );
+ mdelay ( INTELXLVF_RESET_DELAY_MS );
/* Wait for reset to take effect */
if ( ( rc = intelxlvf_reset_wait_teardown ( intelxl ) ) != 0 )
@@ -152,10 +125,35 @@ static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
err_active:
err_teardown:
intelxl_reopen_admin ( intelxl );
- err_command:
return rc;
}
+/**
+ * Reset hardware via admin queue
+ *
+ * @v intelxl Intel device
+ * @ret rc Return status code
+ */
+static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
+ struct intelxlvf_admin_descriptor *cmd;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXLVF_ADMIN_SEND_TO_PF );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_RESET );
+
+ /* Issue command */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ /* Wait for reset to complete */
+ if ( ( rc = intelxlvf_reset_wait ( intelxl ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
/******************************************************************************
*
* Admin queue
@@ -190,13 +188,15 @@ static const struct intelxl_admin_offsets intelxlvf_admin_event_offsets = {
static int intelxlvf_admin_command ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
struct intelxl_admin *admin = &intelxl->command;
- struct intelxl_admin_descriptor *cmd;
+ struct intelxl_admin_descriptor *xlcmd;
+ struct intelxlvf_admin_descriptor *cmd;
unsigned int i;
int rc;
/* Populate descriptor */
- cmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
- cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
+ xlcmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
+ cmd = container_of ( xlcmd, struct intelxlvf_admin_descriptor, xl );
+ cmd->opcode = cpu_to_le16 ( INTELXLVF_ADMIN_SEND_TO_PF );
/* Record opcode */
intelxl->vopcode = le32_to_cpu ( cmd->vopcode );
@@ -218,7 +218,7 @@ static int intelxlvf_admin_command ( struct net_device *netdev ) {
}
/* Check for errors */
- if ( intelxl->vret != 0 )
+ if ( cmd->vret != 0 )
return -EIO;
return 0;
@@ -239,7 +239,7 @@ static int intelxlvf_admin_command ( struct net_device *netdev ) {
* @v link Link status
*/
static void intelxlvf_admin_link ( struct net_device *netdev,
- struct intelxl_admin_vf_status_link *link ) {
+ struct intelxlvf_admin_status_link *link ) {
struct intelxl_nic *intelxl = netdev->priv;
DBGC ( intelxl, "INTELXL %p link %#02x speed %#02x\n", intelxl,
@@ -261,12 +261,12 @@ static void intelxlvf_admin_link ( struct net_device *netdev,
*/
static void
intelxlvf_admin_status ( struct net_device *netdev,
- struct intelxl_admin_vf_status_buffer *stat ) {
+ struct intelxlvf_admin_status_buffer *stat ) {
struct intelxl_nic *intelxl = netdev->priv;
/* Handle event */
switch ( stat->event ) {
- case cpu_to_le32 ( INTELXL_ADMIN_VF_STATUS_LINK ):
+ case cpu_to_le32 ( INTELXLVF_ADMIN_STATUS_LINK ):
intelxlvf_admin_link ( netdev, &stat->data.link );
break;
default:
@@ -278,26 +278,42 @@ intelxlvf_admin_status ( struct net_device *netdev,
}
/**
- * Handle virtual function event
+ * Handle admin event
*
* @v netdev Network device
- * @v evt Admin queue event descriptor
- * @v buf Admin queue event data buffer
+ * @v xlevt Admin queue event descriptor
+ * @v xlbuf Admin queue event data buffer
*/
-void intelxlvf_admin_event ( struct net_device *netdev,
- struct intelxl_admin_descriptor *evt,
- union intelxl_admin_buffer *buf ) {
+static void intelxlvf_admin_event ( struct net_device *netdev,
+ struct intelxl_admin_descriptor *xlevt,
+ union intelxl_admin_buffer *xlbuf ) {
struct intelxl_nic *intelxl = netdev->priv;
- unsigned int vopcode = le32_to_cpu ( evt->vopcode );
+ struct intelxl_admin *admin = &intelxl->command;
+ struct intelxlvf_admin_descriptor *evt =
+ container_of ( xlevt, struct intelxlvf_admin_descriptor, xl );
+ union intelxlvf_admin_buffer *buf =
+ container_of ( xlbuf, union intelxlvf_admin_buffer, xl );
+ unsigned int vopcode;
+ unsigned int index;
+
+ /* Ignore unrecognised events */
+ if ( evt->opcode != cpu_to_le16 ( INTELXLVF_ADMIN_SEND_TO_VF ) ) {
+ DBGC ( intelxl, "INTELXL %p unrecognised event opcode "
+ "%#04x\n", intelxl, le16_to_cpu ( evt->opcode ) );
+ return;
+ }
/* Record command response if applicable */
+ vopcode = le32_to_cpu ( evt->vopcode );
if ( vopcode == intelxl->vopcode ) {
- memcpy ( &intelxl->vbuf, buf, sizeof ( intelxl->vbuf ) );
+ index = ( ( admin->index - 1 ) % INTELXL_ADMIN_NUM_DESC );
+ memcpy ( &admin->desc[index], evt, sizeof ( *evt ) );
+ memcpy ( &admin->buf[index], buf, sizeof ( *buf ) );
intelxl->vopcode = 0;
- intelxl->vret = le32_to_cpu ( evt->vret );
- if ( intelxl->vret != 0 ) {
+ if ( evt->vret != 0 ) {
DBGC ( intelxl, "INTELXL %p admin VF command %#x "
- "error %d\n", intelxl, vopcode, intelxl->vret );
+ "error %d\n", intelxl, vopcode,
+ le32_to_cpu ( evt->vret ) );
DBGC_HDA ( intelxl, virt_to_phys ( evt ), evt,
sizeof ( *evt ) );
DBGC_HDA ( intelxl, virt_to_phys ( buf ), buf,
@@ -308,7 +324,7 @@ void intelxlvf_admin_event ( struct net_device *netdev,
/* Handle unsolicited events */
switch ( vopcode ) {
- case INTELXL_ADMIN_VF_STATUS:
+ case INTELXLVF_ADMIN_STATUS:
intelxlvf_admin_status ( netdev, &buf->stat );
break;
default:
@@ -323,6 +339,45 @@ void intelxlvf_admin_event ( struct net_device *netdev,
}
/**
+ * Negotiate API version
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int intelxlvf_admin_version ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
+ unsigned int api;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_VERSION );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->ver ) );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
+ buf->ver.major = cpu_to_le32 ( INTELXLVF_ADMIN_API_MAJOR );
+ buf->ver.minor = cpu_to_le32 ( INTELXLVF_ADMIN_API_MINOR );
+
+ /* Issue command */
+ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
+ return rc;
+ api = le32_to_cpu ( buf->ver.major );
+ DBGC ( intelxl, "INTELXL %p API v%d.%d\n",
+ intelxl, api, le32_to_cpu ( buf->ver.minor ) );
+
+ /* Check for API compatibility */
+ if ( api > INTELXLVF_ADMIN_API_MAJOR ) {
+ DBGC ( intelxl, "INTELXL %p unsupported API v%d\n",
+ intelxl, api );
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/**
* Get resources
*
* @v netdev Network device
@@ -330,23 +385,116 @@ void intelxlvf_admin_event ( struct net_device *netdev,
*/
static int intelxlvf_admin_get_resources ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- struct intelxl_admin_vf_get_resources_buffer *res;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
int rc;
/* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_GET_RESOURCES );
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_GET_RESOURCES );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->caps ) );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
+ buf->caps.caps = cpu_to_le32 ( INTELXLVF_ADMIN_CAP_L2 |
+ INTELXLVF_ADMIN_CAP_RQPS );
/* Issue command */
if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
return rc;
/* Parse response */
- res = &intelxl->vbuf.res;
- intelxl->vsi = le16_to_cpu ( res->vsi );
- memcpy ( netdev->hw_addr, res->mac, ETH_ALEN );
- DBGC ( intelxl, "INTELXL %p VSI %#04x\n", intelxl, intelxl->vsi );
+ intelxl->caps = le32_to_cpu ( buf->res.caps );
+ intelxl->vsi = le16_to_cpu ( buf->res.vsi );
+ memcpy ( netdev->hw_addr, buf->res.mac, ETH_ALEN );
+ DBGC ( intelxl, "INTELXL %p capabilities %#08x VSI %#04x\n",
+ intelxl, intelxl->caps, intelxl->vsi );
+
+ return 0;
+}
+
+/**
+ * Get statistics (for debugging)
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int intelxlvf_admin_stats ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
+ struct intelxlvf_admin_stats *tx;
+ struct intelxlvf_admin_stats *rx;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_GET_STATS );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->queues ) );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
+ buf->queues.vsi = cpu_to_le16 ( intelxl->vsi );
+ tx = &buf->stats.tx;
+ rx = &buf->stats.rx;
+
+ /* Issue command */
+ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
+ return rc;
+ DBGC ( intelxl, "INTELXL %p TX bytes %#llx discards %#llx errors "
+ "%#llx\n", intelxl,
+ ( ( unsigned long long ) le64_to_cpu ( tx->bytes ) ),
+ ( ( unsigned long long ) le64_to_cpu ( tx->discards ) ),
+ ( ( unsigned long long ) le64_to_cpu ( tx->errors ) ) );
+ DBGC ( intelxl, "INTELXL %p TX unicasts %#llx multicasts %#llx "
+ "broadcasts %#llx\n", intelxl,
+ ( ( unsigned long long ) le64_to_cpu ( tx->unicasts ) ),
+ ( ( unsigned long long ) le64_to_cpu ( tx->multicasts ) ),
+ ( ( unsigned long long ) le64_to_cpu ( tx->broadcasts ) ) );
+ DBGC ( intelxl, "INTELXL %p RX bytes %#llx discards %#llx errors "
+ "%#llx\n", intelxl,
+ ( ( unsigned long long ) le64_to_cpu ( rx->bytes ) ),
+ ( ( unsigned long long ) le64_to_cpu ( rx->discards ) ),
+ ( ( unsigned long long ) le64_to_cpu ( rx->errors ) ) );
+ DBGC ( intelxl, "INTELXL %p RX unicasts %#llx multicasts %#llx "
+ "broadcasts %#llx\n", intelxl,
+ ( ( unsigned long long ) le64_to_cpu ( rx->unicasts ) ),
+ ( ( unsigned long long ) le64_to_cpu ( rx->multicasts ) ),
+ ( ( unsigned long long ) le64_to_cpu ( rx->broadcasts ) ) );
+
+ return 0;
+}
+
+/**
+ * Configure number of queue pairs
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int intelxlvf_admin_request_qps ( struct net_device *netdev ) {
+ struct intelxl_nic *intelxl = netdev->priv;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
+ int rc;
+
+ /* Populate descriptor */
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->opcode = cpu_to_le16 ( INTELXLVF_ADMIN_SEND_TO_PF );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_REQUEST_QPS );
+ cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
+ cmd->len = cpu_to_le16 ( sizeof ( buf->rqps ) );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
+ buf->rqps.count = cpu_to_le16 ( 1 );
+
+ /* Issue command (which will trigger a reset) */
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
+ return rc;
+
+ /* Wait for reset to complete */
+ if ( ( rc = intelxlvf_reset_wait ( intelxl ) ) != 0 )
+ return rc;
+
+ /* Reestablish capabilities to reactivate VF after reset */
+ if ( ( rc = intelxlvf_admin_get_resources ( netdev ) ) != 0 )
+ return rc;
return 0;
}
@@ -366,16 +514,16 @@ static int intelxlvf_admin_get_resources ( struct net_device *netdev ) {
*/
static int intelxlvf_admin_configure ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
int rc;
/* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_CONFIGURE );
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_CONFIGURE );
cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
cmd->len = cpu_to_le16 ( sizeof ( buf->cfg ) );
- buf = intelxl_admin_command_buffer ( intelxl );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
buf->cfg.vsi = cpu_to_le16 ( intelxl->vsi );
buf->cfg.count = cpu_to_le16 ( 1 );
buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi );
@@ -404,18 +552,19 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) {
*/
static int intelxlvf_admin_irq_map ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
int rc;
/* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_IRQ_MAP );
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_IRQ_MAP );
cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
cmd->len = cpu_to_le16 ( sizeof ( buf->irq ) );
- buf = intelxl_admin_command_buffer ( intelxl );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
buf->irq.count = cpu_to_le16 ( 1 );
buf->irq.vsi = cpu_to_le16 ( intelxl->vsi );
+ buf->irq.vec = cpu_to_le16 ( INTELXLVF_MSIX_VECTOR );
buf->irq.rxmap = cpu_to_le16 ( 0x0001 );
buf->irq.txmap = cpu_to_le16 ( 0x0001 );
@@ -435,17 +584,17 @@ static int intelxlvf_admin_irq_map ( struct net_device *netdev ) {
*/
static int intelxlvf_admin_queues ( struct net_device *netdev, int enable ) {
struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
int rc;
/* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = ( enable ? cpu_to_le32 ( INTELXL_ADMIN_VF_ENABLE ) :
- cpu_to_le32 ( INTELXL_ADMIN_VF_DISABLE ) );
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = ( enable ? cpu_to_le32 ( INTELXLVF_ADMIN_ENABLE ) :
+ cpu_to_le32 ( INTELXLVF_ADMIN_DISABLE ) );
cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
cmd->len = cpu_to_le16 ( sizeof ( buf->queues ) );
- buf = intelxl_admin_command_buffer ( intelxl );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
buf->queues.vsi = cpu_to_le16 ( intelxl->vsi );
buf->queues.rx = cpu_to_le32 ( 1 );
buf->queues.tx = cpu_to_le32 ( 1 );
@@ -465,16 +614,16 @@ static int intelxlvf_admin_queues ( struct net_device *netdev, int enable ) {
*/
static int intelxlvf_admin_promisc ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
+ struct intelxlvf_admin_descriptor *cmd;
+ union intelxlvf_admin_buffer *buf;
int rc;
/* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_PROMISC );
+ cmd = intelxlvf_admin_command_descriptor ( intelxl );
+ cmd->vopcode = cpu_to_le32 ( INTELXLVF_ADMIN_PROMISC );
cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
cmd->len = cpu_to_le16 ( sizeof ( buf->promisc ) );
- buf = intelxl_admin_command_buffer ( intelxl );
+ buf = intelxlvf_admin_command_buffer ( intelxl );
buf->promisc.vsi = cpu_to_le16 ( intelxl->vsi );
buf->promisc.flags = cpu_to_le16 ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
INTELXL_ADMIN_PROMISC_FL_MULTICAST );
@@ -524,10 +673,14 @@ static int intelxlvf_open ( struct net_device *netdev ) {
if ( ( rc = intelxlvf_admin_promisc ( netdev ) ) != 0 )
goto err_promisc;
+ /* Reset statistics counters (if debugging) */
+ if ( DBG_LOG )
+ intelxlvf_admin_stats ( netdev );
+
return 0;
err_promisc:
- intelxlvf_admin_queues ( netdev, INTELXL_ADMIN_VF_DISABLE );
+ intelxlvf_admin_queues ( netdev, 0 );
err_enable:
err_irq_map:
err_configure:
@@ -547,6 +700,10 @@ static void intelxlvf_close ( struct net_device *netdev ) {
struct intelxl_nic *intelxl = netdev->priv;
int rc;
+ /* Show statistics (if debugging) */
+ if ( DBG_LOG )
+ intelxlvf_admin_stats ( netdev );
+
/* Disable queues */
if ( ( rc = intelxlvf_admin_queues ( netdev, 0 ) ) != 0 ) {
/* Leak memory; there's nothing else we can do */
@@ -600,7 +757,8 @@ static int intelxlvf_probe ( struct pci_device *pci ) {
pci_set_drvdata ( pci, netdev );
netdev->dev = &pci->dev;
memset ( intelxl, 0, sizeof ( *intelxl ) );
- intelxl->intr = INTELXLVF_VFINT_DYN_CTL0;
+ intelxl->intr = INTELXLVF_VFINT_DYN_CTLN ( INTELXLVF_MSIX_VECTOR );
+ intelxl->handle = intelxlvf_admin_event;
intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN,
&intelxlvf_admin_command_offsets );
intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN,
@@ -637,10 +795,11 @@ static int intelxlvf_probe ( struct pci_device *pci ) {
}
/* Reset the function via PCIe FLR */
- intelxlvf_reset_flr ( intelxl, pci );
+ pci_reset ( pci, intelxl->exp );
/* Enable MSI-X dummy interrupt */
- if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
+ if ( ( rc = intelxl_msix_enable ( intelxl, pci,
+ INTELXLVF_MSIX_VECTOR ) ) != 0 )
goto err_msix;
/* Open admin queues */
@@ -651,10 +810,19 @@ static int intelxlvf_probe ( struct pci_device *pci ) {
if ( ( rc = intelxlvf_reset_admin ( intelxl ) ) != 0 )
goto err_reset_admin;
+ /* Negotiate API version */
+ if ( ( rc = intelxlvf_admin_version ( netdev ) ) != 0 )
+ goto err_version;
+
/* Get MAC address */
if ( ( rc = intelxlvf_admin_get_resources ( netdev ) ) != 0 )
goto err_get_resources;
+ /* Configure number of queue pairs, if applicable */
+ if ( ( intelxl->caps & INTELXLVF_ADMIN_CAP_RQPS ) &&
+ ( ( rc = intelxlvf_admin_request_qps ( netdev ) ) != 0 ) )
+ goto err_rqps;
+
/* Register network device */
if ( ( rc = register_netdev ( netdev ) ) != 0 )
goto err_register_netdev;
@@ -663,13 +831,15 @@ static int intelxlvf_probe ( struct pci_device *pci ) {
unregister_netdev ( netdev );
err_register_netdev:
+ err_rqps:
err_get_resources:
+ err_version:
err_reset_admin:
intelxl_close_admin ( intelxl );
err_open_admin:
- intelxl_msix_disable ( intelxl, pci );
+ intelxl_msix_disable ( intelxl, pci, INTELXLVF_MSIX_VECTOR );
err_msix:
- intelxlvf_reset_flr ( intelxl, pci );
+ pci_reset ( pci, intelxl->exp );
err_exp:
iounmap ( intelxl->regs );
err_ioremap:
@@ -698,10 +868,10 @@ static void intelxlvf_remove ( struct pci_device *pci ) {
intelxl_close_admin ( intelxl );
/* Disable MSI-X dummy interrupt */
- intelxl_msix_disable ( intelxl, pci );
+ intelxl_msix_disable ( intelxl, pci, INTELXLVF_MSIX_VECTOR );
/* Reset the function via PCIe FLR */
- intelxlvf_reset_flr ( intelxl, pci );
+ pci_reset ( pci, intelxl->exp );
/* Free network device */
iounmap ( intelxl->regs );
@@ -713,7 +883,7 @@ static void intelxlvf_remove ( struct pci_device *pci ) {
static struct pci_device_id intelxlvf_nics[] = {
PCI_ROM ( 0x8086, 0x154c, "xl710-vf", "XL710 VF", 0 ),
PCI_ROM ( 0x8086, 0x1571, "xl710-vf-hv", "XL710 VF (Hyper-V)", 0 ),
- PCI_ROM ( 0x8086, 0x1889, "xl710-vf-ad", "XL710 VF (adaptive)", 0 ),
+ PCI_ROM ( 0x8086, 0x1889, "iavf", "Intel adaptive VF", 0 ),
PCI_ROM ( 0x8086, 0x37cd, "x722-vf", "X722 VF", 0 ),
PCI_ROM ( 0x8086, 0x37d9, "x722-vf-hv", "X722 VF (Hyper-V)", 0 ),
};
diff --git a/src/drivers/net/intelxlvf.h b/src/drivers/net/intelxlvf.h
index ffcae5674..95ddf9474 100644
--- a/src/drivers/net/intelxlvf.h
+++ b/src/drivers/net/intelxlvf.h
@@ -14,12 +14,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** BAR size */
#define INTELXLVF_BAR_SIZE 0x10000
+/** MSI-X vector
+ *
+ * The 100 Gigabit physical function driver requires a virtual
+ * function driver to request that transmit and receive queues are
+ * mapped to MSI-X vector 1 or higher.
+ */
+#define INTELXLVF_MSIX_VECTOR 1
+
/** Transmit Queue Tail Register */
#define INTELXLVF_QTX_TAIL 0x00000
/** Receive Queue Tail Register */
#define INTELXLVF_QRX_TAIL 0x02000
+/** VF Interrupt N Dynamic Control Register */
+#define INTELXLVF_VFINT_DYN_CTLN( x ) ( 0x3800 + ( 0x4 * ( (x) - 1 ) ) )
+
/** VF Interrupt Zero Dynamic Control Register */
#define INTELXLVF_VFINT_DYN_CTL0 0x5c00
@@ -59,11 +70,335 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Maximum time to wait for a VF admin request to complete */
#define INTELXLVF_ADMIN_MAX_WAIT_MS 2000
+/** Admin queue Send Message to PF command */
+#define INTELXLVF_ADMIN_SEND_TO_PF 0x0801
+
+/** Admin queue Send Message to VF command */
+#define INTELXLVF_ADMIN_SEND_TO_VF 0x0802
+
+/** Admin Queue VF Version opcode */
+#define INTELXLVF_ADMIN_VERSION 0x00000001
+
+/** Admin Queue VF Version data buffer */
+struct intelxlvf_admin_version_buffer {
+ /** Major version */
+ uint32_t major;
+ /** Minor version */
+ uint32_t minor;
+} __attribute__ (( packed ));
+
+/** Admin queue VF API major version */
+#define INTELXLVF_ADMIN_API_MAJOR 1
+
+/** Admin queue VF API minor version */
+#define INTELXLVF_ADMIN_API_MINOR 1
+
+/** Admin Queue VF Reset opcode */
+#define INTELXLVF_ADMIN_RESET 0x00000002
+
+/** Admin Queue VF Get Resources opcode */
+#define INTELXLVF_ADMIN_GET_RESOURCES 0x00000003
+
+/** Admin Queue VF Capabilities data buffer */
+struct intelxlvf_admin_capabilities_buffer {
+ /** Capabilities */
+ uint32_t caps;
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Get Resources data buffer */
+struct intelxlvf_admin_get_resources_buffer {
+ /** Number of VSIs */
+ uint16_t vsis;
+ /** Number of queue pairs */
+ uint16_t qps;
+ /** Number of MSI-X vectors */
+ uint16_t vectors;
+ /** Maximum MTU */
+ uint16_t mtu;
+ /** Capabilities */
+ uint32_t caps;
+ /** Reserved */
+ uint8_t reserved_a[8];
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Reserved */
+ uint8_t reserved_b[8];
+ /** MAC address */
+ uint8_t mac[ETH_ALEN];
+} __attribute__ (( packed ));
+
+/** Layer 2 capabilities (add/remove MAC, configure promiscuous mode) */
+#define INTELXLVF_ADMIN_CAP_L2 0x00000001
+
+/** Request Queues capabilities */
+#define INTELXLVF_ADMIN_CAP_RQPS 0x00000040
+
+/** Admin Queue VF Status Change Event opcode */
+#define INTELXLVF_ADMIN_STATUS 0x00000011
+
+/** Link status change event type */
+#define INTELXLVF_ADMIN_STATUS_LINK 0x00000001
+
+/** Link status change event data */
+struct intelxlvf_admin_status_link {
+ /** Link speed */
+ uint32_t speed;
+ /** Link status */
+ uint8_t status;
+ /** Reserved */
+ uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Status Change Event data buffer */
+struct intelxlvf_admin_status_buffer {
+ /** Event type */
+ uint32_t event;
+ /** Event data */
+ union {
+ /** Link change event data */
+ struct intelxlvf_admin_status_link link;
+ } data;
+ /** Reserved */
+ uint8_t reserved[4];
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Configure Queues opcode */
+#define INTELXLVF_ADMIN_CONFIGURE 0x00000006
+
+/** Admin Queue VF Configure Queues data buffer */
+struct intelxlvf_admin_configure_buffer {
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Number of queue pairs */
+ uint16_t count;
+ /** Reserved */
+ uint8_t reserved_a[4];
+ /** Transmit queue */
+ struct {
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Queue ID */
+ uint16_t id;
+ /** Queue count */
+ uint16_t count;
+ /** Reserved */
+ uint8_t reserved_a[2];
+ /** Base address */
+ uint64_t base;
+ /** Reserved */
+ uint8_t reserved_b[8];
+ } __attribute__ (( packed )) tx;
+ /** Receive queue */
+ struct {
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Queue ID */
+ uint16_t id;
+ /** Queue count */
+ uint32_t count;
+ /** Reserved */
+ uint8_t reserved_a[4];
+ /** Data buffer length */
+ uint32_t len;
+ /** Maximum frame size */
+ uint32_t mfs;
+ /** Reserved */
+ uint8_t reserved_b[4];
+ /** Base address */
+ uint64_t base;
+ /** Reserved */
+ uint8_t reserved_c[8];
+ } __attribute__ (( packed )) rx;
+ /** Reserved
+ *
+ * This field exists only due to a bug in the PF driver's
+ * message validation logic, which causes it to miscalculate
+ * the expected message length.
+ */
+ uint8_t reserved_b[64];
+} __attribute__ (( packed ));
+
+/** Admin Queue VF IRQ Map opcode */
+#define INTELXLVF_ADMIN_IRQ_MAP 0x00000007
+
+/** Admin Queue VF IRQ Map data buffer */
+struct intelxlvf_admin_irq_map_buffer {
+ /** Number of interrupt vectors */
+ uint16_t count;
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Interrupt vector ID */
+ uint16_t vec;
+ /** Receive queue bitmap */
+ uint16_t rxmap;
+ /** Transmit queue bitmap */
+ uint16_t txmap;
+ /** Receive interrupt throttling index */
+ uint16_t rxitr;
+ /** Transmit interrupt throttling index */
+ uint16_t txitr;
+ /** Reserved
+ *
+ * This field exists only due to a bug in the PF driver's
+ * message validation logic, which causes it to miscalculate
+ * the expected message length.
+ */
+ uint8_t reserved[12];
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Enable Queues opcode */
+#define INTELXLVF_ADMIN_ENABLE 0x00000008
+
+/** Admin Queue VF Disable Queues opcode */
+#define INTELXLVF_ADMIN_DISABLE 0x00000009
+
+/** Admin Queue VF Enable/Disable Queues data buffer */
+struct intelxlvf_admin_queues_buffer {
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Reserved */
+ uint8_t reserved[2];
+ /** Receive queue bitmask */
+ uint32_t rx;
+ /** Transmit queue bitmask */
+ uint32_t tx;
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Configure Promiscuous Mode opcode */
+#define INTELXLVF_ADMIN_PROMISC 0x0000000e
+
+/** Admin Queue VF Configure Promiscuous Mode data buffer */
+struct intelxlvf_admin_promisc_buffer {
+ /** VSI switching element ID */
+ uint16_t vsi;
+ /** Flags */
+ uint16_t flags;
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Get Statistics opcode */
+#define INTELXLVF_ADMIN_GET_STATS 0x0000000f
+
+/** VF statistics */
+struct intelxlvf_admin_stats {
+ /** Bytes */
+ uint64_t bytes;
+ /** Unicast packets */
+ uint64_t unicasts;
+ /** Multicast packets */
+ uint64_t multicasts;
+ /** Broadcast packets */
+ uint64_t broadcasts;
+ /** Discarded packets */
+ uint64_t discards;
+ /** Errors */
+ uint64_t errors;
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Get Statistics data buffer */
+struct intelxlvf_admin_stats_buffer {
+ /** Receive statistics */
+ struct intelxlvf_admin_stats rx;
+ /** Transmit statistics */
+ struct intelxlvf_admin_stats tx;
+} __attribute__ (( packed ));
+
+/** Admin Queue VF Request Queues opcode */
+#define INTELXLVF_ADMIN_REQUEST_QPS 0x0000001d
+
+/** Admin Queue VF Request Queues data buffer */
+struct intelxlvf_admin_request_qps_buffer {
+ /** Number of queue pairs */
+ uint16_t count;
+} __attribute__ (( packed ));
+
+/** Admin queue data buffer */
+union intelxlvf_admin_buffer {
+ /** Original 40 Gigabit Ethernet data buffer */
+ union intelxl_admin_buffer xl;
+ /** VF Version data buffer */
+ struct intelxlvf_admin_version_buffer ver;
+ /** VF Capabilities data buffer */
+ struct intelxlvf_admin_capabilities_buffer caps;
+ /** VF Get Resources data buffer */
+ struct intelxlvf_admin_get_resources_buffer res;
+ /** VF Status Change Event data buffer */
+ struct intelxlvf_admin_status_buffer stat;
+ /** VF Configure Queues data buffer */
+ struct intelxlvf_admin_configure_buffer cfg;
+ /** VF Enable/Disable Queues data buffer */
+ struct intelxlvf_admin_queues_buffer queues;
+ /** VF Configure Promiscuous Mode data buffer */
+ struct intelxlvf_admin_promisc_buffer promisc;
+ /** VF IRQ Map data buffer */
+ struct intelxlvf_admin_irq_map_buffer irq;
+ /** VF Get Statistics data buffer */
+ struct intelxlvf_admin_stats_buffer stats;
+ /** VF Request Queues data buffer */
+ struct intelxlvf_admin_request_qps_buffer rqps;
+} __attribute__ (( packed ));
+
+/** Admin queue descriptor */
+struct intelxlvf_admin_descriptor {
+ /** Transparent union */
+ union {
+ /** Original 40 Gigabit Ethernet descriptor */
+ struct intelxl_admin_descriptor xl;
+ /** Transparent struct */
+ struct {
+ /** Flags */
+ uint16_t flags;
+ /** Opcode */
+ uint16_t opcode;
+ /** Data length */
+ uint16_t len;
+ /** Return value */
+ uint16_t ret;
+ /** VF opcode */
+ uint32_t vopcode;
+ /** VF return value */
+ int32_t vret;
+ /** Parameters */
+ union intelxl_admin_params params;
+ } __attribute__ (( packed ));
+ } __attribute__ (( packed ));
+} __attribute__ (( packed ));
+
+/**
+ * Get next admin command queue descriptor
+ *
+ * @v intelxl Intel device
+ * @ret cmd Command descriptor
+ */
+struct intelxlvf_admin_descriptor *
+intelxlvf_admin_command_descriptor ( struct intelxl_nic *intelxl ) {
+ struct intelxl_admin_descriptor *xlcmd =
+ intelxl_admin_command_descriptor ( intelxl );
+
+ return container_of ( xlcmd, struct intelxlvf_admin_descriptor, xl );
+}
+
+/**
+ * Get next admin command queue data buffer
+ *
+ * @v intelxl Intel device
+ * @ret buf Data buffer
+ */
+static inline __attribute__ (( always_inline )) union intelxlvf_admin_buffer *
+intelxlvf_admin_command_buffer ( struct intelxl_nic *intelxl ) {
+ union intelxl_admin_buffer *xlbuf =
+ intelxl_admin_command_buffer ( intelxl );
+
+ return container_of ( xlbuf, union intelxlvf_admin_buffer, xl );
+}
+
/** VF Reset Status Register */
#define INTELXLVF_VFGEN_RSTAT 0x8800
#define INTELXLVF_VFGEN_RSTAT_VFR_STATE(x) ( (x) & 0x3 )
#define INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE 0x2
+/** Minimum time to wait for reset to complete */
+#define INTELXLVF_RESET_DELAY_MS 100
+
/** Maximum time to wait for reset to complete */
#define INTELXLVF_RESET_MAX_WAIT_MS 1000
diff --git a/src/drivers/net/ncm.c b/src/drivers/net/ncm.c
index 1e8088d76..2c0f91e21 100644
--- a/src/drivers/net/ncm.c
+++ b/src/drivers/net/ncm.c
@@ -598,7 +598,7 @@ static int ncm_probe ( struct usb_function *func,
}
/* Fetch MAC address */
- if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
+ if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev ) ) != 0 ) {
DBGC ( ncm, "NCM %p could not fetch MAC address: %s\n",
ncm, strerror ( rc ) );
goto err_fetch_mac;
diff --git a/src/hci/commands/pci_cmd.c b/src/hci/commands/pci_cmd.c
index a2a811aa0..5bae66fbe 100644
--- a/src/hci/commands/pci_cmd.c
+++ b/src/hci/commands/pci_cmd.c
@@ -22,6 +22,7 @@
*/
#include <stdio.h>
+#include <errno.h>
#include <getopt.h>
#include <ipxe/pci.h>
#include <ipxe/command.h>
@@ -58,7 +59,7 @@ static int pciscan_exec ( int argc, char **argv ) {
struct named_setting setting;
struct pci_device pci;
unsigned long prev;
- int next;
+ uint32_t busdevfn;
int len;
int rc;
@@ -75,17 +76,19 @@ static int pciscan_exec ( int argc, char **argv ) {
if ( ( len = fetchn_setting ( setting.settings, &setting.setting,
NULL, &setting.setting, &prev ) ) < 0 ) {
/* Setting not yet defined: start searching from 00:00.0 */
- prev = 0;
+ busdevfn = 0;
} else {
/* Setting is defined: start searching from next location */
- prev++;
+ busdevfn = ( prev + 1 );
+ if ( ! busdevfn ) {
+ rc = -ENOENT;
+ goto err_end;
+ }
}
/* Find next existent PCI device */
- if ( ( next = pci_find_next ( &pci, prev ) ) < 0 ) {
- rc = next;
+ if ( ( rc = pci_find_next ( &pci, &busdevfn ) ) != 0 )
goto err_find_next;
- }
/* Apply default type if necessary. Use ":uint16" rather than
* ":busdevfn" to allow for easy inclusion within a
@@ -96,13 +99,14 @@ static int pciscan_exec ( int argc, char **argv ) {
/* Store setting */
if ( ( rc = storen_setting ( setting.settings, &setting.setting,
- next ) ) != 0 ) {
+ busdevfn ) ) != 0 ) {
printf ( "Could not store \"%s\": %s\n",
setting.setting.name, strerror ( rc ) );
goto err_store;
}
err_store:
+ err_end:
err_find_next:
err_parse_setting:
err_parse_options:
diff --git a/src/include/ipxe/dhe.h b/src/include/ipxe/dhe.h
new file mode 100644
index 000000000..3cd24a880
--- /dev/null
+++ b/src/include/ipxe/dhe.h
@@ -0,0 +1,19 @@
+#ifndef _IPXE_DHE_H
+#define _IPXE_DHE_H
+
+/** @file
+ *
+ * Ephemeral Diffie-Hellman key exchange
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+extern int dhe_key ( const void *modulus, size_t len, const void *generator,
+ size_t generator_len, const void *partner,
+ size_t partner_len, const void *private,
+ size_t private_len, void *public, void *shared );
+
+#endif /* _IPXE_DHE_H */
diff --git a/src/include/ipxe/ecam.h b/src/include/ipxe/ecam.h
new file mode 100644
index 000000000..683d613a0
--- /dev/null
+++ b/src/include/ipxe/ecam.h
@@ -0,0 +1,57 @@
+#ifndef _IPXE_ECAM_H
+#define _IPXE_ECAM_H
+
+/** @file
+ *
+ * PCI I/O API for Enhanced Configuration Access Mechanism (ECAM)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/acpi.h>
+#include <ipxe/pci.h>
+
+/** Enhanced Configuration Access Mechanism per-device size */
+#define ECAM_SIZE 4096
+
+/** Enhanced Configuration Access Mechanism table signature */
+#define ECAM_SIGNATURE ACPI_SIGNATURE ( 'M', 'C', 'F', 'G' )
+
+/** An Enhanced Configuration Access Mechanism allocation */
+struct ecam_allocation {
+ /** Base address */
+ uint64_t base;
+ /** PCI segment number */
+ uint16_t segment;
+ /** Start PCI bus number */
+ uint8_t start;
+ /** End PCI bus number */
+ uint8_t end;
+ /** Reserved */
+ uint8_t reserved[4];
+} __attribute__ (( packed ));
+
+/** An Enhanced Configuration Access Mechanism table */
+struct ecam_table {
+ /** ACPI header */
+ struct acpi_header acpi;
+ /** Reserved */
+ uint8_t reserved[8];
+ /** Allocation structures */
+ struct ecam_allocation alloc[0];
+} __attribute__ (( packed ));
+
+/** A mapped Enhanced Configuration Access Mechanism allocation */
+struct ecam_mapping {
+ /** Allocation */
+ struct ecam_allocation alloc;
+ /** PCI bus:dev.fn address range */
+ struct pci_range range;
+ /** MMIO base address */
+ void *regs;
+};
+
+extern struct pci_api ecam_api;
+
+#endif /* _IPXE_ECAM_H */
diff --git a/src/include/ipxe/ecam_io.h b/src/include/ipxe/ecam_io.h
new file mode 100644
index 000000000..4fb24db33
--- /dev/null
+++ b/src/include/ipxe/ecam_io.h
@@ -0,0 +1,139 @@
+#ifndef _IPXE_ECAM_IO_H
+#define _IPXE_ECAM_IO_H
+
+/** @file
+ *
+ * PCI I/O API for Enhanced Configuration Access Mechanism (ECAM)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+#ifdef PCIAPI_ECAM
+#define PCIAPI_PREFIX_ecam
+#else
+#define PCIAPI_PREFIX_ecam __ecam_
+#endif
+
+struct pci_device;
+
+/** Construct ECAM location */
+#define ECAM_LOC( where, len ) ( ( (len) << 16 ) | where )
+
+/** Extract offset from ECAM location */
+#define ECAM_WHERE( location ) ( (location) & 0xffff )
+
+/** Extract length from ECAM location */
+#define ECAM_LEN( location ) ( (location) >> 16 )
+
+extern int ecam_read ( struct pci_device *pci, unsigned int location,
+ void *value );
+extern int ecam_write ( struct pci_device *pci, unsigned int location,
+ unsigned long value );
+
+/**
+ * Read byte from PCI configuration space via ECAM
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( ecam, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
+ return ecam_read ( pci, ECAM_LOC ( where, sizeof ( *value ) ), value );
+}
+
+/**
+ * Read word from PCI configuration space via ECAM
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( ecam, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
+ return ecam_read ( pci, ECAM_LOC ( where, sizeof ( *value ) ), value );
+}
+
+/**
+ * Read dword from PCI configuration space via ECAM
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( ecam, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
+ return ecam_read ( pci, ECAM_LOC ( where, sizeof ( *value ) ), value );
+}
+
+/**
+ * Write byte to PCI configuration space via ECAM
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( ecam, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
+ return ecam_write ( pci, ECAM_LOC ( where, sizeof ( value ) ), value );
+}
+
+/**
+ * Write word to PCI configuration space via ECAM
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( ecam, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
+ return ecam_write ( pci, ECAM_LOC ( where, sizeof ( value ) ), value );
+}
+
+/**
+ * Write dword to PCI configuration space via ECAM
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( ecam, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
+ return ecam_write ( pci, ECAM_LOC ( where, sizeof ( value ) ), value );
+}
+
+/**
+ * Map PCI bus address as an I/O address
+ *
+ * @v bus_addr PCI bus address
+ * @v len Length of region
+ * @ret io_addr I/O address, or NULL on error
+ */
+static inline __always_inline void *
+PCIAPI_INLINE ( ecam, pci_ioremap ) ( struct pci_device *pci __unused,
+ unsigned long bus_addr, size_t len ) {
+ return ioremap ( bus_addr, len );
+}
+
+#endif /* _IPXE_ECAM_IO_H */
diff --git a/src/include/ipxe/efi/efi_pci_api.h b/src/include/ipxe/efi/efi_pci_api.h
index 887d5ee14..cf5e1d020 100644
--- a/src/include/ipxe/efi/efi_pci_api.h
+++ b/src/include/ipxe/efi/efi_pci_api.h
@@ -33,14 +33,17 @@ extern int efipci_write ( struct pci_device *pci, unsigned long location,
unsigned long value );
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static inline __always_inline int
-PCIAPI_INLINE ( efi, pci_num_bus ) ( void ) {
+static inline __always_inline void
+PCIAPI_INLINE ( efi, pci_discover ) ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
+
/* EFI does not want us to scan the PCI bus ourselves */
- return 0;
+ range->count = 0;
}
/**
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index 81f555725..c3541e8a0 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.h
@@ -215,6 +215,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 )
#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 )
#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
+#define ERRFILE_ice ( ERRFILE_DRIVER | 0x00d20000 )
+#define ERRFILE_ecam ( ERRFILE_DRIVER | 0x00d30000 )
+#define ERRFILE_pcibridge ( ERRFILE_DRIVER | 0x00d40000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
@@ -396,6 +399,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_linux_sysfs ( ERRFILE_OTHER | 0x00560000 )
#define ERRFILE_linux_acpi ( ERRFILE_OTHER | 0x00570000 )
#define ERRFILE_dynkeymap ( ERRFILE_OTHER | 0x00580000 )
+#define ERRFILE_pci_cmd ( ERRFILE_OTHER | 0x00590000 )
+#define ERRFILE_dhe ( ERRFILE_OTHER | 0x005a0000 )
/** @} */
diff --git a/src/include/ipxe/hmac.h b/src/include/ipxe/hmac.h
index 09d3e273d..cf9d08677 100644
--- a/src/include/ipxe/hmac.h
+++ b/src/include/ipxe/hmac.h
@@ -10,23 +10,45 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/crypto.h>
+/** HMAC context type */
+#define hmac_context_t( digest ) struct { \
+ /** Digest context */ \
+ uint8_t ctx[ digest->ctxsize ]; \
+ /** HMAC input/output padding */ \
+ uint8_t pad[ digest->blocksize ]; \
+ } __attribute__ (( packed ))
+
+/**
+ * Calculate HMAC context size
+ *
+ * @v digest Digest algorithm to use
+ * @ret len HMAC context size
+ */
+static inline __attribute__ (( always_inline )) size_t
+hmac_ctxsize ( struct digest_algorithm *digest ) {
+ hmac_context_t ( digest ) *hctx;
+
+ return sizeof ( *hctx );
+}
+
/**
* Update HMAC
*
* @v digest Digest algorithm to use
- * @v digest_ctx Digest context
+ * @v ctx HMAC context
* @v data Data
* @v len Length of data
*/
-static inline void hmac_update ( struct digest_algorithm *digest,
- void *digest_ctx, const void *data,
- size_t len ) {
- digest_update ( digest, digest_ctx, data, len );
+static inline void hmac_update ( struct digest_algorithm *digest, void *ctx,
+ const void *data, size_t len ) {
+ hmac_context_t ( digest ) *hctx = ctx;
+
+ digest_update ( digest, hctx->ctx, data, len );
}
-extern void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
- void *key, size_t *key_len );
-extern void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
- void *key, size_t *key_len, void *hmac );
+extern void hmac_init ( struct digest_algorithm *digest, void *ctx,
+ const void *key, size_t key_len );
+extern void hmac_final ( struct digest_algorithm *digest, void *ctx,
+ void *hmac );
#endif /* _IPXE_HMAC_H */
diff --git a/src/include/ipxe/linux/linux_pci.h b/src/include/ipxe/linux/linux_pci.h
index de42f766b..ec6ff8b1c 100644
--- a/src/include/ipxe/linux/linux_pci.h
+++ b/src/include/ipxe/linux/linux_pci.h
@@ -23,14 +23,18 @@ extern int linux_pci_write ( struct pci_device *pci, unsigned long where,
unsigned long value, size_t len );
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static inline __always_inline int
-PCIAPI_INLINE ( linux, pci_num_bus ) ( void ) {
- /* Assume all buses may exist */
- return 0x100;
+static inline __always_inline void
+PCIAPI_INLINE ( linux, pci_discover ) ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
+
+ /* Assume all buses in segment 0 may exist */
+ range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 1, 0, 0, 0 );
}
/**
diff --git a/src/include/ipxe/md4.h b/src/include/ipxe/md4.h
index 8f172e626..9f6cb8a5f 100644
--- a/src/include/ipxe/md4.h
+++ b/src/include/ipxe/md4.h
@@ -65,6 +65,9 @@ struct md4_context {
/** MD4 context size */
#define MD4_CTX_SIZE sizeof ( struct md4_context )
+/** MD4 block size */
+#define MD4_BLOCK_SIZE sizeof ( union md4_block )
+
/** MD4 digest size */
#define MD4_DIGEST_SIZE sizeof ( struct md4_digest )
diff --git a/src/include/ipxe/md5.h b/src/include/ipxe/md5.h
index 05c3974c8..527ad3658 100644
--- a/src/include/ipxe/md5.h
+++ b/src/include/ipxe/md5.h
@@ -65,6 +65,9 @@ struct md5_context {
/** MD5 context size */
#define MD5_CTX_SIZE sizeof ( struct md5_context )
+/** MD5 block size */
+#define MD5_BLOCK_SIZE sizeof ( union md5_block )
+
/** MD5 digest size */
#define MD5_DIGEST_SIZE sizeof ( struct md5_digest )
diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h
index 933f48530..637b20d60 100644
--- a/src/include/ipxe/pci.h
+++ b/src/include/ipxe/pci.h
@@ -127,6 +127,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Network controller */
#define PCI_CLASS_NETWORK 0x02
+/** Bridge device */
+#define PCI_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_PCI 0x04 /**< PCI-to-PCI bridge */
+
/** Serial bus controller */
#define PCI_CLASS_SERIAL 0x0c
#define PCI_CLASS_SERIAL_USB 0x03 /**< USB controller */
@@ -135,9 +139,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define PCI_CLASS_SERIAL_USB_EHCI 0x20 /**< ECHI USB controller */
#define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */
+/** Primary bus number */
+#define PCI_PRIMARY 0x18
+
+/** Secondary bus number */
+#define PCI_SECONDARY 0x19
+
/** Subordinate bus number */
#define PCI_SUBORDINATE 0x1a
+/** Memory base and limit */
+#define PCI_MEM_BASE 0x20
+#define PCI_MEM_LIMIT 0x22
+#define PCI_MEM_MASK 0x000f
+
/** Construct PCI class
*
* @v base Base class (or PCI_ANY_ID)
@@ -262,9 +277,6 @@ struct pci_driver {
#define PCI_BUS( busdevfn ) ( ( (busdevfn) >> 8 ) & 0xff )
#define PCI_SLOT( busdevfn ) ( ( (busdevfn) >> 3 ) & 0x1f )
#define PCI_FUNC( busdevfn ) ( ( (busdevfn) >> 0 ) & 0x07 )
-#define PCI_BUSDEVFN( segment, bus, slot, func ) \
- ( ( (segment) << 16 ) | ( (bus) << 8 ) | \
- ( (slot) << 3 ) | ( (func) << 0 ) )
#define PCI_FIRST_FUNC( busdevfn ) ( (busdevfn) & ~0x07 )
#define PCI_LAST_FUNC( busdevfn ) ( (busdevfn) | 0x07 )
@@ -301,7 +313,7 @@ extern void adjust_pci_device ( struct pci_device *pci );
extern unsigned long pci_bar_start ( struct pci_device *pci,
unsigned int reg );
extern int pci_read_config ( struct pci_device *pci );
-extern int pci_find_next ( struct pci_device *pci, unsigned int busdevfn );
+extern int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn );
extern int pci_find_driver ( struct pci_device *pci );
extern int pci_probe ( struct pci_device *pci );
extern void pci_remove ( struct pci_device *pci );
@@ -309,6 +321,7 @@ extern int pci_find_capability ( struct pci_device *pci, int capability );
extern int pci_find_next_capability ( struct pci_device *pci,
int pos, int capability );
extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
+extern void pci_reset ( struct pci_device *pci, unsigned int exp );
/**
* Initialise PCI device
diff --git a/src/include/ipxe/pci_io.h b/src/include/ipxe/pci_io.h
index 2dcdd9b28..4c035b18b 100644
--- a/src/include/ipxe/pci_io.h
+++ b/src/include/ipxe/pci_io.h
@@ -14,6 +14,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iomap.h>
#include <config/ioapi.h>
+struct pci_device;
+struct pci_api;
+
+/** A PCI bus:dev.fn address range */
+struct pci_range {
+ /** Starting bus:dev.fn address */
+ uint32_t start;
+ /** Number of bus:dev.fn addresses within this range */
+ unsigned int count;
+};
+
+#define PCI_BUSDEVFN( segment, bus, slot, func ) \
+ ( ( (segment) << 16 ) | ( (bus) << 8 ) | \
+ ( (slot) << 3 ) | ( (func) << 0 ) )
+
/**
* Calculate static inline PCI I/O API function name
*
@@ -44,6 +59,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
/* Include all architecture-independent I/O API headers */
+#include <ipxe/ecam_io.h>
#include <ipxe/efi/efi_pci_api.h>
#include <ipxe/linux/linux_pci.h>
@@ -51,11 +67,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <bits/pci_io.h>
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-int pci_num_bus ( void );
+void pci_discover ( uint32_t busdevfn, struct pci_range *range );
/**
* Read byte from PCI configuration space
@@ -133,4 +150,36 @@ int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
void * pci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
size_t len );
+/** A runtime selectable PCI I/O API */
+struct pci_api {
+ const char *name;
+ typeof ( pci_discover ) ( * pci_discover );
+ typeof ( pci_read_config_byte ) ( * pci_read_config_byte );
+ typeof ( pci_read_config_word ) ( * pci_read_config_word );
+ typeof ( pci_read_config_dword ) ( * pci_read_config_dword );
+ typeof ( pci_write_config_byte ) ( * pci_write_config_byte );
+ typeof ( pci_write_config_word ) ( * pci_write_config_word );
+ typeof ( pci_write_config_dword ) ( * pci_write_config_dword );
+ typeof ( pci_ioremap ) ( * pci_ioremap );
+};
+
+/** Provide a runtime selectable PCI I/O API */
+#define PCIAPI_RUNTIME( _subsys ) { \
+ .name = #_subsys, \
+ .pci_discover = PCIAPI_INLINE ( _subsys, pci_discover ), \
+ .pci_read_config_byte = \
+ PCIAPI_INLINE ( _subsys, pci_read_config_byte ), \
+ .pci_read_config_word = \
+ PCIAPI_INLINE ( _subsys, pci_read_config_word ), \
+ .pci_read_config_dword = \
+ PCIAPI_INLINE ( _subsys, pci_read_config_dword ), \
+ .pci_write_config_byte = \
+ PCIAPI_INLINE ( _subsys, pci_write_config_byte ), \
+ .pci_write_config_word = \
+ PCIAPI_INLINE ( _subsys, pci_write_config_word ), \
+ .pci_write_config_dword = \
+ PCIAPI_INLINE ( _subsys, pci_write_config_dword ), \
+ .pci_ioremap = PCIAPI_INLINE ( _subsys, pci_ioremap ), \
+ }
+
#endif /* _IPXE_PCI_IO_H */
diff --git a/src/include/ipxe/pcibridge.h b/src/include/ipxe/pcibridge.h
new file mode 100644
index 000000000..c57a81067
--- /dev/null
+++ b/src/include/ipxe/pcibridge.h
@@ -0,0 +1,43 @@
+#ifndef _IPXE_PCIBRIDGE_H
+#define _IPXE_PCIBRIDGE_H
+
+/** @file
+ *
+ * PCI-to-PCI bridge
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/pci.h>
+
+/** A PCI-to-PCI bridge */
+struct pci_bridge {
+ /** PCI device */
+ struct pci_device *pci;
+ /** Bridge numbers */
+ union {
+ /** Raw dword */
+ uint32_t buses;
+ struct {
+ /** Primary bus */
+ uint8_t primary;
+ /** Secondary bus */
+ uint8_t secondary;
+ /** Subordinate bus */
+ uint8_t subordinate;
+ } __attribute__ (( packed ));
+ };
+ /** Memory base */
+ uint32_t membase;
+ /** Memory limit */
+ uint32_t memlimit;
+ /** List of bridges */
+ struct list_head list;
+};
+
+extern struct pci_bridge * pcibridge_find ( struct pci_device *pci );
+
+#endif /* _IPXE_PCIBRIDGE_H */
diff --git a/src/include/ipxe/sha1.h b/src/include/ipxe/sha1.h
index a97035ec7..9cbbebdee 100644
--- a/src/include/ipxe/sha1.h
+++ b/src/include/ipxe/sha1.h
@@ -65,6 +65,9 @@ struct sha1_context {
/** SHA-1 context size */
#define SHA1_CTX_SIZE sizeof ( struct sha1_context )
+/** SHA-1 block size */
+#define SHA1_BLOCK_SIZE sizeof ( union sha1_block )
+
/** SHA-1 digest size */
#define SHA1_DIGEST_SIZE sizeof ( struct sha1_digest )
diff --git a/src/include/ipxe/sha256.h b/src/include/ipxe/sha256.h
index e234cce33..f226ad07b 100644
--- a/src/include/ipxe/sha256.h
+++ b/src/include/ipxe/sha256.h
@@ -70,6 +70,9 @@ struct sha256_context {
/** SHA-256 context size */
#define SHA256_CTX_SIZE sizeof ( struct sha256_context )
+/** SHA-256 block size */
+#define SHA256_BLOCK_SIZE sizeof ( union sha256_block )
+
/** SHA-256 digest size */
#define SHA256_DIGEST_SIZE sizeof ( struct sha256_digest )
diff --git a/src/include/ipxe/sha512.h b/src/include/ipxe/sha512.h
index 8e22d8357..82a9e4e69 100644
--- a/src/include/ipxe/sha512.h
+++ b/src/include/ipxe/sha512.h
@@ -72,6 +72,9 @@ struct sha512_context {
/** SHA-512 context size */
#define SHA512_CTX_SIZE sizeof ( struct sha512_context )
+/** SHA-512 block size */
+#define SHA512_BLOCK_SIZE sizeof ( union sha512_block )
+
/** SHA-512 digest size */
#define SHA512_DIGEST_SIZE sizeof ( struct sha512_digest )
diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h
index 8b03579cc..6d6c82de0 100644
--- a/src/include/ipxe/tls.h
+++ b/src/include/ipxe/tls.h
@@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iobuf.h>
#include <ipxe/tables.h>
+struct tls_connection;
+
/** A TLS header */
struct tls_header {
/** Content type
@@ -48,6 +50,9 @@ struct tls_header {
/** TLS version 1.2 */
#define TLS_VERSION_TLS_1_2 0x0303
+/** Maximum supported TLS version */
+#define TLS_VERSION_MAX TLS_VERSION_TLS_1_2
+
/** Change cipher content type */
#define TLS_TYPE_CHANGE_CIPHER 20
@@ -140,8 +145,23 @@ enum tls_tx_pending {
TLS_TX_FINISHED = 0x0020,
};
+/** A TLS key exchange algorithm */
+struct tls_key_exchange_algorithm {
+ /** Algorithm name */
+ const char *name;
+ /**
+ * Transmit Client Key Exchange record
+ *
+ * @v tls TLS connection
+ * @ret rc Return status code
+ */
+ int ( * exchange ) ( struct tls_connection *tls );
+};
+
/** A TLS cipher suite */
struct tls_cipher_suite {
+ /** Key exchange algorithm */
+ struct tls_key_exchange_algorithm *exchange;
/** Public-key encryption algorithm */
struct pubkey_algorithm *pubkey;
/** Bulk encryption cipher algorithm */
@@ -209,14 +229,6 @@ struct tls_signature_hash_algorithm {
#define __tls_sig_hash_algorithm \
__table_entry ( TLS_SIG_HASH_ALGORITHMS, 01 )
-/** TLS pre-master secret */
-struct tls_pre_master_secret {
- /** TLS version */
- uint16_t version;
- /** Random data */
- uint8_t random[46];
-} __attribute__ (( packed ));
-
/** TLS client random data */
struct tls_client_random {
/** GMT Unix time */
@@ -309,14 +321,16 @@ struct tls_connection {
struct tls_cipherspec rx_cipherspec;
/** Next RX cipher specification */
struct tls_cipherspec rx_cipherspec_pending;
- /** Premaster secret */
- struct tls_pre_master_secret pre_master_secret;
/** Master secret */
uint8_t master_secret[48];
/** Server random bytes */
uint8_t server_random[32];
/** Client random bytes */
struct tls_client_random client_random;
+ /** Server Key Exchange record (if any) */
+ void *server_key;
+ /** Server Key Exchange record length */
+ size_t server_key_len;
/** MD5+SHA1 context for handshake verification */
uint8_t handshake_md5_sha1_ctx[MD5_SHA1_CTX_SIZE];
/** SHA256 context for handshake verification */
@@ -388,6 +402,9 @@ struct tls_connection {
/** RX I/O buffer alignment */
#define TLS_RX_ALIGN 16
+extern struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm;
+extern struct tls_key_exchange_algorithm tls_dhe_exchange_algorithm;
+
extern int add_tls ( struct interface *xfer, const char *name,
struct x509_root *root, struct private_key *key );
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index fda4aba0e..19e341707 100644
--- a/src/interface/efi/efi_pci.c
+++ b/src/interface/efi/efi_pci.c
@@ -362,7 +362,7 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
return ioremap ( bus_addr, len );
}
-PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( efi, pci_discover );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
diff --git a/src/interface/linux/linux_pci.c b/src/interface/linux/linux_pci.c
index 99c629c19..300844737 100644
--- a/src/interface/linux/linux_pci.c
+++ b/src/interface/linux/linux_pci.c
@@ -187,3 +187,12 @@ int linux_pci_write ( struct pci_device *pci, unsigned long where,
err_open:
return rc;
}
+
+PROVIDE_PCIAPI_INLINE ( linux, pci_discover );
+PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( linux, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( linux, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( linux, pci_write_config_dword );
+PROVIDE_PCIAPI_INLINE ( linux, pci_ioremap );
diff --git a/src/net/80211/wpa_ccmp.c b/src/net/80211/wpa_ccmp.c
index a073c6a3c..0abd217e7 100644
--- a/src/net/80211/wpa_ccmp.c
+++ b/src/net/80211/wpa_ccmp.c
@@ -478,16 +478,15 @@ struct net80211_crypto ccmp_crypto __net80211_crypto = {
static void ccmp_kie_mic ( const void *kck, const void *msg, size_t len,
void *mic )
{
- u8 sha1_ctx[SHA1_CTX_SIZE];
+ u8 ctx[SHA1_CTX_SIZE + SHA1_BLOCK_SIZE];
u8 kckb[16];
u8 hash[SHA1_DIGEST_SIZE];
- size_t kck_len = 16;
- memcpy ( kckb, kck, kck_len );
+ memcpy ( kckb, kck, sizeof ( kckb ) );
- hmac_init ( &sha1_algorithm, sha1_ctx, kckb, &kck_len );
- hmac_update ( &sha1_algorithm, sha1_ctx, msg, len );
- hmac_final ( &sha1_algorithm, sha1_ctx, kckb, &kck_len, hash );
+ hmac_init ( &sha1_algorithm, ctx, kckb, sizeof ( kckb ) );
+ hmac_update ( &sha1_algorithm, ctx, msg, len );
+ hmac_final ( &sha1_algorithm, ctx, hash );
memcpy ( mic, hash, 16 );
}
diff --git a/src/net/80211/wpa_tkip.c b/src/net/80211/wpa_tkip.c
index 3b1934b59..3bd651512 100644
--- a/src/net/80211/wpa_tkip.c
+++ b/src/net/80211/wpa_tkip.c
@@ -545,15 +545,14 @@ struct net80211_crypto tkip_crypto __net80211_crypto = {
static void tkip_kie_mic ( const void *kck, const void *msg, size_t len,
void *mic )
{
- uint8_t ctx[MD5_CTX_SIZE];
+ uint8_t ctx[MD5_CTX_SIZE + MD5_BLOCK_SIZE];
u8 kckb[16];
- size_t kck_len = 16;
- memcpy ( kckb, kck, kck_len );
+ memcpy ( kckb, kck, sizeof ( kckb ) );
- hmac_init ( &md5_algorithm, ctx, kckb, &kck_len );
+ hmac_init ( &md5_algorithm, ctx, kckb, sizeof ( kckb ) );
hmac_update ( &md5_algorithm, ctx, msg, len );
- hmac_final ( &md5_algorithm, ctx, kckb, &kck_len, mic );
+ hmac_final ( &md5_algorithm, ctx, mic );
}
/**
diff --git a/src/net/ipv6.c b/src/net/ipv6.c
index 4b2c33eb4..901203c40 100644
--- a/src/net/ipv6.c
+++ b/src/net/ipv6.c
@@ -251,7 +251,7 @@ int ipv6_add_miniroute ( struct net_device *netdev, struct in6_addr *address,
*prefix_mask = 0xff;
}
if ( remaining )
- *prefix_mask <<= ( 8 - remaining );
+ *prefix_mask = ( 0xff << ( 8 - remaining ) );
}
/* Add to start of routing table */
diff --git a/src/net/ndp.c b/src/net/ndp.c
index 75e531648..c8e8ebad3 100644
--- a/src/net/ndp.c
+++ b/src/net/ndp.c
@@ -789,29 +789,43 @@ static int ndp_prefix_fetch_ip6 ( struct settings *settings, void *data,
container_of ( ndpset->settings.parent, struct net_device,
settings.settings );
struct ndp_prefix_information_option *prefix = prefset->prefix;
- struct in6_addr ip6;
+ struct in6_addr *ip6 = &prefix->prefix;
+ struct in6_addr slaac;
int prefix_len;
+ int rc;
/* Skip dead prefixes */
if ( ! prefix->valid )
return -ENOENT;
/* Construct IPv6 address via SLAAC, if applicable */
- memcpy ( &ip6, &prefix->prefix, sizeof ( ip6 ) );
if ( prefix->flags & NDP_PREFIX_AUTONOMOUS ) {
- prefix_len = ipv6_eui64 ( &ip6, netdev );
- if ( prefix_len < 0 )
- return prefix_len;
- if ( prefix_len != prefix->prefix_len )
- return -EINVAL;
+ memcpy ( &slaac, ip6, sizeof ( slaac ) );
+ prefix_len = ipv6_eui64 ( &slaac, netdev );
+ if ( prefix_len == prefix->prefix_len ) {
+ /* Correctly configured prefix: use SLAAC address */
+ ip6 = &slaac;
+ } else if ( prefix_len < 0 ) {
+ /* Link layer does not support SLAAC */
+ rc = prefix_len;
+ DBGC ( netdev, "NDP %s does not support SLAAC: %s\n",
+ netdev->name, strerror ( rc ) );
+ } else {
+ /* Prefix length incorrect: assume a badly
+ * configured router and ignore SLAAC address.
+ */
+ DBGC ( netdev, "NDP %s ignoring misconfigured SLAAC "
+ "on prefix %s/%d\n", netdev->name,
+ inet6_ntoa ( ip6 ), prefix->prefix_len );
+ }
}
/* Fill in IPv6 address */
- if ( len > sizeof ( ip6 ) )
- len = sizeof ( ip6 );
- memcpy ( data, &ip6, len );
+ if ( len > sizeof ( *ip6 ) )
+ len = sizeof ( *ip6 );
+ memcpy ( data, ip6, len );
- return sizeof ( ip6 );
+ return sizeof ( *ip6 );
}
/**
diff --git a/src/net/pccrc.c b/src/net/pccrc.c
index 4cd82cd1c..a94bc0e11 100644
--- a/src/net/pccrc.c
+++ b/src/net/pccrc.c
@@ -104,9 +104,8 @@ static void peerdist_info_segment_hash ( struct peerdist_info_segment *segment,
const void *hash, const void *secret ){
const struct peerdist_info *info = segment->info;
struct digest_algorithm *digest = info->digest;
- uint8_t ctx[digest->ctxsize];
+ uint8_t ctx[ hmac_ctxsize ( digest ) ];
size_t digestsize = info->digestsize;
- size_t secretsize = digestsize;
static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;
/* Sanity check */
@@ -121,12 +120,10 @@ static void peerdist_info_segment_hash ( struct peerdist_info_segment *segment,
memcpy ( segment->secret, secret, digestsize );
/* Calculate segment identifier */
- hmac_init ( digest, ctx, segment->secret, &secretsize );
- assert ( secretsize == digestsize );
+ hmac_init ( digest, ctx, segment->secret, digestsize );
hmac_update ( digest, ctx, segment->hash, digestsize );
hmac_update ( digest, ctx, magic, sizeof ( magic ) );
- hmac_final ( digest, ctx, segment->secret, &secretsize, segment->id );
- assert ( secretsize == digestsize );
+ hmac_final ( digest, ctx, segment->id );
}
/******************************************************************************
diff --git a/src/net/tls.c b/src/net/tls.c
index 3c4144450..4aa4d9e29 100644
--- a/src/net/tls.c
+++ b/src/net/tls.c
@@ -49,6 +49,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/rbg.h>
#include <ipxe/validator.h>
#include <ipxe/job.h>
+#include <ipxe/dhe.h>
#include <ipxe/tls.h>
#include <config/crypto.h>
@@ -109,6 +110,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_EINVAL_TICKET \
__einfo_uniqify ( EINFO_EINVAL, 0x0e, \
"Invalid New Session Ticket record")
+#define EINVAL_KEY_EXCHANGE __einfo_error ( EINFO_EINVAL_KEY_EXCHANGE )
+#define EINFO_EINVAL_KEY_EXCHANGE \
+ __einfo_uniqify ( EINFO_EINVAL, 0x0f, \
+ "Invalid Server Key Exchange record" )
#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
#define EINFO_EIO_ALERT \
__einfo_uniqify ( EINFO_EIO, 0x01, \
@@ -177,6 +182,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_EPERM_RENEG_VERIFY \
__einfo_uniqify ( EINFO_EPERM, 0x05, \
"Secure renegotiation verification failed" )
+#define EPERM_KEY_EXCHANGE __einfo_error ( EINFO_EPERM_KEY_EXCHANGE )
+#define EINFO_EPERM_KEY_EXCHANGE \
+ __einfo_uniqify ( EINFO_EPERM, 0x06, \
+ "ServerKeyExchange verification failed" )
#define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
#define EINFO_EPROTO_VERSION \
__einfo_uniqify ( EINFO_EPROTO, 0x01, \
@@ -377,6 +386,7 @@ static void free_tls ( struct refcnt *refcnt ) {
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
+ free ( tls->server_key );
list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
list_del ( &iobuf->list );
free_iob ( iobuf );
@@ -458,17 +468,17 @@ static int tls_generate_random ( struct tls_connection *tls,
* Update HMAC with a list of ( data, len ) pairs
*
* @v digest Hash function to use
- * @v digest_ctx Digest context
+ * @v ctx HMAC context
* @v args ( data, len ) pairs of data, terminated by NULL
*/
static void tls_hmac_update_va ( struct digest_algorithm *digest,
- void *digest_ctx, va_list args ) {
+ void *ctx, va_list args ) {
void *data;
size_t len;
while ( ( data = va_arg ( args, void * ) ) ) {
len = va_arg ( args, size_t );
- hmac_update ( digest, digest_ctx, data, len );
+ hmac_update ( digest, ctx, data, len );
}
}
@@ -485,43 +495,38 @@ static void tls_hmac_update_va ( struct digest_algorithm *digest,
*/
static void tls_p_hash_va ( struct tls_connection *tls,
struct digest_algorithm *digest,
- void *secret, size_t secret_len,
+ const void *secret, size_t secret_len,
void *out, size_t out_len,
va_list seeds ) {
- uint8_t secret_copy[secret_len];
- uint8_t digest_ctx[digest->ctxsize];
- uint8_t digest_ctx_partial[digest->ctxsize];
+ uint8_t ctx[ hmac_ctxsize ( digest ) ];
+ uint8_t ctx_partial[ sizeof ( ctx ) ];
uint8_t a[digest->digestsize];
uint8_t out_tmp[digest->digestsize];
size_t frag_len = digest->digestsize;
va_list tmp;
- /* Copy the secret, in case HMAC modifies it */
- memcpy ( secret_copy, secret, secret_len );
- secret = secret_copy;
DBGC2 ( tls, "TLS %p %s secret:\n", tls, digest->name );
DBGC2_HD ( tls, secret, secret_len );
/* Calculate A(1) */
- hmac_init ( digest, digest_ctx, secret, &secret_len );
+ hmac_init ( digest, ctx, secret, secret_len );
va_copy ( tmp, seeds );
- tls_hmac_update_va ( digest, digest_ctx, tmp );
+ tls_hmac_update_va ( digest, ctx, tmp );
va_end ( tmp );
- hmac_final ( digest, digest_ctx, secret, &secret_len, a );
+ hmac_final ( digest, ctx, a );
DBGC2 ( tls, "TLS %p %s A(1):\n", tls, digest->name );
DBGC2_HD ( tls, &a, sizeof ( a ) );
/* Generate as much data as required */
while ( out_len ) {
/* Calculate output portion */
- hmac_init ( digest, digest_ctx, secret, &secret_len );
- hmac_update ( digest, digest_ctx, a, sizeof ( a ) );
- memcpy ( digest_ctx_partial, digest_ctx, digest->ctxsize );
+ hmac_init ( digest, ctx, secret, secret_len );
+ hmac_update ( digest, ctx, a, sizeof ( a ) );
+ memcpy ( ctx_partial, ctx, sizeof ( ctx_partial ) );
va_copy ( tmp, seeds );
- tls_hmac_update_va ( digest, digest_ctx, tmp );
+ tls_hmac_update_va ( digest, ctx, tmp );
va_end ( tmp );
- hmac_final ( digest, digest_ctx,
- secret, &secret_len, out_tmp );
+ hmac_final ( digest, ctx, out_tmp );
/* Copy output */
if ( frag_len > out_len )
@@ -531,8 +536,7 @@ static void tls_p_hash_va ( struct tls_connection *tls,
DBGC2_HD ( tls, out, frag_len );
/* Calculate A(i) */
- hmac_final ( digest, digest_ctx_partial,
- secret, &secret_len, a );
+ hmac_final ( digest, ctx_partial, a );
DBGC2 ( tls, "TLS %p %s A(n):\n", tls, digest->name );
DBGC2_HD ( tls, &a, sizeof ( a ) );
@@ -551,13 +555,13 @@ static void tls_p_hash_va ( struct tls_connection *tls,
* @v out_len Length of output buffer
* @v ... ( data, len ) pairs of seed data, terminated by NULL
*/
-static void tls_prf ( struct tls_connection *tls, void *secret,
+static void tls_prf ( struct tls_connection *tls, const void *secret,
size_t secret_len, void *out, size_t out_len, ... ) {
va_list seeds;
va_list tmp;
size_t subsecret_len;
- void *md5_secret;
- void *sha1_secret;
+ const void *md5_secret;
+ const void *sha1_secret;
uint8_t buf[out_len];
unsigned int i;
@@ -622,21 +626,23 @@ static void tls_prf ( struct tls_connection *tls, void *secret,
* Generate master secret
*
* @v tls TLS connection
+ * @v pre_master_secret Pre-master secret
+ * @v pre_master_secret_len Length of pre-master secret
*
- * The pre-master secret and the client and server random values must
- * already be known.
+ * The client and server random values must already be known.
*/
-static void tls_generate_master_secret ( struct tls_connection *tls ) {
+static void tls_generate_master_secret ( struct tls_connection *tls,
+ const void *pre_master_secret,
+ size_t pre_master_secret_len ) {
+
DBGC ( tls, "TLS %p pre-master-secret:\n", tls );
- DBGC_HD ( tls, &tls->pre_master_secret,
- sizeof ( tls->pre_master_secret ) );
+ DBGC_HD ( tls, pre_master_secret, pre_master_secret_len );
DBGC ( tls, "TLS %p client random bytes:\n", tls );
DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
DBGC ( tls, "TLS %p server random bytes:\n", tls );
DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
- tls_prf_label ( tls, &tls->pre_master_secret,
- sizeof ( tls->pre_master_secret ),
+ tls_prf_label ( tls, pre_master_secret, pre_master_secret_len,
&tls->master_secret, sizeof ( tls->master_secret ),
"master secret",
&tls->client_random, sizeof ( tls->client_random ),
@@ -737,6 +743,7 @@ static int tls_generate_keys ( struct tls_connection *tls ) {
/** Null cipher suite */
struct tls_cipher_suite tls_cipher_suite_null = {
+ .exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &pubkey_null,
.cipher = &cipher_null,
.digest = &digest_null,
@@ -852,7 +859,8 @@ static int tls_select_cipher ( struct tls_connection *tls,
suite ) ) != 0 )
return rc;
- DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls, suite->pubkey->name,
+ DBGC ( tls, "TLS %p selected %s-%s-%s-%d-%s\n", tls,
+ suite->exchange->name, suite->pubkey->name,
suite->cipher->name, ( suite->key_len * 8 ),
suite->digest->name );
@@ -916,6 +924,44 @@ tls_signature_hash_algorithm ( struct pubkey_algorithm *pubkey,
return NULL;
}
+/**
+ * Find TLS signature algorithm
+ *
+ * @v code Signature and hash algorithm identifier
+ * @ret pubkey Public key algorithm, or NULL
+ */
+static struct pubkey_algorithm *
+tls_signature_hash_pubkey ( struct tls_signature_hash_id code ) {
+ struct tls_signature_hash_algorithm *sig_hash;
+
+ /* Identify signature and hash algorithm */
+ for_each_table_entry ( sig_hash, TLS_SIG_HASH_ALGORITHMS ) {
+ if ( sig_hash->code.signature == code.signature )
+ return sig_hash->pubkey;
+ }
+
+ return NULL;
+}
+
+/**
+ * Find TLS hash algorithm
+ *
+ * @v code Signature and hash algorithm identifier
+ * @ret digest Digest algorithm, or NULL
+ */
+static struct digest_algorithm *
+tls_signature_hash_digest ( struct tls_signature_hash_id code ) {
+ struct tls_signature_hash_algorithm *sig_hash;
+
+ /* Identify signature and hash algorithm */
+ for_each_table_entry ( sig_hash, TLS_SIG_HASH_ALGORITHMS ) {
+ if ( sig_hash->code.hash == code.hash )
+ return sig_hash->digest;
+ }
+
+ return NULL;
+}
+
/******************************************************************************
*
* Handshake verification
@@ -1208,16 +1254,20 @@ static int tls_send_certificate ( struct tls_connection *tls ) {
}
/**
- * Transmit Client Key Exchange record
+ * Transmit Client Key Exchange record using public key exchange
*
* @v tls TLS connection
* @ret rc Return status code
*/
-static int tls_send_client_key_exchange ( struct tls_connection *tls ) {
+static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) {
struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx );
struct {
+ uint16_t version;
+ uint8_t random[46];
+ } __attribute__ (( packed )) pre_master_secret;
+ struct {
uint32_t type_length;
uint16_t encrypted_pre_master_secret_len;
uint8_t encrypted_pre_master_secret[max_len];
@@ -1226,11 +1276,28 @@ static int tls_send_client_key_exchange ( struct tls_connection *tls ) {
int len;
int rc;
+ /* Generate pre-master secret */
+ pre_master_secret.version = htons ( TLS_VERSION_MAX );
+ if ( ( rc = tls_generate_random ( tls, &pre_master_secret.random,
+ ( sizeof ( pre_master_secret.random ) ) ) ) != 0 ) {
+ return rc;
+ }
+
+ /* Generate master secret */
+ tls_generate_master_secret ( tls, &pre_master_secret,
+ sizeof ( pre_master_secret ) );
+
+ /* Generate keys */
+ if ( ( rc = tls_generate_keys ( tls ) ) != 0 ) {
+ DBGC ( tls, "TLS %p could not generate keys: %s\n",
+ tls, strerror ( rc ) );
+ return rc;
+ }
+
/* Encrypt pre-master secret using server's public key */
memset ( &key_xchg, 0, sizeof ( key_xchg ) );
len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx,
- &tls->pre_master_secret,
- sizeof ( tls->pre_master_secret ),
+ &pre_master_secret, sizeof ( pre_master_secret ),
key_xchg.encrypted_pre_master_secret );
if ( len < 0 ) {
rc = len;
@@ -1251,6 +1318,225 @@ static int tls_send_client_key_exchange ( struct tls_connection *tls ) {
( sizeof ( key_xchg ) - unused ) );
}
+/** Public key exchange algorithm */
+struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm = {
+ .name = "pubkey",
+ .exchange = tls_send_client_key_exchange_pubkey,
+};
+
+/**
+ * Transmit Client Key Exchange record using DHE key exchange
+ *
+ * @v tls TLS connection
+ * @ret rc Return status code
+ */
+static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) {
+ struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
+ struct pubkey_algorithm *pubkey;
+ struct digest_algorithm *digest;
+ int use_sig_hash = tls_version ( tls, TLS_VERSION_TLS_1_2 );
+ uint8_t private[ sizeof ( tls->client_random.random ) ];
+ const struct {
+ uint16_t len;
+ uint8_t data[0];
+ } __attribute__ (( packed )) *dh_val[3];
+ const struct {
+ struct tls_signature_hash_id sig_hash[use_sig_hash];
+ uint16_t signature_len;
+ uint8_t signature[0];
+ } __attribute__ (( packed )) *sig;
+ const void *data;
+ size_t remaining;
+ size_t frag_len;
+ unsigned int i;
+ int rc;
+
+ /* Parse ServerKeyExchange */
+ data = tls->server_key;
+ remaining = tls->server_key_len;
+ for ( i = 0 ; i < ( sizeof ( dh_val ) / sizeof ( dh_val[0] ) ) ; i++ ){
+ dh_val[i] = data;
+ if ( ( sizeof ( *dh_val[i] ) > remaining ) ||
+ ( ntohs ( dh_val[i]->len ) > ( remaining -
+ sizeof ( *dh_val[i] ) ) )){
+ DBGC ( tls, "TLS %p received underlength "
+ "ServerKeyExchange\n", tls );
+ DBGC_HDA ( tls, 0, tls->server_key,
+ tls->server_key_len );
+ rc = -EINVAL_KEY_EXCHANGE;
+ goto err_header;
+ }
+ frag_len = ( sizeof ( *dh_val[i] ) + ntohs ( dh_val[i]->len ));
+ data += frag_len;
+ remaining -= frag_len;
+ }
+ sig = data;
+ if ( ( sizeof ( *sig ) > remaining ) ||
+ ( ntohs ( sig->signature_len ) > ( remaining -
+ sizeof ( *sig ) ) ) ) {
+ DBGC ( tls, "TLS %p received underlength ServerKeyExchange\n",
+ tls );
+ DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len );
+ rc = -EINVAL_KEY_EXCHANGE;
+ goto err_header;
+ }
+
+ /* Identify signature and hash algorithm */
+ if ( use_sig_hash ) {
+ pubkey = tls_signature_hash_pubkey ( sig->sig_hash[0] );
+ digest = tls_signature_hash_digest ( sig->sig_hash[0] );
+ if ( ( ! pubkey ) || ( ! digest ) ) {
+ DBGC ( tls, "TLS %p ServerKeyExchange unsupported "
+ "signature and hash algorithm\n", tls );
+ rc = -ENOTSUP_SIG_HASH;
+ goto err_sig_hash;
+ }
+ if ( pubkey != cipherspec->suite->pubkey ) {
+ DBGC ( tls, "TLS %p ServerKeyExchange incorrect "
+ "signature algorithm %s (expected %s)\n", tls,
+ pubkey->name, cipherspec->suite->pubkey->name );
+ rc = -EPERM_KEY_EXCHANGE;
+ goto err_sig_hash;
+ }
+ } else {
+ pubkey = cipherspec->suite->pubkey;
+ digest = &md5_sha1_algorithm;
+ }
+
+ /* Verify signature */
+ {
+ const void *signature = sig->signature;
+ size_t signature_len = ntohs ( sig->signature_len );
+ uint8_t ctx[digest->ctxsize];
+ uint8_t hash[digest->digestsize];
+
+ /* Calculate digest */
+ digest_init ( digest, ctx );
+ digest_update ( digest, ctx, &tls->client_random,
+ sizeof ( tls->client_random ) );
+ digest_update ( digest, ctx, tls->server_random,
+ sizeof ( tls->server_random ) );
+ digest_update ( digest, ctx, tls->server_key,
+ ( tls->server_key_len - remaining ) );
+ digest_final ( digest, ctx, hash );
+
+ /* Verify signature */
+ if ( ( rc = pubkey_verify ( pubkey, cipherspec->pubkey_ctx,
+ digest, hash, signature,
+ signature_len ) ) != 0 ) {
+ DBGC ( tls, "TLS %p ServerKeyExchange failed "
+ "verification\n", tls );
+ DBGC_HDA ( tls, 0, tls->server_key,
+ tls->server_key_len );
+ rc = -EPERM_KEY_EXCHANGE;
+ goto err_verify;
+ }
+ }
+
+ /* Generate Diffie-Hellman private key */
+ if ( ( rc = tls_generate_random ( tls, private,
+ sizeof ( private ) ) ) != 0 ) {
+ goto err_random;
+ }
+
+ /* Construct pre-master secret and ClientKeyExchange record */
+ {
+ typeof ( dh_val[0] ) dh_p = dh_val[0];
+ typeof ( dh_val[1] ) dh_g = dh_val[1];
+ typeof ( dh_val[2] ) dh_ys = dh_val[2];
+ size_t len = ntohs ( dh_p->len );
+ struct {
+ uint32_t type_length;
+ uint16_t dh_xs_len;
+ uint8_t dh_xs[len];
+ } __attribute__ (( packed )) *key_xchg;
+ struct {
+ uint8_t pre_master_secret[len];
+ typeof ( *key_xchg ) key_xchg;
+ } *dynamic;
+ uint8_t *pre_master_secret;
+
+ /* Allocate space */
+ dynamic = malloc ( sizeof ( *dynamic ) );
+ if ( ! dynamic ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ pre_master_secret = dynamic->pre_master_secret;
+ key_xchg = &dynamic->key_xchg;
+ key_xchg->type_length =
+ ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
+ htonl ( sizeof ( *key_xchg ) -
+ sizeof ( key_xchg->type_length ) ) );
+ key_xchg->dh_xs_len = htons ( len );
+
+ /* Calculate pre-master secret and client public value */
+ if ( ( rc = dhe_key ( dh_p->data, len,
+ dh_g->data, ntohs ( dh_g->len ),
+ dh_ys->data, ntohs ( dh_ys->len ),
+ private, sizeof ( private ),
+ key_xchg->dh_xs,
+ pre_master_secret ) ) != 0 ) {
+ DBGC ( tls, "TLS %p could not calculate DHE key: %s\n",
+ tls, strerror ( rc ) );
+ goto err_dhe_key;
+ }
+
+ /* Strip leading zeroes from pre-master secret */
+ while ( len && ( ! *pre_master_secret ) ) {
+ pre_master_secret++;
+ len--;
+ }
+
+ /* Generate master secret */
+ tls_generate_master_secret ( tls, pre_master_secret, len );
+
+ /* Generate keys */
+ if ( ( rc = tls_generate_keys ( tls ) ) != 0 ) {
+ DBGC ( tls, "TLS %p could not generate keys: %s\n",
+ tls, strerror ( rc ) );
+ goto err_generate_keys;
+ }
+
+ /* Transmit Client Key Exchange record */
+ if ( ( rc = tls_send_handshake ( tls, key_xchg,
+ sizeof ( *key_xchg ) ) ) !=0){
+ goto err_send_handshake;
+ }
+
+ err_send_handshake:
+ err_generate_keys:
+ err_dhe_key:
+ free ( dynamic );
+ }
+ err_alloc:
+ err_random:
+ err_verify:
+ err_sig_hash:
+ err_header:
+ return rc;
+}
+
+/** Ephemeral Diffie-Hellman key exchange algorithm */
+struct tls_key_exchange_algorithm tls_dhe_exchange_algorithm = {
+ .name = "dhe",
+ .exchange = tls_send_client_key_exchange_dhe,
+};
+
+/**
+ * Transmit Client Key Exchange record
+ *
+ * @v tls TLS connection
+ * @ret rc Return status code
+ */
+static int tls_send_client_key_exchange ( struct tls_connection *tls ) {
+ struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
+ struct tls_cipher_suite *suite = cipherspec->suite;
+
+ /* Transmit Client Key Exchange record via key exchange algorithm */
+ return suite->exchange->exchange ( tls );
+}
+
/**
* Transmit Certificate Verify record
*
@@ -1628,7 +1914,7 @@ static int tls_new_server_hello ( struct tls_connection *tls,
if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
return rc;
- /* Reuse or generate master secret */
+ /* Check session ID */
if ( hello_a->session_id_len &&
( hello_a->session_id_len == tls->session_id_len ) &&
( memcmp ( session_id, tls->session_id,
@@ -1637,12 +1923,11 @@ static int tls_new_server_hello ( struct tls_connection *tls,
/* Session ID match: reuse master secret */
DBGC ( tls, "TLS %p resuming session ID:\n", tls );
DBGC_HDA ( tls, 0, tls->session_id, tls->session_id_len );
+ if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
+ return rc;
} else {
- /* Generate new master secret */
- tls_generate_master_secret ( tls );
-
/* Record new session ID, if present */
if ( hello_a->session_id_len &&
( hello_a->session_id_len <= sizeof ( tls->session_id ))){
@@ -1655,10 +1940,6 @@ static int tls_new_server_hello ( struct tls_connection *tls,
}
}
- /* Generate keys */
- if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
- return rc;
-
/* Handle secure renegotiation */
if ( tls->secure_renegotiation ) {
@@ -1856,6 +2137,37 @@ static int tls_new_certificate ( struct tls_connection *tls,
}
/**
+ * Receive new Server Key Exchange handshake record
+ *
+ * @v tls TLS connection
+ * @v data Plaintext handshake record
+ * @v len Length of plaintext handshake record
+ * @ret rc Return status code
+ */
+static int tls_new_server_key_exchange ( struct tls_connection *tls,
+ const void *data, size_t len ) {
+
+ /* Free any existing server key exchange record */
+ free ( tls->server_key );
+ tls->server_key_len = 0;
+
+ /* Allocate copy of server key exchange record */
+ tls->server_key = malloc ( len );
+ if ( ! tls->server_key )
+ return -ENOMEM;
+
+ /* Store copy of server key exchange record for later
+ * processing. We cannot verify the signature at this point
+ * since the certificate validation will not yet have
+ * completed.
+ */
+ memcpy ( tls->server_key, data, len );
+ tls->server_key_len = len;
+
+ return 0;
+}
+
+/**
* Receive new Certificate Request handshake record
*
* @v tls TLS connection
@@ -2088,6 +2400,10 @@ static int tls_new_handshake ( struct tls_connection *tls,
case TLS_CERTIFICATE:
rc = tls_new_certificate ( tls, payload, payload_len );
break;
+ case TLS_SERVER_KEY_EXCHANGE:
+ rc = tls_new_server_key_exchange ( tls, payload,
+ payload_len );
+ break;
case TLS_CERTIFICATE_REQUEST:
rc = tls_new_certificate_request ( tls, payload,
payload_len );
@@ -2213,7 +2529,7 @@ static void tls_hmac_init ( struct tls_cipherspec *cipherspec, void *ctx,
uint64_t seq, struct tls_header *tlshdr ) {
struct digest_algorithm *digest = cipherspec->suite->digest;
- hmac_init ( digest, ctx, cipherspec->mac_secret, &digest->digestsize );
+ hmac_init ( digest, ctx, cipherspec->mac_secret, digest->digestsize );
seq = cpu_to_be64 ( seq );
hmac_update ( digest, ctx, &seq, sizeof ( seq ) );
hmac_update ( digest, ctx, tlshdr, sizeof ( *tlshdr ) );
@@ -2245,8 +2561,7 @@ static void tls_hmac_final ( struct tls_cipherspec *cipherspec, void *ctx,
void *hmac ) {
struct digest_algorithm *digest = cipherspec->suite->digest;
- hmac_final ( digest, ctx, cipherspec->mac_secret,
- &digest->digestsize, hmac );
+ hmac_final ( digest, ctx, hmac );
}
/**
@@ -2263,7 +2578,7 @@ static void tls_hmac ( struct tls_cipherspec *cipherspec,
uint64_t seq, struct tls_header *tlshdr,
const void *data, size_t len, void *hmac ) {
struct digest_algorithm *digest = cipherspec->suite->digest;
- uint8_t ctx[digest->ctxsize];
+ uint8_t ctx[ hmac_ctxsize ( digest ) ];
tls_hmac_init ( cipherspec, ctx, seq, tlshdr );
tls_hmac_update ( cipherspec, ctx, data, len );
@@ -2545,7 +2860,7 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
struct cipher_algorithm *cipher = cipherspec->suite->cipher;
struct digest_algorithm *digest = cipherspec->suite->digest;
- uint8_t ctx[digest->ctxsize];
+ uint8_t ctx[ hmac_ctxsize ( digest ) ];
uint8_t verify_mac[digest->digestsize];
struct io_buffer *iobuf;
void *mac;
@@ -3175,7 +3490,7 @@ int add_tls ( struct interface *xfer, const char *name,
&tls->refcnt );
tls->key = privkey_get ( key ? key : &private_key );
tls->root = x509_root_get ( root ? root : &root_certificates );
- tls->version = TLS_VERSION_TLS_1_2;
+ tls->version = TLS_VERSION_MAX;
tls_clear_cipher ( tls, &tls->tx_cipherspec );
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
@@ -3188,11 +3503,6 @@ int add_tls ( struct interface *xfer, const char *name,
( sizeof ( tls->client_random.random ) ) ) ) != 0 ) {
goto err_random;
}
- tls->pre_master_secret.version = htons ( tls->version );
- if ( ( rc = tls_generate_random ( tls, &tls->pre_master_secret.random,
- ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) {
- goto err_random;
- }
if ( ( rc = tls_session ( tls, name ) ) != 0 )
goto err_session;
list_add_tail ( &tls->list, &tls->session->conn );
diff --git a/src/tests/dhe_test.c b/src/tests/dhe_test.c
new file mode 100644
index 000000000..ea97ec7f4
--- /dev/null
+++ b/src/tests/dhe_test.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Ephemeral Diffie-Hellman self-tests
+ *
+ * NIST test vectors are taken from
+ *
+ * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/keymgmt/KASTestVectorsFFC2014.zip
+ *
+ * using the files in the "KASTestVectorsFFC2014/Test of 800-56A
+ * excluding KDF/FFC Ephemeral Scheme" subdirectory
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/dhe.h>
+#include <ipxe/test.h>
+
+/** Define inline prime modulus data */
+#define MODULUS(...) { __VA_ARGS__ }
+
+/** Define inline generator data */
+#define GENERATOR(...) { __VA_ARGS__ }
+
+/** Define inline partner public key data */
+#define PARTNER(...) { __VA_ARGS__ }
+
+/** Define inline private key data */
+#define PRIVATE(...) { __VA_ARGS__ }
+
+/** Define inline public key data */
+#define PUBLIC(...) { __VA_ARGS__ }
+
+/** Define inline shared secret data */
+#define SHARED(...) { __VA_ARGS__ }
+
+/** An Ephemeral Diffie-Hellman self-test */
+struct dhe_test {
+ /** Prime modulus */
+ const void *modulus;
+ /** Length of prime modulus */
+ size_t len;
+ /** Generator */
+ const void *generator;
+ /** Length of generator */
+ size_t generator_len;
+ /** Partner public key */
+ const void *partner;
+ /** Length of partner public key */
+ size_t partner_len;
+ /** Private key */
+ const void *private;
+ /** Length of private key */
+ size_t private_len;
+ /** Expected public key */
+ const void *public;
+ /** Length of expected public key */
+ size_t public_len;
+ /** Expected shared secret */
+ const void *shared;
+ /** Length of shared secret */
+ size_t shared_len;
+};
+
+/**
+ * Define an Ephemeral Diffie-Hellman test
+ *
+ * @v name Test name
+ * @v MODULUS Prime modulus
+ * @v GENERATOR Generator
+ * @v PARTNER Partner public key
+ * @v PRIVATE Private key
+ * @v PUBLIC Expected public key
+ * @v SHARED Expected shared secret
+ * @ret test Ephemeral Diffie-Hellman test
+ */
+#define DHE_TEST( name, MODULUS, GENERATOR, PARTNER, PRIVATE, PUBLIC, \
+ SHARED ) \
+ static const uint8_t name ## _modulus[] = MODULUS; \
+ static const uint8_t name ## _generator[] = GENERATOR; \
+ static const uint8_t name ## _partner[] = PARTNER; \
+ static const uint8_t name ## _private[] = PRIVATE; \
+ static const uint8_t name ## _public[] = PUBLIC; \
+ static const uint8_t name ## _shared[] = SHARED; \
+ static struct dhe_test name = { \
+ .modulus = name ## _modulus, \
+ .len = sizeof ( name ## _modulus ), \
+ .generator = name ## _generator, \
+ .generator_len = sizeof ( name ## _generator ), \
+ .partner = name ## _partner, \
+ .partner_len = sizeof ( name ## _partner ), \
+ .private = name ## _private, \
+ .private_len = sizeof ( name ## _private ), \
+ .public = name ## _public, \
+ .public_len = sizeof ( name ## _public ), \
+ .shared = name ## _shared, \
+ .shared_len = sizeof ( name ## _shared ), \
+ }
+
+/**
+ * Report an Ephemeral Diffie-Hellman test result
+ *
+ * @v test Ephemeral Diffie-Hellman test
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void dhe_key_okx ( struct dhe_test *test, const char *file,
+ unsigned int line ) {
+ uint8_t public[test->len];
+ uint8_t shared[test->len];
+
+ /* Sanity checks */
+ okx ( test->generator_len <= test->len, file, line );
+ okx ( test->partner_len <= test->len, file, line );
+ okx ( test->private_len <= test->len, file, line );
+ okx ( test->public_len == test->len, file, line );
+ okx ( test->shared_len == test->len, file, line );
+
+ /* Calculate Diffie-Hellman key */
+ okx ( dhe_key ( test->modulus, test->len, test->generator,
+ test->generator_len, test->partner, test->partner_len,
+ test->private, test->private_len, public,
+ shared ) == 0, file, line );
+
+ /* Compare against expected result */
+ okx ( memcmp ( public, test->public, test->len ) == 0, file, line );
+ okx ( memcmp ( shared, test->shared, test->len ) == 0, file, line );
+}
+#define dhe_key_ok( test ) dhe_key_okx ( test, __FILE__, __LINE__ )
+
+/* KASValidityTest_FFCEphem_NOKC_ZZOnly_init.fax test 0 */
+DHE_TEST ( kasvaliditytest_ffcephem_nokc_zzonly_init_fb_0,
+ MODULUS ( 0xc5, 0x7c, 0xa2, 0x4f, 0x4b, 0xd6, 0x8c, 0x3c, 0xda,
+ 0xc7, 0xba, 0xaa, 0xea, 0x2e, 0x5c, 0x1e, 0x18, 0xb2,
+ 0x7b, 0x8c, 0x55, 0x65, 0x9f, 0xea, 0xe0, 0xa1, 0x36,
+ 0x53, 0x2b, 0x36, 0xe0, 0x4e, 0x3e, 0x64, 0xa9, 0xe4,
+ 0xfc, 0x8f, 0x32, 0x62, 0x97, 0xe4, 0xbe, 0xf7, 0xc1,
+ 0xde, 0x07, 0x5a, 0x89, 0x28, 0xf3, 0xfe, 0x4f, 0xfe,
+ 0x68, 0xbc, 0xfb, 0x0a, 0x7c, 0xa4, 0xb3, 0x14, 0x48,
+ 0x89, 0x9f, 0xaf, 0xb8, 0x43, 0xe2, 0xa0, 0x62, 0x5c,
+ 0xb4, 0x88, 0x3f, 0x06, 0x50, 0x11, 0xfe, 0x65, 0x8d,
+ 0x49, 0xd2, 0xf5, 0x4b, 0x74, 0x79, 0xdb, 0x06, 0x62,
+ 0x92, 0x89, 0xed, 0xda, 0xcb, 0x87, 0x37, 0x16, 0xd2,
+ 0xa1, 0x7a, 0xe8, 0xde, 0x92, 0xee, 0x3e, 0x41, 0x4a,
+ 0x91, 0x5e, 0xed, 0xf3, 0x6c, 0x6b, 0x7e, 0xfd, 0x15,
+ 0x92, 0x18, 0xfc, 0xa7, 0xac, 0x42, 0x85, 0x57, 0xe9,
+ 0xdc, 0xda, 0x55, 0xc9, 0x8b, 0x28, 0x9e, 0xc1, 0xc4,
+ 0x46, 0x4d, 0x88, 0xed, 0x62, 0x8e, 0xdb, 0x3f, 0xb9,
+ 0xd7, 0xc8, 0xe3, 0xcf, 0xb8, 0x34, 0x2c, 0xd2, 0x6f,
+ 0x28, 0x06, 0x41, 0xe3, 0x66, 0x8c, 0xfc, 0x72, 0xff,
+ 0x26, 0x3b, 0x6b, 0x6c, 0x6f, 0x73, 0xde, 0xf2, 0x90,
+ 0x29, 0xe0, 0x61, 0x32, 0xc4, 0x12, 0x74, 0x09, 0x52,
+ 0xec, 0xf3, 0x1b, 0xa6, 0x45, 0x98, 0xac, 0xf9, 0x1c,
+ 0x65, 0x8e, 0x3a, 0x91, 0x84, 0x4b, 0x23, 0x8a, 0xb2,
+ 0x3c, 0xc9, 0xfa, 0xea, 0xf1, 0x38, 0xce, 0xd8, 0x05,
+ 0xe0, 0xfa, 0x44, 0x68, 0x1f, 0xeb, 0xd9, 0x57, 0xb8,
+ 0x4a, 0x97, 0x5b, 0x88, 0xc5, 0xf1, 0xbb, 0xb0, 0x49,
+ 0xc3, 0x91, 0x7c, 0xd3, 0x13, 0xb9, 0x47, 0xbb, 0x91,
+ 0x8f, 0xe5, 0x26, 0x07, 0xab, 0xa9, 0xc5, 0xd0, 0x3d,
+ 0x95, 0x41, 0x26, 0x92, 0x9d, 0x13, 0x67, 0xf2, 0x7e,
+ 0x11, 0x88, 0xdc, 0x2d ),
+ GENERATOR ( 0x4a, 0x1a, 0xf3, 0xa4, 0x92, 0xe9, 0xee, 0x74, 0x6e,
+ 0x57, 0xd5, 0x8c, 0x2c, 0x5b, 0x41, 0x41, 0x5e, 0xd4,
+ 0x55, 0x19, 0xdc, 0xd9, 0x32, 0x91, 0xf7, 0xfd, 0xc2,
+ 0x57, 0xff, 0x03, 0x14, 0xdb, 0xf1, 0xb7, 0x60, 0x0c,
+ 0x43, 0x59, 0x3f, 0xff, 0xac, 0xf1, 0x80, 0x9a, 0x15,
+ 0x6f, 0xd8, 0x6e, 0xb7, 0x85, 0x18, 0xc8, 0xec, 0x4e,
+ 0x59, 0x4a, 0xe2, 0x91, 0x43, 0x4c, 0xeb, 0x95, 0xb6,
+ 0x2e, 0x9a, 0xea, 0x53, 0x68, 0x80, 0x64, 0x69, 0x40,
+ 0xf9, 0xec, 0xbd, 0x85, 0x89, 0x26, 0x97, 0x67, 0xaf,
+ 0xb0, 0xad, 0x00, 0x1b, 0xd4, 0xfd, 0x94, 0xd3, 0xe9,
+ 0x92, 0xb1, 0xb4, 0xbc, 0x5a, 0xaa, 0x92, 0x80, 0x89,
+ 0x3b, 0x39, 0x05, 0x6c, 0x22, 0x26, 0xfe, 0x5a, 0x28,
+ 0x6c, 0x37, 0x50, 0x5a, 0x38, 0x99, 0xcf, 0xf3, 0xc1,
+ 0x96, 0x45, 0xdc, 0x01, 0xcb, 0x20, 0x87, 0xa5, 0x00,
+ 0x8c, 0xf5, 0x4d, 0xc2, 0xef, 0xb8, 0x9b, 0xd1, 0x87,
+ 0xbe, 0xed, 0xd5, 0x0a, 0x29, 0x15, 0x34, 0x59, 0x4c,
+ 0x3a, 0x05, 0x22, 0x05, 0x44, 0x4f, 0x9f, 0xc8, 0x47,
+ 0x12, 0x24, 0x8e, 0xa8, 0x79, 0xe4, 0x67, 0xba, 0x4d,
+ 0x5b, 0x75, 0x56, 0x95, 0xeb, 0xe8, 0x8a, 0xfa, 0x8e,
+ 0x01, 0x8c, 0x1b, 0x74, 0x63, 0xd9, 0x2f, 0xf7, 0xd3,
+ 0x44, 0x8f, 0xa8, 0xf5, 0xaf, 0x6c, 0x4f, 0xdb, 0xe7,
+ 0xc9, 0x6c, 0x71, 0x22, 0xa3, 0x1d, 0xf1, 0x40, 0xb2,
+ 0xe0, 0x9a, 0xb6, 0x72, 0xc9, 0xc0, 0x13, 0x16, 0xa2,
+ 0x4a, 0xe1, 0x92, 0xc7, 0x54, 0x23, 0xab, 0x9d, 0xa1,
+ 0xa1, 0xe5, 0x0b, 0xed, 0xba, 0xe8, 0x84, 0x37, 0xb2,
+ 0xe7, 0xfe, 0x32, 0x8d, 0xfa, 0x1c, 0x53, 0x77, 0x97,
+ 0xc7, 0xf3, 0x48, 0xc9, 0xdb, 0x2d, 0x75, 0x52, 0x9d,
+ 0x42, 0x51, 0x78, 0x62, 0x68, 0x05, 0x45, 0x15, 0xf8,
+ 0xa2, 0x4e, 0xf3, 0x0b ),
+ PARTNER ( 0x7d, 0x06, 0x60, 0xbf, 0xce, 0x9e, 0x72, 0x63, 0xf6,
+ 0xbf, 0xc7, 0x9b, 0xca, 0x58, 0xfe, 0xca, 0x71, 0x31,
+ 0x07, 0x7d, 0x31, 0xa9, 0x64, 0xdd, 0x3a, 0x2a, 0x9a,
+ 0x49, 0x34, 0x20, 0xfb, 0x49, 0x62, 0xbe, 0x61, 0xae,
+ 0xfa, 0x37, 0x63, 0x53, 0x54, 0x56, 0x36, 0x71, 0xf6,
+ 0x61, 0x86, 0xe8, 0x09, 0x6e, 0x6e, 0x88, 0x81, 0x60,
+ 0xce, 0x1d, 0xdc, 0xf1, 0xb5, 0xfe, 0x4b, 0xf5, 0xc9,
+ 0xf6, 0xc9, 0x9a, 0x63, 0x01, 0x5d, 0x17, 0x23, 0xad,
+ 0xcd, 0x8a, 0x2a, 0xeb, 0xd4, 0x84, 0x7a, 0xb0, 0x22,
+ 0x89, 0x6f, 0x81, 0x07, 0x11, 0x4c, 0xbc, 0xf3, 0x4e,
+ 0xa3, 0x24, 0x35, 0xd5, 0xa2, 0x68, 0x9f, 0x73, 0x56,
+ 0xd3, 0x89, 0x4a, 0xea, 0xfd, 0x9a, 0xd8, 0x0b, 0xaa,
+ 0xb0, 0xfd, 0xd2, 0x67, 0x15, 0x40, 0xa5, 0x9b, 0x2f,
+ 0xc7, 0x89, 0xfd, 0x0b, 0xe4, 0x15, 0x43, 0x57, 0xdf,
+ 0x8d, 0x7f, 0x99, 0x6f, 0x20, 0x76, 0xe9, 0x63, 0xfa,
+ 0x59, 0xd5, 0xff, 0xd9, 0xfe, 0x8a, 0x00, 0x6c, 0xe0,
+ 0x9c, 0x05, 0x2e, 0xbe, 0xbc, 0xc6, 0xdb, 0x71, 0xb7,
+ 0x77, 0x8f, 0xb0, 0xd3, 0x03, 0x0f, 0x18, 0xad, 0x26,
+ 0x04, 0xd3, 0x15, 0x2a, 0x20, 0x7f, 0x66, 0x25, 0xa6,
+ 0x31, 0x21, 0xbd, 0x02, 0x17, 0xa4, 0x42, 0x48, 0x56,
+ 0xd2, 0x16, 0x7a, 0xf8, 0xfe, 0xa3, 0xe7, 0x7d, 0x20,
+ 0xeb, 0xe1, 0x61, 0x24, 0xd0, 0xe7, 0x4f, 0x95, 0xfb,
+ 0x8b, 0x5e, 0xd6, 0x19, 0x44, 0x71, 0x52, 0xe4, 0x88,
+ 0x3d, 0x00, 0xfc, 0x2e, 0x3d, 0x14, 0xf2, 0x6a, 0x72,
+ 0x4f, 0xde, 0x7e, 0x87, 0x0f, 0x19, 0x6e, 0xc5, 0xa0,
+ 0x40, 0xbb, 0xba, 0xf4, 0xda, 0x12, 0x03, 0x4e, 0x5c,
+ 0xbf, 0x94, 0x62, 0x4e, 0x2d, 0xc2, 0x80, 0xb1, 0xd4,
+ 0x44, 0x57, 0xc8, 0x82, 0x0d, 0x3c, 0x48, 0x5a, 0x80,
+ 0x23, 0xd6, 0xbb, 0x44 ),
+ PRIVATE ( 0xc7, 0xb3, 0x46, 0x82, 0x6d, 0xd8, 0xd9, 0x40, 0x6d,
+ 0xda, 0xbf, 0x92, 0x6e, 0x71, 0xee, 0xf1, 0xec, 0xe5,
+ 0xbb, 0x78, 0xd4, 0x32, 0x12, 0xc5, 0xa0, 0x38, 0xd8,
+ 0x35 ),
+ PUBLIC ( 0x78, 0x04, 0x58, 0x69, 0x39, 0x2d, 0x56, 0xf3, 0x52,
+ 0x07, 0x12, 0xa6, 0x8f, 0x29, 0x46, 0x6d, 0x8a, 0x89,
+ 0xcf, 0x41, 0x91, 0x92, 0x50, 0x4c, 0x45, 0x3c, 0x22,
+ 0x4d, 0xbc, 0x9a, 0x0f, 0xfd, 0x29, 0x7d, 0x6c, 0xc1,
+ 0xa3, 0x70, 0xee, 0xe9, 0x39, 0x81, 0x39, 0x9d, 0xa4,
+ 0xc7, 0x08, 0x97, 0xaa, 0xb4, 0x8f, 0x33, 0x4f, 0x05,
+ 0xa5, 0x56, 0x27, 0x33, 0xe4, 0xe7, 0x31, 0xc3, 0x7f,
+ 0x17, 0x38, 0x80, 0x76, 0x00, 0x88, 0xed, 0xb1, 0xe9,
+ 0x98, 0x6a, 0x5d, 0x43, 0x08, 0x06, 0xd5, 0x14, 0x64,
+ 0x24, 0xd9, 0x3a, 0x7f, 0xa4, 0xa3, 0x91, 0x65, 0x9f,
+ 0xf9, 0x66, 0x67, 0x55, 0xe7, 0x5a, 0x14, 0x38, 0x81,
+ 0x61, 0x13, 0xe1, 0x44, 0x8e, 0x6e, 0x14, 0xb4, 0x6c,
+ 0xe8, 0xad, 0x79, 0x08, 0xfe, 0xc3, 0xb8, 0xe5, 0x02,
+ 0x25, 0x72, 0x63, 0xea, 0xba, 0xfe, 0xfc, 0x9a, 0x3b,
+ 0x9c, 0x64, 0x52, 0x21, 0x50, 0xfb, 0xc2, 0x11, 0xf4,
+ 0x5e, 0xef, 0x43, 0x35, 0xfb, 0xc6, 0xdc, 0x01, 0xa9,
+ 0x15, 0x69, 0x43, 0xab, 0xae, 0x05, 0xc3, 0xb1, 0x77,
+ 0xac, 0x9d, 0x7e, 0x3b, 0xd3, 0xc5, 0x7e, 0xf5, 0x8d,
+ 0xf9, 0x52, 0x3b, 0xcf, 0xc5, 0x53, 0x2d, 0x67, 0xac,
+ 0x61, 0x17, 0x4f, 0x6c, 0x9c, 0x09, 0xa9, 0x38, 0x92,
+ 0xdf, 0xbf, 0x49, 0x0d, 0x15, 0x0b, 0x02, 0xf2, 0x24,
+ 0x38, 0x56, 0x19, 0xcf, 0x6d, 0xb9, 0x0a, 0x6f, 0x79,
+ 0x04, 0x2e, 0xf9, 0xef, 0xdb, 0xbc, 0xdb, 0xf2, 0xa3,
+ 0x8b, 0x01, 0x12, 0xec, 0x40, 0xdc, 0x6b, 0xff, 0x2b,
+ 0xc7, 0xf5, 0x96, 0x41, 0x78, 0x40, 0xe3, 0xac, 0x4a,
+ 0xa5, 0xa5, 0xd0, 0x44, 0xe7, 0x1a, 0x87, 0x6a, 0x10,
+ 0xa2, 0x04, 0xdf, 0x71, 0x34, 0x47, 0xf2, 0x92, 0x0d,
+ 0x92, 0x18, 0x0e, 0x14, 0x43, 0x18, 0xce, 0x0e, 0x18,
+ 0xb8, 0x7e, 0xef, 0x6e ),
+ SHARED ( 0x0d, 0xf1, 0xd1, 0xb0, 0xfa, 0xae, 0x8b, 0x8a, 0xfb,
+ 0x7c, 0x47, 0x88, 0x48, 0x49, 0xf2, 0x3a, 0x2d, 0x8f,
+ 0x01, 0xee, 0x47, 0x14, 0x1e, 0x91, 0xd5, 0x49, 0x49,
+ 0xff, 0x7f, 0xd0, 0xd1, 0x10, 0xac, 0x4c, 0xcc, 0xc6,
+ 0x7f, 0x42, 0x8a, 0x04, 0xee, 0x64, 0x41, 0xf8, 0x1d,
+ 0x1a, 0x04, 0x26, 0x3b, 0x99, 0xb5, 0xee, 0xf6, 0x17,
+ 0x94, 0xfd, 0x3d, 0x58, 0x4b, 0xd7, 0xe1, 0xf4, 0xf6,
+ 0x10, 0xb8, 0xdc, 0xb7, 0x8d, 0x04, 0x5f, 0x72, 0x13,
+ 0x19, 0xf6, 0xa8, 0x33, 0x3e, 0x82, 0x8c, 0x56, 0xb1,
+ 0x97, 0x5c, 0x4f, 0xa3, 0xd3, 0x1e, 0xeb, 0x61, 0xa4,
+ 0xc2, 0x04, 0x2c, 0xc9, 0x22, 0x6c, 0x6e, 0xee, 0xa7,
+ 0x5b, 0x66, 0x8b, 0xfb, 0xb5, 0x0d, 0x1b, 0x7c, 0xa1,
+ 0x88, 0xc7, 0x95, 0x85, 0xa4, 0x4c, 0xe5, 0x38, 0x04,
+ 0x1e, 0x94, 0x1b, 0x03, 0xe6, 0xcc, 0xa4, 0x36, 0x58,
+ 0x02, 0xbe, 0x79, 0x89, 0x5a, 0xd2, 0x60, 0x1e, 0x47,
+ 0xe6, 0x26, 0x35, 0x15, 0x3a, 0x91, 0xef, 0x92, 0xa9,
+ 0x0f, 0x89, 0x58, 0xd3, 0xf7, 0xd2, 0xc5, 0x03, 0x61,
+ 0x37, 0x78, 0x51, 0x1e, 0x39, 0x4d, 0x92, 0x8f, 0xdd,
+ 0xb0, 0x7d, 0xc7, 0xad, 0xf4, 0x34, 0x85, 0x4e, 0x94,
+ 0x85, 0x19, 0xf1, 0xbf, 0xb7, 0xca, 0x02, 0x3b, 0xb0,
+ 0x46, 0x45, 0x96, 0xb6, 0x01, 0x0e, 0x38, 0x0d, 0xa5,
+ 0xd7, 0x13, 0x5c, 0x5a, 0x0d, 0x41, 0xc5, 0x6d, 0x37,
+ 0x92, 0xf6, 0xdc, 0x5e, 0x09, 0xa4, 0x2f, 0x7e, 0x2a,
+ 0x94, 0x86, 0xd8, 0x59, 0x0b, 0x01, 0x54, 0x2a, 0xe6,
+ 0x9f, 0xa1, 0x4f, 0xa5, 0x82, 0xca, 0x73, 0x44, 0x43,
+ 0x47, 0x05, 0x64, 0x9d, 0x68, 0x78, 0x85, 0xcc, 0x24,
+ 0x77, 0xaa, 0x4c, 0x08, 0x8d, 0x47, 0x33, 0x95, 0x48,
+ 0x92, 0x6b, 0x9f, 0x7a, 0x17, 0x13, 0x82, 0x67, 0xf3,
+ 0xe4, 0x55, 0x89, 0xdb ) );
+
+/* KASValidityTest_FFCEphem_NOKC_ZZOnly_init.fax test 0 */
+DHE_TEST ( kasvaliditytest_ffcephem_nokc_zzonly_init_fc_0,
+ MODULUS ( 0xc7, 0x37, 0xde, 0x69, 0x33, 0x3e, 0xb6, 0xd7, 0xe8,
+ 0x3f, 0x8c, 0xfc, 0x69, 0xbb, 0x39, 0xcf, 0x2d, 0xd1,
+ 0xe6, 0xe3, 0xd0, 0x03, 0x9a, 0x3b, 0x25, 0x53, 0x39,
+ 0x4b, 0xbb, 0xe2, 0x7a, 0x25, 0xa3, 0x5b, 0x76, 0xf4,
+ 0xd5, 0x6b, 0xb6, 0x95, 0xf3, 0x6e, 0x87, 0x1d, 0x68,
+ 0x0f, 0x62, 0xfc, 0xce, 0xef, 0x57, 0x0f, 0xd1, 0x24,
+ 0xfe, 0x55, 0xe1, 0xfe, 0xfa, 0x70, 0xb4, 0x7a, 0x38,
+ 0x8f, 0x26, 0x4a, 0xa5, 0x28, 0x2d, 0x11, 0x51, 0x62,
+ 0x17, 0x4f, 0x27, 0xe1, 0x80, 0x3b, 0xf4, 0x2b, 0xde,
+ 0x54, 0x91, 0xe5, 0x8c, 0xfe, 0x15, 0x0e, 0x76, 0xbf,
+ 0xbd, 0x83, 0x62, 0xdf, 0xc4, 0xc1, 0x22, 0x39, 0x65,
+ 0x7d, 0x7c, 0x65, 0x74, 0xb1, 0x81, 0xb1, 0xfc, 0xf8,
+ 0x8c, 0xc0, 0xc8, 0x91, 0xec, 0xd9, 0xcc, 0x43, 0xb4,
+ 0x10, 0xa6, 0x50, 0xfd, 0xaf, 0x26, 0xb8, 0x01, 0xdc,
+ 0x88, 0xa1, 0x3d, 0x67, 0x27, 0xe0, 0x3d, 0x9a, 0x18,
+ 0xf8, 0x9b, 0x9c, 0xb3, 0xee, 0x80, 0xcc, 0x2d, 0x1e,
+ 0xb5, 0x33, 0xf4, 0xcc, 0xce, 0x09, 0x4f, 0xb3, 0xe2,
+ 0x33, 0xde, 0xd0, 0x79, 0x10, 0x5d, 0x1f, 0xbc, 0x21,
+ 0xdc, 0xa3, 0xf8, 0x72, 0x97, 0xc3, 0x7a, 0xe5, 0x37,
+ 0xb8, 0x88, 0x71, 0xce, 0xdc, 0xf5, 0x65, 0x89, 0xf1,
+ 0x13, 0xc9, 0xb3, 0x2a, 0xcf, 0xb5, 0xb8, 0xd4, 0x2d,
+ 0xf6, 0x03, 0x27, 0x87, 0x14, 0xd8, 0xa6, 0xbe, 0x1c,
+ 0x7e, 0x74, 0x27, 0x04, 0xf1, 0x27, 0x79, 0xf1, 0x08,
+ 0x92, 0xca, 0xf0, 0xef, 0x40, 0x4f, 0x06, 0xa0, 0x8c,
+ 0xff, 0x11, 0x02, 0x97, 0xac, 0x0d, 0x2a, 0x99, 0x93,
+ 0x6c, 0x15, 0xfa, 0x30, 0xed, 0x7d, 0xee, 0x19, 0xc5,
+ 0xbb, 0x5c, 0x6d, 0x55, 0x54, 0x2e, 0xa0, 0xb9, 0x4f,
+ 0xed, 0xe0, 0x32, 0x73, 0xf6, 0x2a, 0x11, 0xc6, 0xd6,
+ 0xe4, 0x27, 0x9c, 0x19 ),
+ GENERATOR ( 0x3a, 0xb1, 0xe0, 0x51, 0x9b, 0xcc, 0xc1, 0xa4, 0x6c,
+ 0xb9, 0x12, 0x4c, 0xb1, 0x1a, 0xcf, 0x3b, 0x42, 0x69,
+ 0x1a, 0x7f, 0x40, 0x83, 0x10, 0x5f, 0xd9, 0xac, 0xe0,
+ 0x13, 0x54, 0xec, 0xcb, 0xed, 0x1d, 0x05, 0xb6, 0x4b,
+ 0x14, 0x94, 0x91, 0xd1, 0x0a, 0x92, 0xdb, 0x1f, 0x56,
+ 0xea, 0x9d, 0x9b, 0xe2, 0xba, 0x60, 0x31, 0x0c, 0x1e,
+ 0xe3, 0xf6, 0xa2, 0x7c, 0x20, 0x19, 0x36, 0x32, 0xff,
+ 0x4f, 0x8e, 0x0e, 0x79, 0xe8, 0xd1, 0x7d, 0x27, 0x51,
+ 0xa5, 0x78, 0x08, 0x60, 0xd1, 0x52, 0x53, 0x75, 0x49,
+ 0x42, 0x5c, 0x69, 0x6e, 0x66, 0x26, 0xaa, 0x5e, 0x79,
+ 0x42, 0x76, 0xf1, 0x86, 0xfd, 0xcc, 0x04, 0x5b, 0x30,
+ 0x55, 0xec, 0x5b, 0x40, 0xf4, 0xe3, 0xbf, 0xf9, 0x8a,
+ 0x2b, 0x1a, 0x54, 0x5b, 0x80, 0x19, 0xc4, 0xa1, 0x36,
+ 0x0a, 0x49, 0x0e, 0xb9, 0xc6, 0xd7, 0x7e, 0xfb, 0x24,
+ 0x84, 0x26, 0x10, 0xb2, 0xfc, 0xcd, 0x9b, 0xd9, 0x53,
+ 0xc9, 0xd7, 0x0f, 0x6d, 0xf4, 0xcf, 0xdc, 0xe7, 0xb0,
+ 0x1a, 0x4d, 0x21, 0x4c, 0x99, 0xb1, 0x1c, 0x5d, 0x28,
+ 0x09, 0x96, 0xd5, 0x3e, 0xef, 0x09, 0x3b, 0xd5, 0x29,
+ 0xa5, 0x2d, 0xcc, 0xdb, 0x9c, 0xaf, 0xd9, 0x6f, 0xa7,
+ 0xc9, 0x28, 0x8b, 0x14, 0xf4, 0x8e, 0x0b, 0x4e, 0x35,
+ 0xdf, 0x57, 0x22, 0xb2, 0x8a, 0xa0, 0x05, 0xa8, 0x84,
+ 0xb4, 0x57, 0xcb, 0x12, 0x07, 0x8f, 0x9e, 0x83, 0xb3,
+ 0xbe, 0xac, 0xb0, 0x3e, 0xf2, 0x47, 0x6b, 0x22, 0x63,
+ 0xd2, 0x03, 0xa3, 0x3b, 0xc5, 0x17, 0x05, 0xe7, 0xe8,
+ 0xe6, 0x18, 0xd3, 0x41, 0x94, 0xc7, 0x16, 0xde, 0x38,
+ 0x0c, 0xb1, 0xb7, 0xeb, 0xe5, 0x55, 0xf2, 0x2e, 0xa6,
+ 0xe5, 0x61, 0x75, 0xd0, 0x7d, 0x6c, 0xbe, 0xd1, 0xc9,
+ 0x4c, 0x59, 0xfb, 0x37, 0xb7, 0xdc, 0xd5, 0x6f, 0xf7,
+ 0xb2, 0xf2, 0xf9, 0x97 ),
+ PARTNER ( 0x65, 0x6c, 0x5d, 0x99, 0xbc, 0xb5, 0x92, 0x1f, 0xc2,
+ 0xf7, 0x86, 0x99, 0xd9, 0x8e, 0xe0, 0x46, 0xbe, 0x70,
+ 0x76, 0x1a, 0x85, 0x7a, 0x9d, 0xfe, 0xad, 0x51, 0x7b,
+ 0xee, 0x16, 0xe8, 0xae, 0xf9, 0x19, 0x26, 0x04, 0xa8,
+ 0x29, 0x5e, 0x02, 0xef, 0xd4, 0xfe, 0xf2, 0x43, 0x64,
+ 0xd0, 0x53, 0x4f, 0xa2, 0x7c, 0x41, 0xef, 0x85, 0x0d,
+ 0xe2, 0xee, 0xb7, 0x4f, 0x03, 0xb4, 0x7d, 0x59, 0x0b,
+ 0x8d, 0x32, 0x4c, 0x9b, 0xf9, 0x48, 0x53, 0x7b, 0xa9,
+ 0xb7, 0x32, 0x1d, 0x1e, 0x51, 0xf2, 0x69, 0x66, 0x44,
+ 0xf3, 0x9c, 0x78, 0xa9, 0xa7, 0x4a, 0x93, 0x90, 0xb0,
+ 0xc3, 0x79, 0x36, 0xdd, 0xda, 0x92, 0xfe, 0x71, 0x60,
+ 0x21, 0xf6, 0xea, 0xb6, 0xa9, 0xbe, 0x9f, 0x42, 0x12,
+ 0xf7, 0x8a, 0x51, 0x2e, 0x39, 0x43, 0x50, 0xbb, 0xe4,
+ 0xbf, 0x6a, 0x5f, 0x8c, 0x97, 0x97, 0x74, 0x67, 0xf6,
+ 0xb1, 0xd9, 0x2a, 0xc9, 0x88, 0xc8, 0x1c, 0xe2, 0x48,
+ 0x81, 0xba, 0x59, 0x5d, 0x5f, 0x62, 0x8b, 0x25, 0x24,
+ 0x57, 0x9e, 0x47, 0xc9, 0xdc, 0x88, 0x6a, 0x32, 0x4a,
+ 0x6c, 0x37, 0xd7, 0x73, 0x38, 0x0b, 0x6a, 0xf6, 0x45,
+ 0xac, 0x38, 0x49, 0xd0, 0xc7, 0x8d, 0x1d, 0x9e, 0x3a,
+ 0x4c, 0xce, 0xba, 0x0a, 0xc9, 0x54, 0x6b, 0x9d, 0x9c,
+ 0xb7, 0x2b, 0xf4, 0x7a, 0x00, 0xd3, 0xd2, 0xfe, 0x79,
+ 0x8d, 0xb4, 0x6e, 0xe9, 0x38, 0x95, 0xaa, 0x21, 0x2f,
+ 0x71, 0xe1, 0xd4, 0xa8, 0x21, 0x4a, 0x87, 0x4f, 0xcd,
+ 0xa6, 0xca, 0x60, 0x4d, 0xc1, 0xa2, 0x28, 0xcf, 0xa9,
+ 0x55, 0x14, 0xca, 0x24, 0xa9, 0x1b, 0x99, 0xbe, 0x98,
+ 0x4c, 0x7d, 0xff, 0x5e, 0x05, 0xf9, 0x1e, 0x56, 0x65,
+ 0x00, 0x22, 0x65, 0xfb, 0x72, 0x30, 0x3f, 0xae, 0xc0,
+ 0xbb, 0x67, 0xcc, 0xe2, 0x51, 0xa7, 0x06, 0x59, 0x86,
+ 0x1d, 0x43, 0xbb, 0x35 ),
+ PRIVATE ( 0x83, 0x27, 0x46, 0xed, 0x42, 0x07, 0xdf, 0xff, 0x0a,
+ 0x89, 0x19, 0xae, 0x6a, 0xb5, 0x29, 0x2c, 0x37, 0xcb,
+ 0x8b, 0x26, 0xd4, 0x06, 0x27, 0xee, 0xb2, 0xf6, 0x36,
+ 0x46, 0x08, 0xc8, 0x34, 0x54 ),
+ PUBLIC ( 0x88, 0x9d, 0xa3, 0xae, 0x17, 0x79, 0xf8, 0xb6, 0x4e,
+ 0xc4, 0x56, 0xa8, 0x8d, 0x7a, 0x10, 0x5b, 0xdd, 0x7a,
+ 0xaa, 0x87, 0x10, 0xa3, 0x3c, 0xcc, 0x7d, 0x80, 0x59,
+ 0x43, 0x22, 0x91, 0xfc, 0xbf, 0x6d, 0x63, 0x5e, 0x13,
+ 0xc2, 0x8d, 0x19, 0x94, 0x84, 0xbc, 0x56, 0x45, 0x31,
+ 0x71, 0x75, 0x2c, 0x81, 0x18, 0x6e, 0x10, 0x1d, 0x2b,
+ 0x3d, 0x2c, 0xf9, 0x2e, 0x93, 0x6b, 0xed, 0xfa, 0x17,
+ 0xd2, 0x95, 0x30, 0xca, 0xc8, 0x26, 0x0c, 0x78, 0x8f,
+ 0x75, 0x87, 0x0e, 0x30, 0x1e, 0x6c, 0x5e, 0xae, 0xc7,
+ 0x99, 0x37, 0xb0, 0x02, 0x00, 0xda, 0xc1, 0x36, 0x24,
+ 0x12, 0xdd, 0xe4, 0x2b, 0x8a, 0xca, 0xf9, 0x35, 0x36,
+ 0x4b, 0x6d, 0xff, 0xa2, 0x51, 0xd1, 0xe6, 0xa0, 0x78,
+ 0xf3, 0x0f, 0xc3, 0x9e, 0x4e, 0x1c, 0xc6, 0xf6, 0x38,
+ 0x50, 0x07, 0x18, 0x42, 0x04, 0x8c, 0xe7, 0xdf, 0xeb,
+ 0x2a, 0xda, 0x96, 0x28, 0xae, 0xe1, 0x7d, 0x55, 0x96,
+ 0xb0, 0x5a, 0x4e, 0x71, 0xa9, 0xfa, 0x6f, 0x0e, 0x0d,
+ 0xff, 0xea, 0xe0, 0xca, 0xa2, 0xf9, 0x5a, 0x68, 0x3b,
+ 0x3b, 0x29, 0x7e, 0x15, 0x6b, 0x90, 0x95, 0x1c, 0x80,
+ 0xf9, 0x08, 0x03, 0xa8, 0xa5, 0x19, 0x9b, 0xe9, 0xde,
+ 0xb4, 0xf0, 0x18, 0xb4, 0xcd, 0x3c, 0xaf, 0x0b, 0x4d,
+ 0x3c, 0xe5, 0xd6, 0x58, 0xe3, 0x0f, 0xe2, 0x72, 0xcd,
+ 0xe9, 0xd2, 0xc2, 0x57, 0x9a, 0x5e, 0x3f, 0xbd, 0xe2,
+ 0xaa, 0x3a, 0xd4, 0xe0, 0xae, 0x05, 0x9c, 0xfc, 0x69,
+ 0xda, 0x62, 0xd0, 0x6f, 0x70, 0x4f, 0xeb, 0x77, 0x09,
+ 0x1f, 0xac, 0x6f, 0xde, 0x3a, 0xe3, 0xbb, 0x6b, 0x3d,
+ 0xae, 0xec, 0x9d, 0xd6, 0xbc, 0xf5, 0xb1, 0x69, 0x70,
+ 0xf2, 0x6e, 0xc8, 0xde, 0x3c, 0xe7, 0x9b, 0x8f, 0x37,
+ 0xe2, 0x7e, 0xe0, 0x4a, 0x28, 0x0f, 0x28, 0xac, 0xe8,
+ 0x63, 0xf2, 0xd3, 0x13 ),
+ SHARED ( 0x26, 0x2d, 0x59, 0xd0, 0x4c, 0x02, 0x1b, 0x84, 0xc1,
+ 0x16, 0x96, 0xc9, 0x9f, 0xbc, 0x03, 0x50, 0x5b, 0xe5,
+ 0x6b, 0x76, 0x0d, 0x63, 0xf1, 0x0b, 0xa5, 0x30, 0x9c,
+ 0x58, 0x60, 0x96, 0x9d, 0xf6, 0xc1, 0x3c, 0x61, 0xb3,
+ 0x9a, 0x21, 0x37, 0x4c, 0xb3, 0x5e, 0x17, 0x72, 0x60,
+ 0x50, 0x8a, 0xbb, 0xe0, 0x02, 0xf3, 0x7d, 0x15, 0x67,
+ 0x76, 0x97, 0x39, 0x85, 0xe4, 0x66, 0x50, 0x91, 0x31,
+ 0xbc, 0x45, 0xef, 0x0e, 0x32, 0xb9, 0x8b, 0xdb, 0x6c,
+ 0x18, 0x72, 0x06, 0xde, 0x7b, 0xda, 0xc4, 0xaf, 0x5e,
+ 0x39, 0x47, 0x85, 0x0e, 0xea, 0x89, 0x7a, 0xd1, 0xe3,
+ 0xa7, 0x60, 0x73, 0x86, 0xd4, 0xbe, 0x8b, 0xae, 0x01,
+ 0xf3, 0x3d, 0x28, 0xfd, 0xd7, 0x6a, 0xbb, 0x62, 0x80,
+ 0xc6, 0x7b, 0xaa, 0xf3, 0x1e, 0xff, 0x52, 0xf2, 0x87,
+ 0x4c, 0x8b, 0x0e, 0x2f, 0x3c, 0x38, 0x24, 0x13, 0x3a,
+ 0xad, 0x4a, 0x4f, 0x87, 0x0a, 0x81, 0x8b, 0xdf, 0x69,
+ 0x14, 0xd7, 0xe0, 0xbe, 0x1e, 0x61, 0x9f, 0x62, 0xa8,
+ 0x47, 0x78, 0x66, 0x9b, 0xef, 0x83, 0xbf, 0x5d, 0xd9,
+ 0xdf, 0x5f, 0x29, 0x23, 0x9a, 0x57, 0xc6, 0x35, 0x2e,
+ 0x70, 0x9e, 0x30, 0x05, 0x83, 0x29, 0xd8, 0xdd, 0xc1,
+ 0xe6, 0x9b, 0x08, 0x4b, 0x49, 0x53, 0x60, 0xde, 0xe0,
+ 0xda, 0x83, 0xf4, 0x58, 0xf6, 0x53, 0x49, 0x1b, 0x9b,
+ 0x77, 0x70, 0x16, 0xe4, 0xd9, 0x14, 0x72, 0xd7, 0xca,
+ 0xf6, 0x84, 0xd9, 0x79, 0xdf, 0xfa, 0xaa, 0xa6, 0xeb,
+ 0xa1, 0x5e, 0x63, 0x35, 0x08, 0x8b, 0xff, 0x15, 0x1b,
+ 0x39, 0xde, 0x8a, 0x20, 0x3d, 0xb8, 0xff, 0x29, 0x03,
+ 0x4c, 0x98, 0xcc, 0xcb, 0xcd, 0x7e, 0x0b, 0x3b, 0x77,
+ 0x5d, 0xa4, 0x77, 0x1a, 0xfd, 0xb5, 0x5c, 0x5d, 0x3f,
+ 0x80, 0xd0, 0xe2, 0xb3, 0x00, 0xdf, 0x14, 0x26, 0x77,
+ 0x81, 0x95, 0xbf, 0x64 ) );
+
+/* KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.fax test 0 */
+DHE_TEST ( kasvaliditytest_ffcephem_nokc_zzonly_resp_fb_0,
+ MODULUS ( 0x92, 0xac, 0x82, 0xb2, 0x88, 0x5b, 0x17, 0x4d, 0x24,
+ 0x3d, 0x1e, 0x7d, 0x5b, 0xed, 0x4b, 0x6b, 0xac, 0x61,
+ 0xbd, 0x71, 0x32, 0x30, 0x1b, 0xe5, 0xf1, 0xe6, 0x69,
+ 0x43, 0x6d, 0x40, 0x92, 0x95, 0xee, 0x9c, 0x70, 0x05,
+ 0xe5, 0xa1, 0x6f, 0x84, 0x78, 0xfb, 0x6f, 0xd2, 0x14,
+ 0xa1, 0x96, 0xc9, 0x8e, 0xf9, 0xe5, 0x91, 0xe4, 0x5c,
+ 0xd9, 0x33, 0x17, 0x70, 0x3a, 0x2a, 0xec, 0x5b, 0x10,
+ 0x6e, 0xd7, 0xcc, 0x4a, 0x98, 0x7b, 0xa1, 0xae, 0xf7,
+ 0xf6, 0x21, 0x34, 0x8f, 0x00, 0x2b, 0xa9, 0x87, 0x55,
+ 0xe0, 0x10, 0xf0, 0x32, 0x7c, 0xb5, 0x38, 0xec, 0x9b,
+ 0x1a, 0xec, 0x01, 0xdf, 0xaf, 0x26, 0xf1, 0xac, 0x33,
+ 0xb9, 0x17, 0xa9, 0x89, 0xbc, 0x73, 0x98, 0xf1, 0x23,
+ 0x4c, 0x25, 0x52, 0xdc, 0xda, 0xc6, 0x5e, 0x4c, 0xab,
+ 0xc3, 0x7b, 0x5b, 0x24, 0x91, 0x7d, 0xc1, 0x66, 0x46,
+ 0x4b, 0x7a, 0xff, 0x26, 0x89, 0x13, 0x88, 0x79, 0xcf,
+ 0xfa, 0x2a, 0x9e, 0x7c, 0x11, 0xab, 0xff, 0xf1, 0x19,
+ 0x17, 0x77, 0x9b, 0xad, 0x99, 0xfd, 0x31, 0x69, 0x44,
+ 0x7e, 0xf5, 0x08, 0x7f, 0xb6, 0x1e, 0x1a, 0x92, 0x95,
+ 0x55, 0x2d, 0xb7, 0x61, 0xe0, 0x67, 0x87, 0xfa, 0x44,
+ 0xce, 0x83, 0xdf, 0xd5, 0x22, 0x9f, 0x0b, 0xd1, 0x2a,
+ 0x86, 0x73, 0xd0, 0xfc, 0x90, 0x55, 0xbe, 0x05, 0x94,
+ 0x89, 0x8b, 0x5b, 0x03, 0x10, 0xfd, 0xc5, 0x0b, 0xa1,
+ 0x3f, 0x79, 0x00, 0xd5, 0xff, 0xf1, 0xe8, 0x1f, 0xbc,
+ 0x90, 0x42, 0xbf, 0x20, 0x4d, 0x5f, 0x0a, 0xaa, 0x69,
+ 0x66, 0xf7, 0x25, 0xa4, 0xb6, 0xc4, 0x84, 0x8a, 0x8d,
+ 0x81, 0x68, 0xe3, 0x38, 0x9d, 0x7d, 0xfe, 0xca, 0x6a,
+ 0xcd, 0x89, 0xde, 0x55, 0xf4, 0x2d, 0x91, 0x1b, 0x74,
+ 0x9b, 0xb5, 0xb8, 0x2d, 0x61, 0xef, 0x46, 0x32, 0x16,
+ 0xd6, 0x69, 0xac, 0x73 ),
+ GENERATOR ( 0x2e, 0xf4, 0x37, 0xfb, 0x4f, 0x8d, 0xed, 0x56, 0x1d,
+ 0xb4, 0xfe, 0x58, 0x81, 0x53, 0xa3, 0xbe, 0x42, 0x58,
+ 0x72, 0x70, 0xa0, 0xec, 0xf6, 0x42, 0x05, 0x01, 0x87,
+ 0x59, 0xeb, 0x0b, 0xc0, 0x60, 0xf6, 0x27, 0x77, 0x29,
+ 0x7b, 0x3a, 0x99, 0xf4, 0x89, 0x53, 0xfd, 0xce, 0x34,
+ 0xa0, 0xe9, 0x66, 0xdc, 0x9f, 0x79, 0xbc, 0x3b, 0xee,
+ 0x43, 0xbe, 0xad, 0x12, 0xd5, 0x93, 0x72, 0x91, 0x30,
+ 0xef, 0xf2, 0x2a, 0xd7, 0xe8, 0x35, 0x14, 0x79, 0x8f,
+ 0xbf, 0xfc, 0x9c, 0xcc, 0xb3, 0x4a, 0x87, 0x93, 0xaa,
+ 0x95, 0xaf, 0xd2, 0x68, 0x62, 0x47, 0xb5, 0xc1, 0x78,
+ 0x02, 0xc1, 0xd6, 0xe6, 0x46, 0x33, 0x7b, 0xad, 0x88,
+ 0x11, 0x8b, 0x74, 0x07, 0x44, 0x71, 0x3a, 0xd8, 0x4b,
+ 0xf4, 0x82, 0xa6, 0x50, 0x36, 0x4c, 0xf0, 0xc4, 0x4b,
+ 0xe2, 0xe6, 0x42, 0x42, 0xf2, 0x98, 0x98, 0xaf, 0x72,
+ 0x2f, 0xec, 0xf3, 0x9a, 0x49, 0xab, 0xa0, 0xbe, 0xfc,
+ 0x3d, 0xb6, 0x8c, 0xc7, 0x89, 0xf6, 0x07, 0x6f, 0xe9,
+ 0x00, 0x85, 0x6c, 0x01, 0xb1, 0xfd, 0x1e, 0x70, 0xce,
+ 0x0e, 0xce, 0xae, 0xe1, 0x71, 0x7f, 0xff, 0x94, 0x8a,
+ 0xd9, 0xd6, 0x6d, 0x76, 0x28, 0x0a, 0x5f, 0x3e, 0x64,
+ 0xaa, 0x4a, 0x37, 0x39, 0x51, 0xe8, 0x9d, 0xd1, 0x78,
+ 0x53, 0xe0, 0x81, 0xb6, 0xa8, 0x90, 0xdd, 0x79, 0xb1,
+ 0x47, 0x81, 0x75, 0x34, 0xf4, 0x6f, 0xc3, 0x8e, 0x7d,
+ 0xa7, 0x29, 0xc6, 0xd4, 0x5f, 0x5e, 0x25, 0x4f, 0xa1,
+ 0xe1, 0x90, 0xb3, 0x85, 0xfb, 0xe9, 0xf1, 0x60, 0x65,
+ 0x4a, 0x14, 0xe5, 0xb3, 0xc2, 0x83, 0x66, 0x7f, 0x5f,
+ 0x2e, 0x0a, 0xd1, 0x44, 0xbf, 0x10, 0xbf, 0xd3, 0xf9,
+ 0x12, 0x37, 0x0e, 0x81, 0x24, 0x35, 0x49, 0xac, 0xd4,
+ 0x48, 0x3d, 0xaa, 0x43, 0xf1, 0x4a, 0xbc, 0x08, 0xfc,
+ 0xaf, 0xa0, 0xbe, 0x29 ),
+ PARTNER ( 0x4d, 0x7c, 0xea, 0x09, 0x9b, 0x64, 0xdb, 0x3d, 0xdc,
+ 0x8d, 0x3f, 0x8b, 0xd8, 0xb1, 0xcb, 0xea, 0xd7, 0xe0,
+ 0x71, 0xe4, 0x1c, 0x58, 0xcf, 0x08, 0xda, 0x3d, 0xa1,
+ 0x8c, 0x0b, 0x7c, 0xac, 0x6f, 0x76, 0xa4, 0xd8, 0xa9,
+ 0x91, 0xec, 0x9e, 0x74, 0x34, 0x52, 0x02, 0x43, 0x55,
+ 0xa9, 0xa1, 0xf6, 0xd5, 0xc8, 0x67, 0xad, 0x4d, 0x98,
+ 0xeb, 0x8e, 0xf4, 0x72, 0x95, 0x20, 0xd4, 0x7b, 0x38,
+ 0x4a, 0xa3, 0x8b, 0x21, 0x9b, 0x85, 0x4d, 0x05, 0xf1,
+ 0x94, 0x89, 0xa3, 0x34, 0x9d, 0x9e, 0xaa, 0x23, 0x97,
+ 0xac, 0x7e, 0xb2, 0xe8, 0x7f, 0x9e, 0x1e, 0x59, 0x5e,
+ 0xe0, 0xea, 0xcf, 0xff, 0x86, 0x56, 0x80, 0x22, 0xc9,
+ 0x03, 0x6c, 0x05, 0x8c, 0x19, 0x6d, 0xaa, 0x82, 0xdd,
+ 0x47, 0xab, 0xbf, 0x24, 0xe6, 0xea, 0xb8, 0xc9, 0xc1,
+ 0x9e, 0x64, 0xd1, 0x7b, 0xee, 0x9b, 0xed, 0x99, 0xd2,
+ 0x90, 0x3a, 0x4b, 0x90, 0xc3, 0xbb, 0xf5, 0xa4, 0x49,
+ 0xb5, 0xfc, 0xa8, 0x6e, 0x07, 0x9a, 0x27, 0xfb, 0x0f,
+ 0x67, 0xa1, 0x14, 0x0e, 0x30, 0x80, 0x4e, 0x60, 0xdf,
+ 0x01, 0x62, 0x25, 0x8f, 0xb7, 0x18, 0x14, 0x56, 0x5e,
+ 0x76, 0x14, 0xe9, 0x15, 0x35, 0xdb, 0x52, 0xef, 0x34,
+ 0x60, 0x22, 0x01, 0x3c, 0x75, 0x01, 0x27, 0x13, 0xe9,
+ 0x0a, 0xa7, 0x67, 0x05, 0xb5, 0xec, 0x7a, 0x60, 0xdc,
+ 0xb5, 0xdd, 0xdc, 0xc9, 0x9d, 0xbb, 0x10, 0x7b, 0x3d,
+ 0xd9, 0x8f, 0x31, 0xff, 0x26, 0xce, 0x7c, 0x78, 0x24,
+ 0xa8, 0xe7, 0xa5, 0x6d, 0xb4, 0xc2, 0x98, 0x66, 0xac,
+ 0xac, 0x06, 0x4e, 0xa3, 0x85, 0x63, 0xd6, 0xf7, 0xa4,
+ 0x53, 0x91, 0xe5, 0x16, 0x74, 0x14, 0xfe, 0x91, 0x61,
+ 0x95, 0x1f, 0x30, 0xdb, 0xbc, 0x8e, 0xf1, 0xf3, 0x08,
+ 0x8b, 0x0e, 0x8a, 0xc8, 0x6f, 0xe0, 0x5e, 0x48, 0x19,
+ 0x6b, 0xe6, 0x70, 0x10 ),
+ PRIVATE ( 0x68, 0x22, 0xbd, 0xe0, 0x50, 0xfc, 0xdd, 0xf9, 0x0b,
+ 0xa8, 0xc3, 0x98, 0xd6, 0xc9, 0x73, 0x55, 0x2b, 0xe0,
+ 0xf8, 0xf4, 0xb4, 0x8c, 0x86, 0xdf, 0xdd, 0xa2, 0xc1,
+ 0x87 ),
+ PUBLIC ( 0x1e, 0xab, 0x79, 0xb7, 0x83, 0xe8, 0x74, 0x90, 0xa8,
+ 0xab, 0x90, 0x24, 0x02, 0xaa, 0xd7, 0x9d, 0x2c, 0x90,
+ 0x35, 0x2a, 0xf3, 0x54, 0x26, 0x69, 0x1c, 0xac, 0xe0,
+ 0x73, 0x8f, 0xc9, 0xa4, 0x18, 0xee, 0x4f, 0xfd, 0x9f,
+ 0xd3, 0x0d, 0x04, 0x8b, 0xa4, 0x38, 0xa4, 0x87, 0xf6,
+ 0x97, 0x5d, 0x5c, 0x20, 0x22, 0x53, 0xcb, 0xf2, 0xa8,
+ 0x54, 0xff, 0x36, 0x28, 0xde, 0xf8, 0x1d, 0x92, 0x3a,
+ 0x88, 0x20, 0x00, 0xa3, 0xd4, 0xdd, 0x4d, 0x8b, 0x16,
+ 0x7a, 0xdc, 0xcd, 0x71, 0xe4, 0x2e, 0x61, 0xad, 0xae,
+ 0x02, 0x4f, 0xa1, 0xf6, 0x69, 0x09, 0x9c, 0xd8, 0x0a,
+ 0xb3, 0x13, 0xb2, 0xd8, 0x44, 0xea, 0xdf, 0xdf, 0x78,
+ 0x6d, 0xfd, 0x5b, 0x6b, 0x5d, 0x94, 0xe5, 0x47, 0x79,
+ 0xde, 0xc0, 0x1f, 0xf8, 0x63, 0x39, 0x4c, 0xdd, 0xd3,
+ 0xe8, 0x5a, 0x91, 0xe7, 0x2d, 0xd6, 0xa4, 0x0b, 0x77,
+ 0x44, 0xbc, 0xad, 0x37, 0x62, 0x5e, 0xb9, 0x88, 0x7e,
+ 0x9a, 0x12, 0x5f, 0x7b, 0x61, 0x6c, 0xa7, 0x45, 0x9b,
+ 0xae, 0x96, 0xd5, 0x29, 0x72, 0x53, 0xdf, 0x39, 0x8e,
+ 0xd3, 0xfd, 0x0d, 0x1a, 0xf9, 0xf3, 0xbf, 0x66, 0x3a,
+ 0x2c, 0xdf, 0x36, 0x03, 0xb0, 0x5d, 0x72, 0xe7, 0x27,
+ 0x65, 0x8a, 0x40, 0x83, 0xfb, 0x49, 0x81, 0xea, 0xb3,
+ 0x81, 0xcc, 0x99, 0x7a, 0x82, 0x19, 0xd4, 0x5e, 0xd6,
+ 0xef, 0xa5, 0x5f, 0x64, 0x3d, 0x0c, 0x8e, 0xbe, 0x3a,
+ 0x7c, 0x32, 0xd0, 0x5e, 0x90, 0x1e, 0xe2, 0x24, 0x40,
+ 0x2d, 0xbf, 0xfc, 0x1e, 0xa1, 0xa2, 0x6b, 0xbc, 0xba,
+ 0xdd, 0xc8, 0x01, 0xcf, 0x9f, 0x51, 0x19, 0xb8, 0x3d,
+ 0x6e, 0xe9, 0x17, 0x74, 0x71, 0x2e, 0x56, 0x76, 0xf1,
+ 0x67, 0x48, 0xe2, 0x82, 0xa8, 0x44, 0x39, 0x5b, 0x47,
+ 0xe1, 0xc1, 0xee, 0xef, 0x41, 0x33, 0x1d, 0xdb, 0xcd,
+ 0xe6, 0x5e, 0x47, 0x5e ),
+ SHARED ( 0x35, 0xd7, 0xbe, 0xe8, 0x45, 0x91, 0xa8, 0xaf, 0xe9,
+ 0x29, 0x38, 0xaf, 0x83, 0x18, 0xe2, 0xb3, 0x50, 0xea,
+ 0x55, 0x03, 0x80, 0xa7, 0x8f, 0x81, 0x70, 0xb8, 0x6d,
+ 0x47, 0x0a, 0x2b, 0x69, 0x15, 0x4b, 0x6f, 0x96, 0xc9,
+ 0x7e, 0x46, 0x6d, 0x68, 0x75, 0xf5, 0x8f, 0x41, 0x0f,
+ 0xa2, 0x94, 0xa6, 0xa8, 0xcb, 0x55, 0x2d, 0x79, 0xf1,
+ 0xa4, 0xaa, 0x01, 0xf3, 0x01, 0x9c, 0x56, 0x5e, 0xce,
+ 0xf3, 0xe9, 0x2b, 0xbd, 0xa1, 0x8e, 0xe3, 0xf4, 0x76,
+ 0x0e, 0x91, 0x95, 0xff, 0x75, 0x72, 0x3b, 0xe3, 0x0b,
+ 0x86, 0x27, 0xe7, 0xd4, 0x46, 0x17, 0x4c, 0x13, 0x8f,
+ 0x6c, 0x49, 0x1d, 0x1a, 0xeb, 0x12, 0x36, 0xe4, 0x68,
+ 0xd0, 0xbe, 0xed, 0x08, 0x95, 0xad, 0x1a, 0x8d, 0xd6,
+ 0x3f, 0xe9, 0xc5, 0xe5, 0xed, 0x5e, 0xed, 0xbd, 0x34,
+ 0xb1, 0x67, 0x19, 0x03, 0x31, 0x9e, 0x3d, 0xbd, 0x1d,
+ 0x6f, 0xac, 0x86, 0x2d, 0xff, 0x0a, 0xa5, 0x82, 0x8d,
+ 0x4a, 0xb5, 0xc8, 0x28, 0x4b, 0xf7, 0x41, 0x35, 0xf4,
+ 0x18, 0xd3, 0x9a, 0x92, 0x01, 0xd2, 0x48, 0x3f, 0xbb,
+ 0x33, 0xb2, 0x83, 0x3f, 0xf0, 0x3e, 0x7c, 0xd1, 0xfb,
+ 0x1f, 0xda, 0x78, 0x13, 0xaf, 0x84, 0x87, 0x42, 0x02,
+ 0x95, 0xa8, 0xce, 0xd4, 0xc5, 0x8c, 0xd4, 0x82, 0xf3,
+ 0x8d, 0xf0, 0x44, 0xcc, 0x3f, 0x88, 0xfa, 0x02, 0x32,
+ 0x46, 0xd1, 0x0d, 0x22, 0x6c, 0x77, 0x33, 0x73, 0x68,
+ 0xbb, 0x41, 0x0c, 0x9e, 0x66, 0x80, 0x75, 0x6d, 0x22,
+ 0x47, 0x37, 0x06, 0xd2, 0xfd, 0xa1, 0xd1, 0x27, 0xcc,
+ 0x47, 0x0c, 0x24, 0xa7, 0xe7, 0xb6, 0xce, 0x5b, 0x4e,
+ 0x9c, 0xa6, 0x15, 0x96, 0xc3, 0xd1, 0x0a, 0xb0, 0x98,
+ 0x38, 0x0a, 0xd6, 0x13, 0xc9, 0xf8, 0x1a, 0x18, 0xcf,
+ 0xdf, 0x0c, 0x75, 0x78, 0xc1, 0x1c, 0x75, 0xb8, 0x86,
+ 0x00, 0xb4, 0xca, 0x38 ) );
+
+/* KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.fax test 0 */
+DHE_TEST ( kasvaliditytest_ffcephem_nokc_zzonly_resp_fc_0,
+ MODULUS ( 0xf5, 0x28, 0xaa, 0x27, 0x62, 0xdf, 0x76, 0xd7, 0x80,
+ 0x2f, 0xea, 0x08, 0x70, 0x05, 0xd7, 0x6f, 0xeb, 0x69,
+ 0xb7, 0xaf, 0xd9, 0xe7, 0xfb, 0x36, 0x37, 0x15, 0xa1,
+ 0xb4, 0x4f, 0x09, 0xdb, 0xda, 0x5d, 0x06, 0xa6, 0x3e,
+ 0x3d, 0x51, 0x2a, 0xbe, 0x9c, 0x68, 0x10, 0xab, 0xba,
+ 0x2b, 0xfd, 0x48, 0xcf, 0x55, 0x45, 0x13, 0x71, 0x2d,
+ 0xf2, 0x5f, 0x78, 0x62, 0x65, 0xa7, 0x5f, 0x4e, 0x1d,
+ 0xac, 0xaa, 0xcb, 0xbe, 0x9e, 0x52, 0x8a, 0x63, 0x46,
+ 0xa8, 0xbf, 0x38, 0x01, 0x5e, 0xcb, 0xc5, 0x23, 0xd4,
+ 0xe7, 0x8d, 0x73, 0x8b, 0x88, 0x52, 0xbc, 0xd6, 0x66,
+ 0x00, 0xdc, 0x43, 0x42, 0x86, 0xc7, 0x8f, 0x6c, 0xca,
+ 0xe9, 0x92, 0x56, 0x8b, 0x25, 0x8b, 0xb0, 0xd3, 0xb5,
+ 0x03, 0xe3, 0x7e, 0x7a, 0x95, 0x6e, 0xc1, 0x61, 0x69,
+ 0x78, 0xc1, 0xe7, 0x98, 0x92, 0x29, 0xe3, 0x99, 0x14,
+ 0xea, 0x7c, 0x1b, 0xea, 0x39, 0x02, 0xe6, 0x69, 0xdf,
+ 0xc6, 0x23, 0x68, 0xda, 0x13, 0x74, 0x48, 0x35, 0x0c,
+ 0x1d, 0xef, 0x54, 0xbf, 0x3e, 0xe2, 0x14, 0x2c, 0x06,
+ 0x56, 0x01, 0xdf, 0xae, 0x6b, 0xca, 0x07, 0xe9, 0x3c,
+ 0xc4, 0x63, 0x39, 0x3c, 0xbc, 0x48, 0x3b, 0x2c, 0x72,
+ 0x72, 0x55, 0x37, 0x88, 0x2e, 0xd5, 0xb9, 0x60, 0x74,
+ 0xf5, 0x19, 0xfc, 0x73, 0x8f, 0x50, 0x33, 0xb8, 0x7b,
+ 0x5e, 0xdc, 0xa0, 0xec, 0x4a, 0x34, 0xdc, 0x0f, 0x84,
+ 0xd2, 0xfa, 0x2c, 0x36, 0x5f, 0x69, 0x1a, 0x8f, 0xc7,
+ 0xdc, 0x64, 0xbc, 0x08, 0x39, 0xa5, 0x81, 0x3f, 0xef,
+ 0x9a, 0xf3, 0x85, 0xc6, 0x8e, 0x95, 0x2a, 0xf5, 0x66,
+ 0xf7, 0x9b, 0x08, 0x02, 0xbe, 0x99, 0x00, 0xcf, 0x08,
+ 0x38, 0x03, 0x2e, 0xd2, 0x49, 0xaf, 0xea, 0x05, 0x57,
+ 0x21, 0x54, 0x0c, 0x89, 0x61, 0xe6, 0x30, 0x0a, 0xd5,
+ 0xde, 0xc6, 0x51, 0xc7 ),
+ GENERATOR ( 0x08, 0x5c, 0x0a, 0x05, 0x12, 0xc2, 0x41, 0xb5, 0x83,
+ 0xd4, 0x17, 0x03, 0xed, 0xfb, 0xfe, 0xa2, 0xa3, 0xe8,
+ 0x63, 0xde, 0xac, 0x68, 0x85, 0x50, 0x97, 0x70, 0x79,
+ 0x67, 0xe0, 0x97, 0x18, 0x6e, 0xf8, 0x9d, 0x05, 0xc6,
+ 0x52, 0x27, 0xf5, 0x6b, 0x12, 0xde, 0x61, 0x23, 0xba,
+ 0xc8, 0x6c, 0x3c, 0x13, 0xd6, 0x80, 0x99, 0x4b, 0xff,
+ 0xaf, 0x24, 0xb2, 0xa1, 0xed, 0x7f, 0x01, 0xc1, 0x08,
+ 0xb0, 0x65, 0x93, 0xf2, 0x2f, 0x74, 0xb4, 0xaf, 0x22,
+ 0x2b, 0x46, 0xe5, 0xfb, 0x89, 0x48, 0x2f, 0xbd, 0x96,
+ 0xf5, 0x45, 0x1c, 0x9f, 0x45, 0x39, 0x31, 0x36, 0xec,
+ 0x03, 0x7a, 0xa8, 0x1a, 0x81, 0x24, 0x54, 0x59, 0xec,
+ 0x01, 0x80, 0x24, 0x51, 0x83, 0x94, 0xf4, 0xd9, 0x36,
+ 0x59, 0x6d, 0xc5, 0x3c, 0x3d, 0x8a, 0x9f, 0x73, 0x29,
+ 0x03, 0x71, 0x97, 0x96, 0xc0, 0x45, 0xb6, 0x2f, 0xad,
+ 0xea, 0x9d, 0xd1, 0xb2, 0xfa, 0xbe, 0xc1, 0x56, 0x0d,
+ 0xdb, 0x3b, 0x78, 0x0d, 0x96, 0x46, 0xad, 0x0d, 0xd3,
+ 0x16, 0x8c, 0x07, 0xcc, 0x99, 0x4f, 0x79, 0xee, 0x80,
+ 0x4c, 0xae, 0x07, 0x57, 0x39, 0x12, 0x51, 0x1d, 0xe0,
+ 0x50, 0xd0, 0x5a, 0x0d, 0x58, 0xb8, 0x19, 0xec, 0x41,
+ 0xe7, 0xc1, 0x20, 0x5d, 0xc7, 0x19, 0x9f, 0xc6, 0x5a,
+ 0x6a, 0x1a, 0x4f, 0xfc, 0xb4, 0xdf, 0x38, 0xd9, 0xb6,
+ 0x75, 0x72, 0x69, 0x00, 0x34, 0x01, 0xd8, 0x4c, 0x73,
+ 0x23, 0x85, 0xa5, 0x51, 0x74, 0xf2, 0x7d, 0x4b, 0x49,
+ 0x3c, 0xb7, 0x10, 0x98, 0x0c, 0x3a, 0xf9, 0x8b, 0xe7,
+ 0xbc, 0xff, 0x94, 0x67, 0xe8, 0x17, 0x92, 0xf2, 0xd2,
+ 0xf9, 0xa2, 0xf8, 0xd5, 0xd0, 0xdd, 0xc9, 0xa2, 0x29,
+ 0x79, 0x01, 0x92, 0xa1, 0x94, 0xda, 0x5b, 0x20, 0x32,
+ 0xf2, 0xf0, 0xcc, 0x23, 0xff, 0xbc, 0xb2, 0xcc, 0x16,
+ 0x6f, 0x21, 0x28, 0xee ),
+ PARTNER ( 0x81, 0x5e, 0x1c, 0x8e, 0x64, 0xbe, 0x67, 0x86, 0xb6,
+ 0xc2, 0x19, 0x45, 0x06, 0xb6, 0x61, 0x19, 0x9a, 0x56,
+ 0xc8, 0x07, 0xc6, 0x34, 0x0a, 0x83, 0x69, 0x7d, 0x3b,
+ 0xc7, 0x53, 0x04, 0xfb, 0xeb, 0x91, 0xbb, 0x15, 0xac,
+ 0x79, 0x81, 0xba, 0xbb, 0xa2, 0x60, 0xa6, 0x53, 0xe6,
+ 0x66, 0xb0, 0xda, 0x80, 0x12, 0x04, 0x2a, 0x08, 0x85,
+ 0x47, 0xf0, 0xfb, 0xd1, 0xef, 0x56, 0xd1, 0xd1, 0xf6,
+ 0x5e, 0xd8, 0x09, 0xca, 0x85, 0x45, 0x13, 0x9f, 0x57,
+ 0xd3, 0xeb, 0xda, 0x3e, 0x0f, 0x13, 0xe7, 0xef, 0x19,
+ 0xbd, 0xed, 0x4a, 0x8d, 0xfa, 0x20, 0x4f, 0x24, 0x57,
+ 0xa3, 0xd3, 0x92, 0x83, 0x9d, 0xd7, 0x0b, 0xec, 0x53,
+ 0x8a, 0x29, 0xd7, 0x88, 0x74, 0x70, 0x9f, 0x90, 0x5e,
+ 0xc2, 0x87, 0x40, 0xbe, 0x15, 0x76, 0x96, 0xaa, 0x86,
+ 0x2b, 0x57, 0xab, 0x51, 0xef, 0x20, 0x03, 0x36, 0x01,
+ 0xff, 0x83, 0xba, 0x3f, 0xb0, 0xe8, 0x02, 0x55, 0x67,
+ 0x4e, 0x0e, 0x6e, 0x72, 0x69, 0xcd, 0x85, 0xca, 0x10,
+ 0x37, 0x9d, 0x41, 0x8b, 0x73, 0x7d, 0x3c, 0xde, 0xb5,
+ 0xf3, 0x1f, 0xb0, 0x6f, 0x4a, 0x14, 0x11, 0x45, 0x93,
+ 0x6a, 0x9e, 0xec, 0x05, 0x51, 0xb4, 0xba, 0x59, 0xc5,
+ 0x9d, 0x2b, 0x3e, 0xdd, 0xc1, 0x9e, 0xa1, 0x89, 0x78,
+ 0x27, 0x9c, 0xf1, 0x1f, 0x21, 0xa6, 0x5a, 0x9d, 0x2a,
+ 0x10, 0x4c, 0xfe, 0x6a, 0xf9, 0x3f, 0xa8, 0xa1, 0xcc,
+ 0xd1, 0x8b, 0x03, 0x01, 0x7a, 0x8a, 0xb3, 0x19, 0x43,
+ 0x99, 0x31, 0x92, 0xf7, 0x94, 0xd8, 0x7b, 0xbc, 0x27,
+ 0x3e, 0xf9, 0x16, 0x0a, 0xf9, 0x54, 0x48, 0x07, 0x83,
+ 0xcf, 0xb6, 0xa3, 0x7b, 0xa0, 0x85, 0x50, 0x3b, 0xa2,
+ 0x58, 0x16, 0x9a, 0x8d, 0xab, 0xa7, 0x1d, 0x4c, 0x52,
+ 0xde, 0x7c, 0x4e, 0x65, 0x47, 0x22, 0x23, 0xc2, 0x02,
+ 0xad, 0x27, 0x7e, 0x93 ),
+ PRIVATE ( 0x56, 0x1c, 0x94, 0x8b, 0xe9, 0xd0, 0xd9, 0x68, 0xcd,
+ 0xfc, 0x6d, 0x27, 0xcb, 0xfe, 0x52, 0xcd, 0xa3, 0x42,
+ 0xf5, 0x44, 0xf5, 0x6d, 0x57, 0xf1, 0x18, 0x86, 0x63,
+ 0x26, 0xf7, 0x6e, 0x1f, 0x70 ),
+ PUBLIC ( 0x3c, 0x24, 0x97, 0x3b, 0x32, 0x96, 0x26, 0x97, 0x59,
+ 0xce, 0x38, 0xe2, 0xe5, 0x25, 0xc0, 0x09, 0x5d, 0x4b,
+ 0x5c, 0x34, 0xbe, 0x5d, 0x13, 0xb4, 0x5b, 0x22, 0x2b,
+ 0x8e, 0x48, 0x9c, 0x27, 0xfb, 0x44, 0x42, 0xf3, 0x2c,
+ 0xc7, 0x64, 0x66, 0x5e, 0x28, 0xa0, 0x66, 0x55, 0xc7,
+ 0x1f, 0xb3, 0x7f, 0xd8, 0x75, 0xa9, 0x21, 0xd1, 0x79,
+ 0x55, 0x1a, 0x1e, 0x4f, 0x2a, 0x90, 0x54, 0xa7, 0x6c,
+ 0xae, 0x2a, 0x61, 0xd3, 0xcb, 0xec, 0x55, 0xc3, 0xbe,
+ 0x19, 0x85, 0x3a, 0x54, 0x09, 0xd9, 0xff, 0x91, 0x4b,
+ 0x93, 0xbc, 0x78, 0xb8, 0xaa, 0x15, 0x25, 0xb9, 0x08,
+ 0xf3, 0x24, 0x19, 0xa8, 0x8d, 0x77, 0x26, 0xea, 0xd7,
+ 0x6a, 0x3f, 0x88, 0x95, 0xd6, 0x30, 0x71, 0xa9, 0xb0,
+ 0xa6, 0x3f, 0xe4, 0x72, 0x8d, 0x19, 0x51, 0x8d, 0x1d,
+ 0x08, 0x08, 0x81, 0x41, 0xb8, 0x26, 0x9f, 0x0b, 0x0c,
+ 0xd7, 0x71, 0x12, 0xd4, 0x76, 0xaf, 0x9e, 0xfc, 0xc7,
+ 0xf5, 0x90, 0xaf, 0x8f, 0xc1, 0xf9, 0xdc, 0x5e, 0x4c,
+ 0x00, 0xcd, 0x5d, 0xfa, 0x64, 0xa3, 0x3b, 0x2d, 0xf4,
+ 0xdb, 0x9d, 0x85, 0x94, 0xd8, 0x74, 0x89, 0xbe, 0xa6,
+ 0xf6, 0xf3, 0x79, 0x58, 0xbf, 0xb5, 0x98, 0xe5, 0x69,
+ 0x2b, 0x81, 0xbf, 0x11, 0x6b, 0x60, 0x22, 0x7b, 0x62,
+ 0x52, 0xa6, 0x43, 0x8f, 0x04, 0x9c, 0x5c, 0x44, 0x9b,
+ 0xab, 0x02, 0x77, 0x40, 0xf8, 0x55, 0x1b, 0xf1, 0xff,
+ 0xe2, 0x50, 0x84, 0xf2, 0x31, 0xff, 0x64, 0x63, 0x88,
+ 0xd0, 0x09, 0xba, 0x22, 0x19, 0x32, 0x62, 0x02, 0x9b,
+ 0xa1, 0x9a, 0xf2, 0x64, 0x3d, 0xd6, 0x79, 0xf2, 0x83,
+ 0x21, 0x2a, 0x2d, 0x26, 0xad, 0x91, 0x7e, 0xfe, 0x96,
+ 0x42, 0xc7, 0x48, 0xfc, 0xeb, 0x33, 0xfb, 0x0a, 0x6c,
+ 0x13, 0x2f, 0x37, 0x8d, 0xad, 0xa2, 0xcc, 0xce, 0xde,
+ 0x08, 0x6d, 0x8a, 0x31 ),
+ SHARED ( 0xec, 0x23, 0x09, 0xa7, 0xd2, 0x38, 0xae, 0xb0, 0x67,
+ 0x14, 0xc2, 0x7c, 0x1b, 0xbb, 0xb1, 0xb1, 0xc5, 0xaa,
+ 0x3c, 0xdd, 0xdd, 0x76, 0xa4, 0x19, 0xb1, 0xf3, 0x70,
+ 0x4d, 0xd3, 0x43, 0x7c, 0xd1, 0xf2, 0xc8, 0x84, 0x3f,
+ 0x35, 0x0d, 0x67, 0x87, 0x2e, 0xe3, 0x25, 0x97, 0x3f,
+ 0x4e, 0x5a, 0xce, 0x7d, 0x40, 0x6b, 0xe5, 0xde, 0x75,
+ 0xd9, 0xa9, 0x12, 0x0a, 0xf6, 0x7e, 0x32, 0xf0, 0x29,
+ 0x1e, 0x77, 0xe7, 0xa3, 0x97, 0x62, 0x49, 0x29, 0xd6,
+ 0x3d, 0xc0, 0xc4, 0x2e, 0xf8, 0xf4, 0x42, 0xce, 0x89,
+ 0xa3, 0x9b, 0x19, 0x2f, 0xee, 0x38, 0x6c, 0xe6, 0x83,
+ 0x01, 0xc4, 0xb8, 0x28, 0xea, 0x91, 0x89, 0x79, 0x83,
+ 0x46, 0xb6, 0x0f, 0x61, 0x5d, 0xd9, 0x63, 0x91, 0x05,
+ 0xff, 0xea, 0x6e, 0xc6, 0x1e, 0xe5, 0xe4, 0xa7, 0xd6,
+ 0x8c, 0xe7, 0x2b, 0xbf, 0x12, 0x81, 0xd6, 0x86, 0x4e,
+ 0x30, 0x18, 0x1c, 0xe4, 0x19, 0x95, 0x2a, 0x3e, 0xf8,
+ 0x3a, 0x9a, 0xd7, 0xb2, 0x6f, 0xc7, 0x29, 0x2a, 0xd7,
+ 0x45, 0xbf, 0xb5, 0x43, 0xe5, 0xc2, 0xea, 0x31, 0x0a,
+ 0x41, 0x59, 0xe9, 0xd6, 0x60, 0x27, 0x9d, 0x12, 0xc1,
+ 0xe0, 0x38, 0x50, 0xe8, 0x37, 0xc0, 0x1c, 0x54, 0x2a,
+ 0x0f, 0x59, 0xad, 0x61, 0xd0, 0x73, 0x10, 0x05, 0xe8,
+ 0x00, 0x9a, 0x3d, 0x84, 0x06, 0x69, 0x1a, 0xbb, 0x22,
+ 0xf5, 0xf2, 0xe9, 0x6a, 0xe3, 0x45, 0x78, 0x3c, 0x40,
+ 0x3e, 0x59, 0xb9, 0xe9, 0x48, 0xad, 0xdb, 0xea, 0x8a,
+ 0xc7, 0xd7, 0x70, 0x82, 0x10, 0x44, 0xe0, 0x3f, 0x15,
+ 0xae, 0x6f, 0xc3, 0x67, 0xdd, 0xc8, 0x5b, 0xa6, 0x2a,
+ 0x26, 0xb4, 0xd9, 0x4d, 0x77, 0x05, 0xf5, 0xec, 0xad,
+ 0x8a, 0xa2, 0x1b, 0x61, 0x9d, 0x0e, 0x09, 0xf1, 0x24,
+ 0xbe, 0xe8, 0x65, 0x8a, 0x21, 0x87, 0xf7, 0x02, 0x91,
+ 0x07, 0x10, 0x5d, 0xbf ) );
+
+/**
+ * Perform Ephemeral Diffie-Hellman self-tests
+ *
+ */
+static void dhe_test_exec ( void ) {
+
+ dhe_key_ok ( &kasvaliditytest_ffcephem_nokc_zzonly_init_fb_0 );
+ dhe_key_ok ( &kasvaliditytest_ffcephem_nokc_zzonly_init_fc_0 );
+ dhe_key_ok ( &kasvaliditytest_ffcephem_nokc_zzonly_resp_fb_0 );
+ dhe_key_ok ( &kasvaliditytest_ffcephem_nokc_zzonly_resp_fc_0 );
+}
+
+/** Ephemeral Diffie-Hellman self-test */
+struct self_test dhe_test __self_test = {
+ .name = "dhe",
+ .exec = dhe_test_exec,
+};
diff --git a/src/tests/hmac_test.c b/src/tests/hmac_test.c
new file mode 100644
index 000000000..5267999e4
--- /dev/null
+++ b/src/tests/hmac_test.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * HMAC self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <string.h>
+#include <ipxe/hmac.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/test.h>
+
+/** Define inline key data */
+#define KEY(...) { __VA_ARGS__ }
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define inline expected HMAC */
+#define EXPECTED(...) { __VA_ARGS__ }
+
+/** An HMAC test */
+struct hmac_test {
+ /** Digest algorithm */
+ struct digest_algorithm *digest;
+ /** Key */
+ const void *key;
+ /** Length of key */
+ size_t key_len;
+ /** Data */
+ const void *data;
+ /** Length of data */
+ size_t data_len;
+ /** Expected HMAC */
+ const void *expected;
+ /** Length of expected HMAC */
+ size_t expected_len;
+};
+
+/**
+ * Define an HMAC test
+ *
+ * @v name Test name
+ * @v DIGEST Digest algorithm
+ * @v KEY Key
+ * @v DATA Data
+ * @v EXPECTED Expected HMAC
+ * @ret test HMAC test
+ */
+#define HMAC_TEST( name, DIGEST, KEY, DATA, EXPECTED ) \
+ static const uint8_t name ## _key[] = KEY; \
+ static const uint8_t name ## _data[] = DATA; \
+ static const uint8_t name ## _expected[] = EXPECTED; \
+ static struct hmac_test name = { \
+ .digest = DIGEST, \
+ .key = name ## _key, \
+ .key_len = sizeof ( name ## _key ), \
+ .data = name ## _data, \
+ .data_len = sizeof ( name ## _data ), \
+ .expected = name ## _expected, \
+ .expected_len = sizeof ( name ## _expected ), \
+ }
+
+/**
+ * Report an HMAC test result
+ *
+ * @v test HMAC test
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void hmac_okx ( struct hmac_test *test, const char *file,
+ unsigned int line ) {
+ struct digest_algorithm *digest = test->digest;
+ uint8_t ctx[ hmac_ctxsize ( digest ) ];
+ uint8_t hmac[digest->digestsize];
+
+ /* Sanity checks */
+ okx ( sizeof ( ctx ) == ( digest->ctxsize + digest->blocksize ),
+ file, line );
+ okx ( test->expected_len == digest->digestsize, file, line );
+
+ /* Calculate HMAC */
+ DBGC ( test, "HMAC-%s key:\n", digest->name );
+ DBGC_HDA ( test, 0, test->key, test->key_len );
+ DBGC ( test, "HMAC-%s data:\n", digest->name );
+ DBGC_HDA ( test, 0, test->data, test->data_len );
+ hmac_init ( digest, ctx, test->key, test->key_len );
+ hmac_update ( digest, ctx, test->data, test->data_len );
+ hmac_final ( digest, ctx, hmac );
+ DBGC ( test, "HMAC-%s result:\n", digest->name );
+ DBGC_HDA ( test, 0, hmac, sizeof ( hmac ) );
+
+ /* Compare against expected result */
+ okx ( memcmp ( hmac, test->expected, test->expected_len ) == 0,
+ file, line );
+}
+#define hmac_ok( test ) hmac_okx ( test, __FILE__, __LINE__ )
+
+/* Empty key and data */
+HMAC_TEST ( hmac_empty, &sha256_algorithm, KEY(), DATA(),
+ EXPECTED ( 0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec, 0x77,
+ 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5, 0xff, 0x16,
+ 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53, 0xc6, 0xc7, 0x12,
+ 0x14, 0x42, 0x92, 0xc5, 0xad ) );
+
+/* "Hello world" */
+HMAC_TEST ( hmac_hw, &sha256_algorithm,
+ KEY ( 'H', 'e', 'l', 'l', 'o' ),
+ DATA ( 'W', 'o', 'r', 'l', 'd' ),
+ EXPECTED ( 0x59, 0x16, 0x8e, 0x30, 0x9f, 0x2c, 0x97, 0xdd, 0x04,
+ 0xe4, 0x5b, 0xe3, 0xe7, 0x9b, 0xd9, 0xac, 0xb6, 0xd2,
+ 0x2f, 0xda, 0x65, 0x46, 0xc0, 0x0c, 0x53, 0x92, 0x82,
+ 0xc4, 0x1e, 0xeb, 0x91, 0x6e ) );
+
+/* "Hello world" using SHA-1 */
+HMAC_TEST ( hmac_hw_sha1, &sha1_algorithm,
+ KEY ( 'H', 'e', 'l', 'l', 'o' ),
+ DATA ( 'W', 'o', 'r', 'l', 'd' ),
+ EXPECTED ( 0x9e, 0x29, 0xcf, 0x6d, 0x48, 0x90, 0x49, 0x9e, 0xf8,
+ 0x5a, 0x31, 0x47, 0x55, 0x7b, 0x1a, 0x45, 0xd5, 0xae,
+ 0xd1, 0x77 ) );
+
+/* "Hello world" using MD5 */
+HMAC_TEST ( hmac_hw_md5, &md5_algorithm,
+ KEY ( 'H', 'e', 'l', 'l', 'o' ),
+ DATA ( 'W', 'o', 'r', 'l', 'd' ),
+ EXPECTED ( 0xc7, 0x1c, 0x0c, 0xd0, 0xdc, 0x24, 0x49, 0xbd, 0xd8,
+ 0x9d, 0x28, 0xeb, 0x03, 0xbe, 0xf2, 0x04 ) );
+
+/* Block-length key */
+HMAC_TEST ( hmac_maxlen, &sha256_algorithm,
+ KEY ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f ),
+ DATA ( 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' ),
+ EXPECTED ( 0xdd, 0x05, 0xcc, 0xe6, 0xd6, 0xaf, 0x91, 0x61, 0x4b,
+ 0xaf, 0x35, 0x6b, 0x86, 0x0a, 0x05, 0x67, 0x25, 0x22,
+ 0xf0, 0x54, 0xd2, 0x5f, 0xd7, 0xe1, 0x54, 0x26, 0x01,
+ 0x16, 0xfd, 0x8a, 0xf3, 0x5b ) );
+
+/* Over-length key */
+HMAC_TEST ( hmac_overlen, &sha256_algorithm,
+ KEY ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40 ),
+ DATA ( 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' ),
+ EXPECTED ( 0x4f, 0x0f, 0x42, 0x07, 0xda, 0x84, 0x3d, 0x2a, 0x34,
+ 0xae, 0x5d, 0xd9, 0x05, 0x1e, 0x96, 0xa8, 0xb6, 0xef,
+ 0xa1, 0xcd, 0x49, 0x5b, 0xea, 0x30, 0xbf, 0x47, 0x3b,
+ 0xdc, 0xa9, 0x86, 0xbb, 0x31 ) );
+
+/**
+ * Perform HMAC self-tests
+ *
+ */
+static void hmac_test_exec ( void ) {
+
+ hmac_ok ( &hmac_empty );
+ hmac_ok ( &hmac_hw );
+ hmac_ok ( &hmac_hw_sha1 );
+ hmac_ok ( &hmac_hw_md5 );
+ hmac_ok ( &hmac_maxlen );
+ hmac_ok ( &hmac_overlen );
+}
+
+/** HMAC self-tests */
+struct self_test hmac_test __self_test = {
+ .name = "hmac",
+ .exec = hmac_test_exec,
+};
diff --git a/src/tests/ipv6_test.c b/src/tests/ipv6_test.c
index 9b3a744df..de8edc8ad 100644
--- a/src/tests/ipv6_test.c
+++ b/src/tests/ipv6_test.c
@@ -41,12 +41,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Define inline IPv6 address */
#define IPV6(...) { __VA_ARGS__ }
+/** An IPv6 test prefix */
+struct ipv6_test_prefix {
+ /** Prefix length */
+ unsigned int len;
+ /** Prefix mask */
+ const char *mask;
+};
+
/** An IPv6 test routing table entry */
struct ipv6_test_route {
/** Local address */
const char *address;
- /** Prefix length */
- unsigned int prefix_len;
+ /** Prefix */
+ const struct ipv6_test_prefix *prefix;
/** Router address (if any) */
const char *router;
};
@@ -61,6 +69,13 @@ struct ipv6_test_table {
struct list_head list;
};
+/** Define a test prefix */
+#define PREFIX( name, LEN, MASK ) \
+ static const struct ipv6_test_prefix name = { \
+ .len = LEN, \
+ .mask = MASK, \
+ };
+
/** Define a test routing table */
#define TABLE( name, ... ) \
static const struct ipv6_test_route name ## _routes[] = { \
@@ -116,23 +131,45 @@ static struct net_device ipv6_test_netdev = {
.state = NETDEV_OPEN,
};
+/** /48 prefix */
+PREFIX ( prefix48, 48, "ffff:ffff:ffff::" );
+
+/** /64 prefix */
+PREFIX ( prefix64, 64, "ffff:ffff:ffff:ffff::" );
+
+/** /126 prefix */
+PREFIX ( prefix126, 126, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc" );
+
+/** /127 prefix */
+PREFIX ( prefix127, 127, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" );
+
+/** /128 prefix */
+PREFIX ( prefix128, 128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" );
+
/** Routing table with only a link-local address */
TABLE ( table_link_local,
- { "fe80::69ff:fe50:5845", 64, NULL } );
+ { "fe80::69ff:fe50:5845", &prefix64, NULL } );
/** Routing table with a global address */
TABLE ( table_normal,
- { "fe80::69ff:fe50:5845", 64, NULL },
- { "2001:db8:3::1", 64, "fe80::1" } );
+ { "fe80::69ff:fe50:5845", &prefix64, NULL },
+ { "2001:db8:3::1", &prefix64, "fe80::1" } );
/** Routing table with multiple addresses and routers */
TABLE ( table_multi,
- { "fe80::69ff:fe50:5845", 64, NULL },
- { "2001:db8:3::1", 64, "fe80::1" },
- { "2001:db8:5::1", 64, NULL },
- { "2001:db8:42::1", 64, "fe80::2" },
- { "fd44:9112:6442::69ff:fe50:5845", 64, "fe80::1" },
- { "fd70:6ba9:50ae::69ff:fe50:5845", 64, "fe80::3" } );
+ { "fe80::69ff:fe50:5845", &prefix64, NULL },
+ { "2001:db8:3::1", &prefix64, "fe80::1" },
+ { "2001:db8:5::1", &prefix64, NULL },
+ { "2001:db8:42::1", &prefix64, "fe80::2" },
+ { "fd44:9112:6442::69ff:fe50:5845", &prefix64, "fe80::1" },
+ { "fd70:6ba9:50ae::69ff:fe50:5845", &prefix64, "fe80::3" } );
+
+/** Routing table with unusual prefix lengths */
+TABLE ( table_unusual,
+ { "2001:db8:1::1", &prefix48, "fe80::1" },
+ { "2001:db8:2::1", &prefix126, NULL },
+ { "2001:db8:3::1", &prefix127, NULL },
+ { "2001:db8:4::1", &prefix128, NULL } );
/**
* Report an inet6_ntoa() test result
@@ -212,8 +249,10 @@ static void inet6_aton_fail_okx ( const char *text, const char *file,
static void ipv6_table_okx ( struct ipv6_test_table *table, const char *file,
unsigned int line ) {
const struct ipv6_test_route *route;
+ struct ipv6_miniroute *miniroute;
struct in6_addr address;
struct in6_addr router;
+ struct in6_addr mask;
struct list_head saved;
unsigned int i;
@@ -235,13 +274,33 @@ static void ipv6_table_okx ( struct ipv6_test_table *table, const char *file,
okx ( inet6_aton ( route->router, &router ) == 0,
file, line );
}
+ okx ( inet6_aton ( route->prefix->mask, &mask ) == 0,
+ file, line );
/* Add routing table entry */
okx ( ipv6_add_miniroute ( &ipv6_test_netdev, &address,
- route->prefix_len,
+ route->prefix->len,
( route->router ?
&router : NULL ) ) == 0,
file, line );
+
+ /* Check routing table entry */
+ miniroute = list_first_entry ( &ipv6_miniroutes,
+ struct ipv6_miniroute, list );
+ okx ( miniroute != NULL, file, line );
+ okx ( memcmp ( &miniroute->address, &address,
+ sizeof ( address ) ) == 0, file, line );
+ okx ( miniroute->prefix_len == route->prefix->len,
+ file, line );
+ okx ( memcmp ( &miniroute->prefix_mask, &mask,
+ sizeof ( mask ) ) == 0, file, line );
+ if ( route->router ) {
+ okx ( memcmp ( &miniroute->router, &router,
+ sizeof ( router ) ) == 0, file, line );
+ } else {
+ okx ( IN6_IS_ADDR_UNSPECIFIED ( &miniroute->router ),
+ file, line );
+ }
}
/* Save constructed routing table */
@@ -462,6 +521,7 @@ static void ipv6_test_exec ( void ) {
ipv6_table_ok ( &table_link_local );
ipv6_table_ok ( &table_normal );
ipv6_table_ok ( &table_multi );
+ ipv6_table_ok ( &table_unusual );
/* Routing table with only a link-local address */
ipv6_route_ok ( &table_link_local, "fe80::1",
@@ -505,10 +565,27 @@ static void ipv6_test_exec ( void ) {
ipv6_route_ok ( &table_multi, "ff02::1",
"fe80::69ff:fe50:5845", NULL );
+ /* Routing table with unusual prefix lengths */
+ ipv6_route_ok ( &table_unusual, "2001:db8:2::1",
+ "2001:db8:2::1", NULL );
+ ipv6_route_ok ( &table_unusual, "2001:db8:2::3",
+ "2001:db8:2::1", NULL );
+ ipv6_route_ok ( &table_unusual, "2001:db8:3::1",
+ "2001:db8:3::1", NULL );
+ ipv6_route_ok ( &table_unusual, "2001:db8:3::2",
+ "2001:db8:1::1", "fe80::1" );
+ ipv6_route_ok ( &table_unusual, "2001:db8:4::1",
+ "2001:db8:4::1", NULL );
+ ipv6_route_ok ( &table_unusual, "2001:db8:4::0",
+ "2001:db8:1::1", "fe80::1" );
+ ipv6_route_ok ( &table_unusual, "2001:db8:4::2",
+ "2001:db8:1::1", "fe80::1" );
+
/* Destroy test routing tables */
ipv6_table_del ( &table_link_local );
ipv6_table_del ( &table_normal );
ipv6_table_del ( &table_multi );
+ ipv6_table_del ( &table_unusual );
}
/** IPv6 self-test */
diff --git a/src/tests/pccrc_test.c b/src/tests/pccrc_test.c
index f4ab573ac..e69493202 100644
--- a/src/tests/pccrc_test.c
+++ b/src/tests/pccrc_test.c
@@ -467,11 +467,10 @@ peerdist_info_passphrase_okx ( struct peerdist_info_segment_test *test,
uint8_t *pass, size_t pass_len,
const char *file, unsigned int line ) {
struct digest_algorithm *digest = info->digest;
- uint8_t ctx[digest->ctxsize];
+ uint8_t ctx[ hmac_ctxsize ( digest ) ];
uint8_t secret[digest->digestsize];
uint8_t expected[digest->digestsize];
size_t digestsize = info->digestsize;
- size_t secretsize = digestsize;
/* Calculate server secret */
digest_init ( digest, ctx );
@@ -479,11 +478,9 @@ peerdist_info_passphrase_okx ( struct peerdist_info_segment_test *test,
digest_final ( digest, ctx, secret );
/* Calculate expected segment secret */
- hmac_init ( digest, ctx, secret, &secretsize );
- assert ( secretsize == digestsize );
+ hmac_init ( digest, ctx, secret, digestsize );
hmac_update ( digest, ctx, test->expected_hash, digestsize );
- hmac_final ( digest, ctx, secret, &secretsize, expected );
- assert ( secretsize == digestsize );
+ hmac_final ( digest, ctx, expected );
/* Verify segment secret */
okx ( memcmp ( test->expected_secret, expected, digestsize ) == 0,
diff --git a/src/tests/tests.c b/src/tests/tests.c
index 5dbbac1b1..54694fa45 100644
--- a/src/tests/tests.c
+++ b/src/tests/tests.c
@@ -77,3 +77,5 @@ REQUIRE_OBJECT ( zlib_test );
REQUIRE_OBJECT ( gzip_test );
REQUIRE_OBJECT ( utf8_test );
REQUIRE_OBJECT ( acpi_test );
+REQUIRE_OBJECT ( hmac_test );
+REQUIRE_OBJECT ( dhe_test );