iPXE
intelxlvf.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <errno.h>
00029 #include <byteswap.h>
00030 #include <ipxe/pci.h>
00031 #include <ipxe/netdevice.h>
00032 #include <ipxe/ethernet.h>
00033 #include "intelxlvf.h"
00034 
00035 /** @file
00036  *
00037  * Intel 40 Gigabit Ethernet virtual function network card driver
00038  *
00039  */
00040 
00041 /******************************************************************************
00042  *
00043  * Device reset
00044  *
00045  ******************************************************************************
00046  */
00047 
00048 /**
00049  * Reset hardware via PCIe function-level reset
00050  *
00051  * @v intelxl           Intel device
00052  */
00053 static void intelxlvf_reset_flr ( struct intelxl_nic *intelxl,
00054                                   struct pci_device *pci ) {
00055         uint16_t control;
00056 
00057         /* Perform a PCIe function-level reset */
00058         pci_read_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
00059                                &control );
00060         pci_write_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
00061                                 ( control | PCI_EXP_DEVCTL_FLR ) );
00062         mdelay ( INTELXL_RESET_DELAY_MS );
00063 }
00064 
00065 /**
00066  * Wait for admin event queue to be torn down
00067  *
00068  * @v intelxl           Intel device
00069  * @ret rc              Return status code
00070  */
00071 static int intelxlvf_reset_wait_teardown ( struct intelxl_nic *intelxl ) {
00072         uint32_t admin_evt_len;
00073         unsigned int i;
00074 
00075         /* Wait for admin event queue to be torn down */
00076         for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
00077 
00078                 /* Check admin event queue length register */
00079                 admin_evt_len = readl ( intelxl->regs + INTELXLVF_ADMIN +
00080                                         INTELXLVF_ADMIN_EVT_LEN );
00081                 if ( ! ( admin_evt_len & INTELXL_ADMIN_LEN_ENABLE ) )
00082                         return 0;
00083 
00084                 /* Delay */
00085                 mdelay ( 1 );
00086         }
00087 
00088         DBGC ( intelxl, "INTELXL %p timed out waiting for teardown (%#08x)\n",
00089                intelxl, admin_evt_len );
00090         return -ETIMEDOUT;
00091 }
00092 
00093 /**
00094  * Wait for virtual function to be marked as active
00095  *
00096  * @v intelxl           Intel device
00097  * @ret rc              Return status code
00098  */
00099 static int intelxlvf_reset_wait_active ( struct intelxl_nic *intelxl ) {
00100         uint32_t vfgen_rstat;
00101         unsigned int vfr_state;
00102         unsigned int i;
00103 
00104         /* Wait for virtual function to be marked as active */
00105         for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
00106 
00107                 /* Check status as written by physical function driver */
00108                 vfgen_rstat = readl ( intelxl->regs + INTELXLVF_VFGEN_RSTAT );
00109                 vfr_state = INTELXLVF_VFGEN_RSTAT_VFR_STATE ( vfgen_rstat );
00110                 if ( vfr_state == INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE )
00111                         return 0;
00112 
00113                 /* Delay */
00114                 mdelay ( 1 );
00115         }
00116 
00117         DBGC ( intelxl, "INTELXL %p timed out waiting for activation "
00118                "(%#08x)\n", intelxl, vfgen_rstat );
00119         return -ETIMEDOUT;
00120 }
00121 
00122 /**
00123  * Reset hardware via admin queue
00124  *
00125  * @v intelxl           Intel device
00126  * @ret rc              Return status code
00127  */
00128 static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
00129         struct intelxl_admin_descriptor *cmd;
00130         int rc;
00131 
00132         /* Populate descriptor */
00133         cmd = intelxl_admin_command_descriptor ( intelxl );
00134         cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
00135         cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_RESET );
00136 
00137         /* Issue command */
00138         if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
00139                 goto err_command;
00140 
00141         /* Wait for minimum reset time */
00142         mdelay ( INTELXL_RESET_DELAY_MS );
00143 
00144         /* Wait for reset to take effect */
00145         if ( ( rc = intelxlvf_reset_wait_teardown ( intelxl ) ) != 0 )
00146                 goto err_teardown;
00147 
00148         /* Wait for virtual function to become active */
00149         if ( ( rc = intelxlvf_reset_wait_active ( intelxl ) ) != 0 )
00150                 goto err_active;
00151 
00152  err_active:
00153  err_teardown:
00154         intelxl_reopen_admin ( intelxl );
00155  err_command:
00156         return rc;
00157 }
00158 
00159 /******************************************************************************
00160  *
00161  * Admin queue
00162  *
00163  ******************************************************************************
00164  */
00165 
00166 /** Admin command queue register offsets */
00167 static const struct intelxl_admin_offsets intelxlvf_admin_command_offsets = {
00168         .bal = INTELXLVF_ADMIN_CMD_BAL,
00169         .bah = INTELXLVF_ADMIN_CMD_BAH,
00170         .len = INTELXLVF_ADMIN_CMD_LEN,
00171         .head = INTELXLVF_ADMIN_CMD_HEAD,
00172         .tail = INTELXLVF_ADMIN_CMD_TAIL,
00173 };
00174 
00175 /** Admin event queue register offsets */
00176 static const struct intelxl_admin_offsets intelxlvf_admin_event_offsets = {
00177         .bal = INTELXLVF_ADMIN_EVT_BAL,
00178         .bah = INTELXLVF_ADMIN_EVT_BAH,
00179         .len = INTELXLVF_ADMIN_EVT_LEN,
00180         .head = INTELXLVF_ADMIN_EVT_HEAD,
00181         .tail = INTELXLVF_ADMIN_EVT_TAIL,
00182 };
00183 
00184 /**
00185  * Issue admin queue virtual function command
00186  *
00187  * @v netdev            Network device
00188  * @ret rc              Return status code
00189  */
00190 static int intelxlvf_admin_command ( struct net_device *netdev ) {
00191         struct intelxl_nic *intelxl = netdev->priv;
00192         struct intelxl_admin *admin = &intelxl->command;
00193         struct intelxl_admin_descriptor *cmd;
00194         unsigned int i;
00195         int rc;
00196 
00197         /* Populate descriptor */
00198         cmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
00199         cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
00200 
00201         /* Record opcode */
00202         intelxl->vopcode = le32_to_cpu ( cmd->vopcode );
00203 
00204         /* Issue command */
00205         if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
00206                 goto err_command;
00207 
00208         /* Wait for response */
00209         for ( i = 0 ; i < INTELXLVF_ADMIN_MAX_WAIT_MS ; i++ ) {
00210 
00211                 /* Poll admin event queue */
00212                 intelxl_poll_admin ( netdev );
00213 
00214                 /* If response has not arrived, delay 1ms and retry */
00215                 if ( intelxl->vopcode ) {
00216                         mdelay ( 1 );
00217                         continue;
00218                 }
00219 
00220                 /* Check for errors */
00221                 if ( intelxl->vret != 0 )
00222                         return -EIO;
00223 
00224                 return 0;
00225         }
00226 
00227         rc = -ETIMEDOUT;
00228         DBGC ( intelxl, "INTELXL %p timed out waiting for admin VF command "
00229                "%#x\n", intelxl, intelxl->vopcode );
00230  err_command:
00231         intelxl->vopcode = 0;
00232         return rc;
00233 }
00234 
00235 /**
00236  * Handle link status event
00237  *
00238  * @v netdev            Network device
00239  * @v link              Link status
00240  */
00241 static void intelxlvf_admin_link ( struct net_device *netdev,
00242                                    struct intelxl_admin_vf_status_link *link ) {
00243         struct intelxl_nic *intelxl = netdev->priv;
00244 
00245         DBGC ( intelxl, "INTELXL %p link %#02x speed %#02x\n", intelxl,
00246                link->status, link->speed );
00247 
00248         /* Update network device */
00249         if ( link->status ) {
00250                 netdev_link_up ( netdev );
00251         } else {
00252                 netdev_link_down ( netdev );
00253         }
00254 }
00255 
00256 /**
00257  * Handle status change event
00258  *
00259  * @v netdev            Network device
00260  * @v stat              Status change event
00261  */
00262 static void
00263 intelxlvf_admin_status ( struct net_device *netdev,
00264                          struct intelxl_admin_vf_status_buffer *stat ) {
00265         struct intelxl_nic *intelxl = netdev->priv;
00266 
00267         /* Handle event */
00268         switch ( stat->event ) {
00269         case cpu_to_le32 ( INTELXL_ADMIN_VF_STATUS_LINK ):
00270                 intelxlvf_admin_link ( netdev, &stat->data.link );
00271                 break;
00272         default:
00273                 DBGC ( intelxl, "INTELXL %p unrecognised status change "
00274                        "event %#x:\n", intelxl, le32_to_cpu ( stat->event ) );
00275                 DBGC_HDA ( intelxl, 0, stat, sizeof ( *stat ) );
00276                 break;
00277         }
00278 }
00279 
00280 /**
00281  * Handle virtual function event
00282  *
00283  * @v netdev            Network device
00284  * @v evt               Admin queue event descriptor
00285  * @v buf               Admin queue event data buffer
00286  */
00287 void intelxlvf_admin_event ( struct net_device *netdev,
00288                              struct intelxl_admin_descriptor *evt,
00289                              union intelxl_admin_buffer *buf ) {
00290         struct intelxl_nic *intelxl = netdev->priv;
00291         unsigned int vopcode = le32_to_cpu ( evt->vopcode );
00292 
00293         /* Record command response if applicable */
00294         if ( vopcode == intelxl->vopcode ) {
00295                 memcpy ( &intelxl->vbuf, buf, sizeof ( intelxl->vbuf ) );
00296                 intelxl->vopcode = 0;
00297                 intelxl->vret = le32_to_cpu ( evt->vret );
00298                 if ( intelxl->vret != 0 ) {
00299                         DBGC ( intelxl, "INTELXL %p admin VF command %#x "
00300                                "error %d\n", intelxl, vopcode, intelxl->vret );
00301                         DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt,
00302                                    sizeof ( *evt ) );
00303                         DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf,
00304                                    le16_to_cpu ( evt->len ) );
00305                 }
00306                 return;
00307         }
00308 
00309         /* Handle unsolicited events */
00310         switch ( vopcode ) {
00311         case INTELXL_ADMIN_VF_STATUS:
00312                 intelxlvf_admin_status ( netdev, &buf->stat );
00313                 break;
00314         default:
00315                 DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n",
00316                        intelxl, vopcode );
00317                 DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) );
00318                 DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) );
00319                 break;
00320         }
00321 }
00322 
00323 /**
00324  * Get resources
00325  *
00326  * @v netdev            Network device
00327  * @ret rc              Return status code
00328  */
00329 static int intelxlvf_admin_get_resources ( struct net_device *netdev ) {
00330         struct intelxl_nic *intelxl = netdev->priv;
00331         struct intelxl_admin_descriptor *cmd;
00332         struct intelxl_admin_vf_get_resources_buffer *res;
00333         int rc;
00334 
00335         /* Populate descriptor */
00336         cmd = intelxl_admin_command_descriptor ( intelxl );
00337         cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_GET_RESOURCES );
00338 
00339         /* Issue command */
00340         if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
00341                 return rc;
00342 
00343         /* Parse response */
00344         res = &intelxl->vbuf.res;
00345         intelxl->vsi = le16_to_cpu ( res->vsi );
00346         memcpy ( netdev->hw_addr, res->mac, ETH_ALEN );
00347         DBGC ( intelxl, "INTELXL %p VSI %#04x\n", intelxl, intelxl->vsi );
00348 
00349         return 0;
00350 }
00351 
00352 /******************************************************************************
00353  *
00354  * Network device interface
00355  *
00356  ******************************************************************************
00357  */
00358 
00359 /**
00360  * Configure queues
00361  *
00362  * @v netdev            Network device
00363  * @ret rc              Return status code
00364  */
00365 static int intelxlvf_admin_configure ( struct net_device *netdev ) {
00366         struct intelxl_nic *intelxl = netdev->priv;
00367         struct intelxl_admin_descriptor *cmd;
00368         union intelxl_admin_buffer *buf;
00369         int rc;
00370 
00371         /* Populate descriptor */
00372         cmd = intelxl_admin_command_descriptor ( intelxl );
00373         cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_CONFIGURE );
00374         cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
00375         cmd->len = cpu_to_le16 ( sizeof ( buf->cfg ) );
00376         buf = intelxl_admin_command_buffer ( intelxl );
00377         buf->cfg.vsi = cpu_to_le16 ( intelxl->vsi );
00378         buf->cfg.count = cpu_to_le16 ( 1 );
00379         buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi );
00380         buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC );
00381         buf->cfg.tx.base = cpu_to_le64 ( virt_to_bus ( intelxl->tx.desc.raw ) );
00382         buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi );
00383         buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC );
00384         buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs );
00385         buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs );
00386         buf->cfg.rx.base = cpu_to_le64 ( virt_to_bus ( intelxl->rx.desc.raw ) );
00387 
00388         /* Issue command */
00389         if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
00390                 return rc;
00391 
00392         return 0;
00393 }
00394 
00395 /**
00396  * Configure IRQ mapping
00397  *
00398  * @v netdev            Network device
00399  * @ret rc              Return status code
00400  */
00401 static int intelxlvf_admin_irq_map ( struct net_device *netdev ) {
00402         struct intelxl_nic *intelxl = netdev->priv;
00403         struct intelxl_admin_descriptor *cmd;
00404         union intelxl_admin_buffer *buf;
00405         int rc;
00406 
00407         /* Populate descriptor */
00408         cmd = intelxl_admin_command_descriptor ( intelxl );
00409         cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_IRQ_MAP );
00410         cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
00411         cmd->len = cpu_to_le16 ( sizeof ( buf->irq ) );
00412         buf = intelxl_admin_command_buffer ( intelxl );
00413         buf->irq.count = cpu_to_le16 ( 1 );
00414         buf->irq.vsi = cpu_to_le16 ( intelxl->vsi );
00415         buf->irq.rxmap = cpu_to_le16 ( 0x0001 );
00416         buf->irq.txmap = cpu_to_le16 ( 0x0001 );
00417 
00418         /* Issue command */
00419         if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
00420                 return rc;
00421 
00422         return 0;
00423 }
00424 
00425 /**
00426  * Enable/disable queues
00427  *
00428  * @v netdev            Network device
00429  * @v enable            Enable queues
00430  * @ret rc              Return status code
00431  */
00432 static int intelxlvf_admin_queues ( struct net_device *netdev, int enable ) {
00433         struct intelxl_nic *intelxl = netdev->priv;
00434         struct intelxl_admin_descriptor *cmd;
00435         union intelxl_admin_buffer *buf;
00436         int rc;
00437 
00438         /* Populate descriptor */
00439         cmd = intelxl_admin_command_descriptor ( intelxl );
00440         cmd->vopcode = ( enable ? cpu_to_le32 ( INTELXL_ADMIN_VF_ENABLE ) :
00441                          cpu_to_le32 ( INTELXL_ADMIN_VF_DISABLE ) );
00442         cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
00443         cmd->len = cpu_to_le16 ( sizeof ( buf->queues ) );
00444         buf = intelxl_admin_command_buffer ( intelxl );
00445         buf->queues.vsi = cpu_to_le16 ( intelxl->vsi );
00446         buf->queues.rx = cpu_to_le32 ( 1 );
00447         buf->queues.tx = cpu_to_le32 ( 1 );
00448 
00449         /* Issue command */
00450         if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
00451                 return rc;
00452 
00453         return 0;
00454 }
00455 
00456 /**
00457  * Configure promiscuous mode
00458  *
00459  * @v netdev            Network device
00460  * @ret rc              Return status code
00461  */
00462 static int intelxlvf_admin_promisc ( struct net_device *netdev ) {
00463         struct intelxl_nic *intelxl = netdev->priv;
00464         struct intelxl_admin_descriptor *cmd;
00465         union intelxl_admin_buffer *buf;
00466         int rc;
00467 
00468         /* Populate descriptor */
00469         cmd = intelxl_admin_command_descriptor ( intelxl );
00470         cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_PROMISC );
00471         cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
00472         cmd->len = cpu_to_le16 ( sizeof ( buf->promisc ) );
00473         buf = intelxl_admin_command_buffer ( intelxl );
00474         buf->promisc.vsi = cpu_to_le16 ( intelxl->vsi );
00475         buf->promisc.flags = cpu_to_le16 ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
00476                                            INTELXL_ADMIN_PROMISC_FL_MULTICAST );
00477 
00478         /* Issue command */
00479         if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
00480                 return rc;
00481 
00482         return 0;
00483 }
00484 
00485 /**
00486  * Open network device
00487  *
00488  * @v netdev            Network device
00489  * @ret rc              Return status code
00490  */
00491 static int intelxlvf_open ( struct net_device *netdev ) {
00492         struct intelxl_nic *intelxl = netdev->priv;
00493         int rc;
00494 
00495         /* Calculate maximum frame size */
00496         intelxl->mfs = ( ( ETH_HLEN + netdev->mtu + 4 /* CRC */ +
00497                            INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
00498 
00499         /* Allocate transmit descriptor ring */
00500         if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 )
00501                 goto err_alloc_tx;
00502 
00503         /* Allocate receive descriptor ring */
00504         if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 )
00505                 goto err_alloc_rx;
00506 
00507         /* Configure queues */
00508         if ( ( rc = intelxlvf_admin_configure ( netdev ) ) != 0 )
00509                 goto err_configure;
00510 
00511         /* Configure IRQ map */
00512         if ( ( rc = intelxlvf_admin_irq_map ( netdev ) ) != 0 )
00513                 goto err_irq_map;
00514 
00515         /* Enable queues */
00516         if ( ( rc = intelxlvf_admin_queues ( netdev, 1 ) ) != 0 )
00517                 goto err_enable;
00518 
00519         /* Configure promiscuous mode */
00520         if ( ( rc = intelxlvf_admin_promisc ( netdev ) ) != 0 )
00521                 goto err_promisc;
00522 
00523         return 0;
00524 
00525  err_promisc:
00526         intelxlvf_admin_queues ( netdev, INTELXL_ADMIN_VF_DISABLE );
00527  err_enable:
00528  err_irq_map:
00529  err_configure:
00530         intelxl_free_ring ( intelxl, &intelxl->rx );
00531  err_alloc_rx:
00532         intelxl_free_ring ( intelxl, &intelxl->tx );
00533  err_alloc_tx:
00534         return rc;
00535 }
00536 
00537 /**
00538  * Close network device
00539  *
00540  * @v netdev            Network device
00541  */
00542 static void intelxlvf_close ( struct net_device *netdev ) {
00543         struct intelxl_nic *intelxl = netdev->priv;
00544         int rc;
00545 
00546         /* Disable queues */
00547         if ( ( rc = intelxlvf_admin_queues ( netdev, 0 ) ) != 0 ) {
00548                 /* Leak memory; there's nothing else we can do */
00549                 return;
00550         }
00551 
00552         /* Free receive descriptor ring */
00553         intelxl_free_ring ( intelxl, &intelxl->rx );
00554 
00555         /* Free transmit descriptor ring */
00556         intelxl_free_ring ( intelxl, &intelxl->tx );
00557 
00558         /* Discard any unused receive buffers */
00559         intelxl_empty_rx ( intelxl );
00560 }
00561 
00562 /** Network device operations */
00563 static struct net_device_operations intelxlvf_operations = {
00564         .open           = intelxlvf_open,
00565         .close          = intelxlvf_close,
00566         .transmit       = intelxl_transmit,
00567         .poll           = intelxl_poll,
00568 };
00569 
00570 /******************************************************************************
00571  *
00572  * PCI interface
00573  *
00574  ******************************************************************************
00575  */
00576 
00577 /**
00578  * Probe PCI device
00579  *
00580  * @v pci               PCI device
00581  * @ret rc              Return status code
00582  */
00583 static int intelxlvf_probe ( struct pci_device *pci ) {
00584         struct net_device *netdev;
00585         struct intelxl_nic *intelxl;
00586         int rc;
00587 
00588         /* Allocate and initialise net device */
00589         netdev = alloc_etherdev ( sizeof ( *intelxl ) );
00590         if ( ! netdev ) {
00591                 rc = -ENOMEM;
00592                 goto err_alloc;
00593         }
00594         netdev_init ( netdev, &intelxlvf_operations );
00595         intelxl = netdev->priv;
00596         pci_set_drvdata ( pci, netdev );
00597         netdev->dev = &pci->dev;
00598         memset ( intelxl, 0, sizeof ( *intelxl ) );
00599         intelxl->intr = INTELXLVF_VFINT_DYN_CTL0;
00600         intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN,
00601                              &intelxlvf_admin_command_offsets );
00602         intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN,
00603                              &intelxlvf_admin_event_offsets );
00604         intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC,
00605                               sizeof ( intelxl->tx.desc.tx[0] ),
00606                               INTELXLVF_QTX_TAIL );
00607         intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC,
00608                               sizeof ( intelxl->rx.desc.rx[0] ),
00609                               INTELXLVF_QRX_TAIL );
00610 
00611         /* Fix up PCI device */
00612         adjust_pci_device ( pci );
00613 
00614         /* Map registers */
00615         intelxl->regs = ioremap ( pci->membase, INTELXLVF_BAR_SIZE );
00616         if ( ! intelxl->regs ) {
00617                 rc = -ENODEV;
00618                 goto err_ioremap;
00619         }
00620 
00621         /* Locate PCI Express capability */
00622         intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP );
00623         if ( ! intelxl->exp ) {
00624                 DBGC ( intelxl, "INTELXL %p missing PCIe capability\n",
00625                        intelxl );
00626                 rc = -ENXIO;
00627                 goto err_exp;
00628         }
00629 
00630         /* Reset the function via PCIe FLR */
00631         intelxlvf_reset_flr ( intelxl, pci );
00632 
00633         /* Enable MSI-X dummy interrupt */
00634         if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
00635                 goto err_msix;
00636 
00637         /* Open admin queues */
00638         if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
00639                 goto err_open_admin;
00640 
00641         /* Reset the function via admin queue */
00642         if ( ( rc = intelxlvf_reset_admin ( intelxl ) ) != 0 )
00643                 goto err_reset_admin;
00644 
00645         /* Get MAC address */
00646         if ( ( rc = intelxlvf_admin_get_resources ( netdev ) ) != 0 )
00647                 goto err_get_resources;
00648 
00649         /* Register network device */
00650         if ( ( rc = register_netdev ( netdev ) ) != 0 )
00651                 goto err_register_netdev;
00652 
00653         return 0;
00654 
00655         unregister_netdev ( netdev );
00656  err_register_netdev:
00657  err_get_resources:
00658  err_reset_admin:
00659         intelxl_close_admin ( intelxl );
00660  err_open_admin:
00661         intelxl_msix_disable ( intelxl, pci );
00662  err_msix:
00663         intelxlvf_reset_flr ( intelxl, pci );
00664  err_exp:
00665         iounmap ( intelxl->regs );
00666  err_ioremap:
00667         netdev_nullify ( netdev );
00668         netdev_put ( netdev );
00669  err_alloc:
00670         return rc;
00671 }
00672 
00673 /**
00674  * Remove PCI device
00675  *
00676  * @v pci               PCI device
00677  */
00678 static void intelxlvf_remove ( struct pci_device *pci ) {
00679         struct net_device *netdev = pci_get_drvdata ( pci );
00680         struct intelxl_nic *intelxl = netdev->priv;
00681 
00682         /* Unregister network device */
00683         unregister_netdev ( netdev );
00684 
00685         /* Reset the function via admin queue */
00686         intelxlvf_reset_admin ( intelxl );
00687 
00688         /* Close admin queues */
00689         intelxl_close_admin ( intelxl );
00690 
00691         /* Disable MSI-X dummy interrupt */
00692         intelxl_msix_disable ( intelxl, pci );
00693 
00694         /* Reset the function via PCIe FLR */
00695         intelxlvf_reset_flr ( intelxl, pci );
00696 
00697         /* Free network device */
00698         iounmap ( intelxl->regs );
00699         netdev_nullify ( netdev );
00700         netdev_put ( netdev );
00701 }
00702 
00703 /** PCI device IDs */
00704 static struct pci_device_id intelxlvf_nics[] = {
00705         PCI_ROM ( 0x8086, 0x154c, "xl710-vf", "XL710 VF", 0 ),
00706         PCI_ROM ( 0x8086, 0x1571, "xl710-vf-hv", "XL710 VF (Hyper-V)", 0 ),
00707         PCI_ROM ( 0x8086, 0x1889, "xl710-vf-ad", "XL710 VF (adaptive)", 0 ),
00708         PCI_ROM ( 0x8086, 0x37cd, "x722-vf", "X722 VF", 0 ),
00709         PCI_ROM ( 0x8086, 0x37d9, "x722-vf-hv", "X722 VF (Hyper-V)", 0 ),
00710 };
00711 
00712 /** PCI driver */
00713 struct pci_driver intelxlvf_driver __pci_driver = {
00714         .ids = intelxlvf_nics,
00715         .id_count = ( sizeof ( intelxlvf_nics ) /
00716                       sizeof ( intelxlvf_nics[0] ) ),
00717         .probe = intelxlvf_probe,
00718         .remove = intelxlvf_remove,
00719 };