123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- /*
- * Copyright (C) 2019 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 <string.h>
- #include <unistd.h>
- #include <errno.h>
- #include <byteswap.h>
- #include <ipxe/pci.h>
- #include <ipxe/netdevice.h>
- #include <ipxe/ethernet.h>
- #include "intelxlvf.h"
-
- /** @file
- *
- * Intel 40 Gigabit Ethernet virtual function network card driver
- *
- */
-
- /******************************************************************************
- *
- * Device reset
- *
- ******************************************************************************
- */
-
- /**
- * Reset hardware via PCIe function-level reset
- *
- * @v intelxl Intel device
- */
- static void intelxlvf_reset_flr ( struct intelxl_nic *intelxl,
- struct pci_device *pci ) {
- uint16_t control;
-
- /* Perform a PCIe function-level reset */
- pci_read_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
- &control );
- pci_write_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
- ( control | PCI_EXP_DEVCTL_FLR ) );
- mdelay ( INTELXL_RESET_DELAY_MS );
- }
-
- /**
- * Wait for admin event queue to be torn down
- *
- * @v intelxl Intel device
- * @ret rc Return status code
- */
- static int intelxlvf_reset_wait_teardown ( struct intelxl_nic *intelxl ) {
- uint32_t admin_evt_len;
- unsigned int i;
-
- /* Wait for admin event queue to be torn down */
- for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
-
- /* Check admin event queue length register */
- admin_evt_len = readl ( intelxl->regs + INTELXLVF_ADMIN +
- INTELXLVF_ADMIN_EVT_LEN );
- if ( ! ( admin_evt_len & INTELXL_ADMIN_LEN_ENABLE ) )
- return 0;
-
- /* Delay */
- mdelay ( 1 );
- }
-
- DBGC ( intelxl, "INTELXL %p timed out waiting for teardown (%#08x)\n",
- intelxl, admin_evt_len );
- return -ETIMEDOUT;
- }
-
- /**
- * Wait for virtual function to be marked as active
- *
- * @v intelxl Intel device
- * @ret rc Return status code
- */
- static int intelxlvf_reset_wait_active ( struct intelxl_nic *intelxl ) {
- uint32_t vfgen_rstat;
- unsigned int vfr_state;
- unsigned int i;
-
- /* Wait for virtual function to be marked as active */
- for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
-
- /* Check status as written by physical function driver */
- vfgen_rstat = readl ( intelxl->regs + INTELXLVF_VFGEN_RSTAT );
- vfr_state = INTELXLVF_VFGEN_RSTAT_VFR_STATE ( vfgen_rstat );
- if ( vfr_state == INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE )
- return 0;
-
- /* Delay */
- mdelay ( 1 );
- }
-
- DBGC ( intelxl, "INTELXL %p timed out waiting for activation "
- "(%#08x)\n", intelxl, vfgen_rstat );
- return -ETIMEDOUT;
- }
-
- /**
- * Reset hardware via admin queue
- *
- * @v intelxl Intel device
- * @ret rc Return status code
- */
- static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
- struct intelxl_admin_descriptor *cmd;
- int rc;
-
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_RESET );
-
- /* Issue command */
- if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
- goto err_command;
-
- /* Wait for minimum reset time */
- mdelay ( INTELXL_RESET_DELAY_MS );
-
- /* Wait for reset to take effect */
- if ( ( rc = intelxlvf_reset_wait_teardown ( intelxl ) ) != 0 )
- goto err_teardown;
-
- /* Wait for virtual function to become active */
- if ( ( rc = intelxlvf_reset_wait_active ( intelxl ) ) != 0 )
- goto err_active;
-
- err_active:
- err_teardown:
- intelxl_reopen_admin ( intelxl );
- err_command:
- return rc;
- }
-
- /******************************************************************************
- *
- * Admin queue
- *
- ******************************************************************************
- */
-
- /** Admin command queue register offsets */
- static const struct intelxl_admin_offsets intelxlvf_admin_command_offsets = {
- .bal = INTELXLVF_ADMIN_CMD_BAL,
- .bah = INTELXLVF_ADMIN_CMD_BAH,
- .len = INTELXLVF_ADMIN_CMD_LEN,
- .head = INTELXLVF_ADMIN_CMD_HEAD,
- .tail = INTELXLVF_ADMIN_CMD_TAIL,
- };
-
- /** Admin event queue register offsets */
- static const struct intelxl_admin_offsets intelxlvf_admin_event_offsets = {
- .bal = INTELXLVF_ADMIN_EVT_BAL,
- .bah = INTELXLVF_ADMIN_EVT_BAH,
- .len = INTELXLVF_ADMIN_EVT_LEN,
- .head = INTELXLVF_ADMIN_EVT_HEAD,
- .tail = INTELXLVF_ADMIN_EVT_TAIL,
- };
-
- /**
- * Issue admin queue virtual function command
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
- static int intelxlvf_admin_command ( struct net_device *netdev ) {
- struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin *admin = &intelxl->command;
- struct intelxl_admin_descriptor *cmd;
- unsigned int i;
- int rc;
-
- /* Populate descriptor */
- cmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
- cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
-
- /* Record opcode */
- intelxl->vopcode = le32_to_cpu ( cmd->vopcode );
-
- /* Issue command */
- if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
- goto err_command;
-
- /* Wait for response */
- for ( i = 0 ; i < INTELXLVF_ADMIN_MAX_WAIT_MS ; i++ ) {
-
- /* Poll admin event queue */
- intelxl_poll_admin ( netdev );
-
- /* If response has not arrived, delay 1ms and retry */
- if ( intelxl->vopcode ) {
- mdelay ( 1 );
- continue;
- }
-
- /* Check for errors */
- if ( intelxl->vret != 0 )
- return -EIO;
-
- return 0;
- }
-
- rc = -ETIMEDOUT;
- DBGC ( intelxl, "INTELXL %p timed out waiting for admin VF command "
- "%#x\n", intelxl, intelxl->vopcode );
- err_command:
- intelxl->vopcode = 0;
- return rc;
- }
-
- /**
- * Handle link status event
- *
- * @v netdev Network device
- * @v link Link status
- */
- static void intelxlvf_admin_link ( struct net_device *netdev,
- struct intelxl_admin_vf_status_link *link ) {
- struct intelxl_nic *intelxl = netdev->priv;
-
- DBGC ( intelxl, "INTELXL %p link %#02x speed %#02x\n", intelxl,
- link->status, link->speed );
-
- /* Update network device */
- if ( link->status ) {
- netdev_link_up ( netdev );
- } else {
- netdev_link_down ( netdev );
- }
- }
-
- /**
- * Handle status change event
- *
- * @v netdev Network device
- * @v stat Status change event
- */
- static void
- intelxlvf_admin_status ( struct net_device *netdev,
- struct intelxl_admin_vf_status_buffer *stat ) {
- struct intelxl_nic *intelxl = netdev->priv;
-
- /* Handle event */
- switch ( stat->event ) {
- case cpu_to_le32 ( INTELXL_ADMIN_VF_STATUS_LINK ):
- intelxlvf_admin_link ( netdev, &stat->data.link );
- break;
- default:
- DBGC ( intelxl, "INTELXL %p unrecognised status change "
- "event %#x:\n", intelxl, le32_to_cpu ( stat->event ) );
- DBGC_HDA ( intelxl, 0, stat, sizeof ( *stat ) );
- break;
- }
- }
-
- /**
- * Handle virtual function event
- *
- * @v netdev Network device
- * @v evt Admin queue event descriptor
- * @v buf Admin queue event data buffer
- */
- void intelxlvf_admin_event ( struct net_device *netdev,
- struct intelxl_admin_descriptor *evt,
- union intelxl_admin_buffer *buf ) {
- struct intelxl_nic *intelxl = netdev->priv;
- unsigned int vopcode = le32_to_cpu ( evt->vopcode );
-
- /* Record command response if applicable */
- if ( vopcode == intelxl->vopcode ) {
- memcpy ( &intelxl->vbuf, buf, sizeof ( intelxl->vbuf ) );
- intelxl->vopcode = 0;
- intelxl->vret = le32_to_cpu ( evt->vret );
- if ( intelxl->vret != 0 ) {
- DBGC ( intelxl, "INTELXL %p admin VF command %#x "
- "error %d\n", intelxl, vopcode, intelxl->vret );
- DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt,
- sizeof ( *evt ) );
- DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf,
- le16_to_cpu ( evt->len ) );
- }
- return;
- }
-
- /* Handle unsolicited events */
- switch ( vopcode ) {
- case INTELXL_ADMIN_VF_STATUS:
- intelxlvf_admin_status ( netdev, &buf->stat );
- break;
- default:
- DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n",
- intelxl, vopcode );
- DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) );
- DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) );
- break;
- }
- }
-
- /**
- * Get resources
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
- static int intelxlvf_admin_get_resources ( struct net_device *netdev ) {
- struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- struct intelxl_admin_vf_get_resources_buffer *res;
- int rc;
-
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_GET_RESOURCES );
-
- /* Issue command */
- if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
- return rc;
-
- /* Parse response */
- res = &intelxl->vbuf.res;
- intelxl->vsi = le16_to_cpu ( res->vsi );
- memcpy ( netdev->hw_addr, res->mac, ETH_ALEN );
- DBGC ( intelxl, "INTELXL %p VSI %#04x\n", intelxl, intelxl->vsi );
-
- return 0;
- }
-
- /******************************************************************************
- *
- * Network device interface
- *
- ******************************************************************************
- */
-
- /**
- * Configure queues
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
- static int intelxlvf_admin_configure ( struct net_device *netdev ) {
- struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
- int rc;
-
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_CONFIGURE );
- cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
- cmd->len = cpu_to_le16 ( sizeof ( buf->cfg ) );
- buf = intelxl_admin_command_buffer ( intelxl );
- buf->cfg.vsi = cpu_to_le16 ( intelxl->vsi );
- buf->cfg.count = cpu_to_le16 ( 1 );
- buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi );
- buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC );
- buf->cfg.tx.base = cpu_to_le64 ( virt_to_bus ( intelxl->tx.desc.raw ) );
- buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi );
- buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC );
- buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs );
- buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs );
- buf->cfg.rx.base = cpu_to_le64 ( virt_to_bus ( intelxl->rx.desc.raw ) );
-
- /* Issue command */
- if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
- return rc;
-
- return 0;
- }
-
- /**
- * Configure IRQ mapping
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
- static int intelxlvf_admin_irq_map ( struct net_device *netdev ) {
- struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
- int rc;
-
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_IRQ_MAP );
- cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
- cmd->len = cpu_to_le16 ( sizeof ( buf->irq ) );
- buf = intelxl_admin_command_buffer ( intelxl );
- buf->irq.count = cpu_to_le16 ( 1 );
- buf->irq.vsi = cpu_to_le16 ( intelxl->vsi );
- buf->irq.rxmap = cpu_to_le16 ( 0x0001 );
- buf->irq.txmap = cpu_to_le16 ( 0x0001 );
-
- /* Issue command */
- if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
- return rc;
-
- return 0;
- }
-
- /**
- * Enable/disable queues
- *
- * @v netdev Network device
- * @v enable Enable queues
- * @ret rc Return status code
- */
- static int intelxlvf_admin_queues ( struct net_device *netdev, int enable ) {
- struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
- int rc;
-
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = ( enable ? cpu_to_le32 ( INTELXL_ADMIN_VF_ENABLE ) :
- cpu_to_le32 ( INTELXL_ADMIN_VF_DISABLE ) );
- cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
- cmd->len = cpu_to_le16 ( sizeof ( buf->queues ) );
- buf = intelxl_admin_command_buffer ( intelxl );
- buf->queues.vsi = cpu_to_le16 ( intelxl->vsi );
- buf->queues.rx = cpu_to_le32 ( 1 );
- buf->queues.tx = cpu_to_le32 ( 1 );
-
- /* Issue command */
- if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
- return rc;
-
- return 0;
- }
-
- /**
- * Configure promiscuous mode
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
- static int intelxlvf_admin_promisc ( struct net_device *netdev ) {
- struct intelxl_nic *intelxl = netdev->priv;
- struct intelxl_admin_descriptor *cmd;
- union intelxl_admin_buffer *buf;
- int rc;
-
- /* Populate descriptor */
- cmd = intelxl_admin_command_descriptor ( intelxl );
- cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_PROMISC );
- cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
- cmd->len = cpu_to_le16 ( sizeof ( buf->promisc ) );
- buf = intelxl_admin_command_buffer ( intelxl );
- buf->promisc.vsi = cpu_to_le16 ( intelxl->vsi );
- buf->promisc.flags = cpu_to_le16 ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
- INTELXL_ADMIN_PROMISC_FL_MULTICAST );
-
- /* Issue command */
- if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
- return rc;
-
- return 0;
- }
-
- /**
- * Open network device
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
- static int intelxlvf_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 ) );
-
- /* Allocate transmit descriptor ring */
- if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 )
- goto err_alloc_tx;
-
- /* Allocate receive descriptor ring */
- if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 )
- goto err_alloc_rx;
-
- /* Configure queues */
- if ( ( rc = intelxlvf_admin_configure ( netdev ) ) != 0 )
- goto err_configure;
-
- /* Configure IRQ map */
- if ( ( rc = intelxlvf_admin_irq_map ( netdev ) ) != 0 )
- goto err_irq_map;
-
- /* Enable queues */
- if ( ( rc = intelxlvf_admin_queues ( netdev, 1 ) ) != 0 )
- goto err_enable;
-
- /* Configure promiscuous mode */
- if ( ( rc = intelxlvf_admin_promisc ( netdev ) ) != 0 )
- goto err_promisc;
-
- return 0;
-
- err_promisc:
- intelxlvf_admin_queues ( netdev, INTELXL_ADMIN_VF_DISABLE );
- err_enable:
- err_irq_map:
- err_configure:
- intelxl_free_ring ( intelxl, &intelxl->rx );
- err_alloc_rx:
- intelxl_free_ring ( intelxl, &intelxl->tx );
- err_alloc_tx:
- return rc;
- }
-
- /**
- * Close network device
- *
- * @v netdev Network device
- */
- static void intelxlvf_close ( struct net_device *netdev ) {
- struct intelxl_nic *intelxl = netdev->priv;
- int rc;
-
- /* Disable queues */
- if ( ( rc = intelxlvf_admin_queues ( netdev, 0 ) ) != 0 ) {
- /* Leak memory; there's nothing else we can do */
- return;
- }
-
- /* Free receive descriptor ring */
- intelxl_free_ring ( intelxl, &intelxl->rx );
-
- /* Free transmit descriptor ring */
- intelxl_free_ring ( intelxl, &intelxl->tx );
-
- /* Discard any unused receive buffers */
- intelxl_empty_rx ( intelxl );
- }
-
- /** Network device operations */
- static struct net_device_operations intelxlvf_operations = {
- .open = intelxlvf_open,
- .close = intelxlvf_close,
- .transmit = intelxl_transmit,
- .poll = intelxl_poll,
- };
-
- /******************************************************************************
- *
- * PCI interface
- *
- ******************************************************************************
- */
-
- /**
- * Probe PCI device
- *
- * @v pci PCI device
- * @ret rc Return status code
- */
- static int intelxlvf_probe ( struct pci_device *pci ) {
- struct net_device *netdev;
- struct intelxl_nic *intelxl;
- int rc;
-
- /* Allocate and initialise net device */
- netdev = alloc_etherdev ( sizeof ( *intelxl ) );
- if ( ! netdev ) {
- rc = -ENOMEM;
- goto err_alloc;
- }
- netdev_init ( netdev, &intelxlvf_operations );
- intelxl = netdev->priv;
- pci_set_drvdata ( pci, netdev );
- netdev->dev = &pci->dev;
- memset ( intelxl, 0, sizeof ( *intelxl ) );
- intelxl->intr = INTELXLVF_VFINT_DYN_CTL0;
- intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN,
- &intelxlvf_admin_command_offsets );
- intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN,
- &intelxlvf_admin_event_offsets );
- intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC,
- sizeof ( intelxl->tx.desc.tx[0] ),
- INTELXLVF_QTX_TAIL );
- intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC,
- sizeof ( intelxl->rx.desc.rx[0] ),
- INTELXLVF_QRX_TAIL );
-
- /* Fix up PCI device */
- adjust_pci_device ( pci );
-
- /* Map registers */
- intelxl->regs = ioremap ( pci->membase, INTELXLVF_BAR_SIZE );
- if ( ! intelxl->regs ) {
- rc = -ENODEV;
- goto err_ioremap;
- }
-
- /* Locate PCI Express capability */
- intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP );
- if ( ! intelxl->exp ) {
- DBGC ( intelxl, "INTELXL %p missing PCIe capability\n",
- intelxl );
- rc = -ENXIO;
- goto err_exp;
- }
-
- /* Reset the function via PCIe FLR */
- intelxlvf_reset_flr ( intelxl, pci );
-
- /* Enable MSI-X dummy interrupt */
- if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
- goto err_msix;
-
- /* Open admin queues */
- if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
- goto err_open_admin;
-
- /* Reset the function via admin queue */
- if ( ( rc = intelxlvf_reset_admin ( intelxl ) ) != 0 )
- goto err_reset_admin;
-
- /* Get MAC address */
- if ( ( rc = intelxlvf_admin_get_resources ( netdev ) ) != 0 )
- goto err_get_resources;
-
- /* Register network device */
- if ( ( rc = register_netdev ( netdev ) ) != 0 )
- goto err_register_netdev;
-
- return 0;
-
- unregister_netdev ( netdev );
- err_register_netdev:
- err_get_resources:
- err_reset_admin:
- intelxl_close_admin ( intelxl );
- err_open_admin:
- intelxl_msix_disable ( intelxl, pci );
- err_msix:
- intelxlvf_reset_flr ( intelxl, pci );
- 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 intelxlvf_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 );
-
- /* Reset the function via admin queue */
- intelxlvf_reset_admin ( intelxl );
-
- /* Close admin queues */
- intelxl_close_admin ( intelxl );
-
- /* Disable MSI-X dummy interrupt */
- intelxl_msix_disable ( intelxl, pci );
-
- /* Reset the function via PCIe FLR */
- intelxlvf_reset_flr ( intelxl, pci );
-
- /* Free network device */
- iounmap ( intelxl->regs );
- netdev_nullify ( netdev );
- netdev_put ( netdev );
- }
-
- /** PCI device IDs */
- static struct pci_device_id intelxlvf_nics[] = {
- PCI_ROM ( 0x8086, 0x154c, "xl710-vf", "XL710 VF", 0 ),
- PCI_ROM ( 0x8086, 0x1571, "xl710-vf-hv", "XL710 VF (Hyper-V)", 0 ),
- PCI_ROM ( 0x8086, 0x1889, "xl710-vf-ad", "XL710 VF (adaptive)", 0 ),
- PCI_ROM ( 0x8086, 0x37cd, "x722-vf", "X722 VF", 0 ),
- PCI_ROM ( 0x8086, 0x37d9, "x722-vf-hv", "X722 VF (Hyper-V)", 0 ),
- };
-
- /** PCI driver */
- struct pci_driver intelxlvf_driver __pci_driver = {
- .ids = intelxlvf_nics,
- .id_count = ( sizeof ( intelxlvf_nics ) /
- sizeof ( intelxlvf_nics[0] ) ),
- .probe = intelxlvf_probe,
- .remove = intelxlvf_remove,
- };
|