aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/drivers/net/ice.c986
-rw-r--r--src/drivers/net/ice.h565
-rw-r--r--src/drivers/net/intelxl.c14
-rw-r--r--src/drivers/net/intelxl.h10
-rw-r--r--src/include/ipxe/errfile.h1
5 files changed, 1569 insertions, 7 deletions
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 c8c527d53..82b07833c 100644
--- a/src/drivers/net/intelxl.c
+++ b/src/drivers/net/intelxl.c
@@ -123,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,
@@ -575,7 +575,7 @@ static int intelxl_admin_mac_write ( struct net_device *netdev ) {
* @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;
int rc;
@@ -726,7 +726,7 @@ static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
* @v intelxl Intel device
* @ret rc Return status code
*/
-static int intelxl_admin_mac_config ( struct intelxl_nic *intelxl ) {
+int intelxl_admin_mac_config ( struct intelxl_nic *intelxl ) {
struct intelxl_admin_descriptor *cmd;
struct intelxl_admin_mac_config_params *config;
int rc;
@@ -1280,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;
@@ -1314,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 */
diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h
index ad15ca99f..0db16b581 100644
--- a/src/drivers/net/intelxl.h
+++ b/src/drivers/net/intelxl.h
@@ -925,6 +925,8 @@ struct intelxl_nic {
unsigned int vsi;
/** Queue set handle */
unsigned int qset;
+ /** Transmit element ID */
+ uint32_t teid;
/** Interrupt control register */
unsigned int intr;
/** PCI Express capability offset */
@@ -959,6 +961,8 @@ struct intelxl_nic {
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,
unsigned int vector );
@@ -970,6 +974,8 @@ 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 );
@@ -978,6 +984,10 @@ 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 );
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index 81f555725..359e4d2ce 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.h
@@ -215,6 +215,7 @@ 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_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )