diff --git a/src/drivers/net/ice.c b/src/drivers/net/ice.c new file mode 100644 index 00000000000..b5d66f1bbd8 --- /dev/null +++ b/src/drivers/net/ice.c @@ -0,0 +1,986 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 00000000000..26291a7a13b --- /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 +#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 c8c527d53ad..82b07833c81 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 ad15ca99f46..0db16b58129 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 81f555725d6..359e4d2cef6 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 )