|  | @@ -0,0 +1,377 @@
 | 
		
	
		
			
			|  | 1 | +/*
 | 
		
	
		
			
			|  | 2 | + * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
 | 
		
	
		
			
			|  | 3 | + *
 | 
		
	
		
			
			|  | 4 | + * This program is free software; you can redistribute it and/or
 | 
		
	
		
			
			|  | 5 | + * modify it under the terms of the GNU General Public License as
 | 
		
	
		
			
			|  | 6 | + * published by the Free Software Foundation; either version 2 of the
 | 
		
	
		
			
			|  | 7 | + * License, or (at your option) any later version.
 | 
		
	
		
			
			|  | 8 | + *
 | 
		
	
		
			
			|  | 9 | + * This program is distributed in the hope that it will be useful, but
 | 
		
	
		
			
			|  | 10 | + * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
		
	
		
			
			|  | 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
		
	
		
			
			|  | 12 | + * General Public License for more details.
 | 
		
	
		
			
			|  | 13 | + *
 | 
		
	
		
			
			|  | 14 | + * You should have received a copy of the GNU General Public License
 | 
		
	
		
			
			|  | 15 | + * along with this program; if not, write to the Free Software
 | 
		
	
		
			
			|  | 16 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
		
	
		
			
			|  | 17 | + * 02110-1301, USA.
 | 
		
	
		
			
			|  | 18 | + *
 | 
		
	
		
			
			|  | 19 | + * You can also choose to distribute this program under the terms of
 | 
		
	
		
			
			|  | 20 | + * the Unmodified Binary Distribution Licence (as given in the file
 | 
		
	
		
			
			|  | 21 | + * COPYING.UBDL), provided that you have satisfied its requirements.
 | 
		
	
		
			
			|  | 22 | + */
 | 
		
	
		
			
			|  | 23 | +
 | 
		
	
		
			
			|  | 24 | +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			|  | 25 | +
 | 
		
	
		
			
			|  | 26 | +#include <string.h>
 | 
		
	
		
			
			|  | 27 | +#include <unistd.h>
 | 
		
	
		
			
			|  | 28 | +#include <errno.h>
 | 
		
	
		
			
			|  | 29 | +#include <ipxe/io.h>
 | 
		
	
		
			
			|  | 30 | +#include <ipxe/pci.h>
 | 
		
	
		
			
			|  | 31 | +#include <ipxe/netdevice.h>
 | 
		
	
		
			
			|  | 32 | +#include <ipxe/ethernet.h>
 | 
		
	
		
			
			|  | 33 | +#include "intelxvf.h"
 | 
		
	
		
			
			|  | 34 | +
 | 
		
	
		
			
			|  | 35 | +/** @file
 | 
		
	
		
			
			|  | 36 | + *
 | 
		
	
		
			
			|  | 37 | + * Intel 10 Gigabit Ethernet virtual function network card driver
 | 
		
	
		
			
			|  | 38 | + *
 | 
		
	
		
			
			|  | 39 | + */
 | 
		
	
		
			
			|  | 40 | +
 | 
		
	
		
			
			|  | 41 | +/******************************************************************************
 | 
		
	
		
			
			|  | 42 | + *
 | 
		
	
		
			
			|  | 43 | + * Device reset
 | 
		
	
		
			
			|  | 44 | + *
 | 
		
	
		
			
			|  | 45 | + ******************************************************************************
 | 
		
	
		
			
			|  | 46 | + */
 | 
		
	
		
			
			|  | 47 | +
 | 
		
	
		
			
			|  | 48 | +/**
 | 
		
	
		
			
			|  | 49 | + * Reset hardware
 | 
		
	
		
			
			|  | 50 | + *
 | 
		
	
		
			
			|  | 51 | + * @v intel		Intel device
 | 
		
	
		
			
			|  | 52 | + */
 | 
		
	
		
			
			|  | 53 | +static void intelxvf_reset ( struct intel_nic *intel ) {
 | 
		
	
		
			
			|  | 54 | +
 | 
		
	
		
			
			|  | 55 | +	/* Perform a function-level reset */
 | 
		
	
		
			
			|  | 56 | +	writel ( INTELXVF_CTRL_RST, intel->regs + INTELXVF_CTRL );
 | 
		
	
		
			
			|  | 57 | +}
 | 
		
	
		
			
			|  | 58 | +
 | 
		
	
		
			
			|  | 59 | +/******************************************************************************
 | 
		
	
		
			
			|  | 60 | + *
 | 
		
	
		
			
			|  | 61 | + * Link state
 | 
		
	
		
			
			|  | 62 | + *
 | 
		
	
		
			
			|  | 63 | + ******************************************************************************
 | 
		
	
		
			
			|  | 64 | + */
 | 
		
	
		
			
			|  | 65 | +
 | 
		
	
		
			
			|  | 66 | +/**
 | 
		
	
		
			
			|  | 67 | + * Check link state
 | 
		
	
		
			
			|  | 68 | + *
 | 
		
	
		
			
			|  | 69 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 70 | + */
 | 
		
	
		
			
			|  | 71 | +static void intelxvf_check_link ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 72 | +	struct intel_nic *intel = netdev->priv;
 | 
		
	
		
			
			|  | 73 | +	uint32_t links;
 | 
		
	
		
			
			|  | 74 | +
 | 
		
	
		
			
			|  | 75 | +	/* Read link status */
 | 
		
	
		
			
			|  | 76 | +	links = readl ( intel->regs + INTELXVF_LINKS );
 | 
		
	
		
			
			|  | 77 | +	DBGC ( intel, "INTEL %p link status is %08x\n", intel, links );
 | 
		
	
		
			
			|  | 78 | +
 | 
		
	
		
			
			|  | 79 | +	/* Update network device */
 | 
		
	
		
			
			|  | 80 | +	if ( links & INTELXVF_LINKS_UP ) {
 | 
		
	
		
			
			|  | 81 | +		netdev_link_up ( netdev );
 | 
		
	
		
			
			|  | 82 | +	} else {
 | 
		
	
		
			
			|  | 83 | +		netdev_link_down ( netdev );
 | 
		
	
		
			
			|  | 84 | +	}
 | 
		
	
		
			
			|  | 85 | +}
 | 
		
	
		
			
			|  | 86 | +
 | 
		
	
		
			
			|  | 87 | +/******************************************************************************
 | 
		
	
		
			
			|  | 88 | + *
 | 
		
	
		
			
			|  | 89 | + * Network device interface
 | 
		
	
		
			
			|  | 90 | + *
 | 
		
	
		
			
			|  | 91 | + ******************************************************************************
 | 
		
	
		
			
			|  | 92 | + */
 | 
		
	
		
			
			|  | 93 | +
 | 
		
	
		
			
			|  | 94 | +/**
 | 
		
	
		
			
			|  | 95 | + * Open network device
 | 
		
	
		
			
			|  | 96 | + *
 | 
		
	
		
			
			|  | 97 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 98 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 99 | + */
 | 
		
	
		
			
			|  | 100 | +static int intelxvf_open ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 101 | +	struct intel_nic *intel = netdev->priv;
 | 
		
	
		
			
			|  | 102 | +	uint32_t srrctl;
 | 
		
	
		
			
			|  | 103 | +	uint32_t dca_rxctrl;
 | 
		
	
		
			
			|  | 104 | +	int rc;
 | 
		
	
		
			
			|  | 105 | +
 | 
		
	
		
			
			|  | 106 | +	/* Reset the function */
 | 
		
	
		
			
			|  | 107 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 108 | +
 | 
		
	
		
			
			|  | 109 | +	/* Notify PF that reset is complete */
 | 
		
	
		
			
			|  | 110 | +	if ( ( rc = intelvf_mbox_reset ( intel, NULL ) ) != 0 ) {
 | 
		
	
		
			
			|  | 111 | +		DBGC ( intel, "INTEL %p could not reset: %s\n",
 | 
		
	
		
			
			|  | 112 | +		       intel, strerror ( rc ) );
 | 
		
	
		
			
			|  | 113 | +		goto err_mbox_reset;
 | 
		
	
		
			
			|  | 114 | +	}
 | 
		
	
		
			
			|  | 115 | +
 | 
		
	
		
			
			|  | 116 | +	/* Set MAC address */
 | 
		
	
		
			
			|  | 117 | +	if ( ( rc = intelvf_mbox_set_mac ( intel, netdev->ll_addr ) ) != 0 ) {
 | 
		
	
		
			
			|  | 118 | +		DBGC ( intel, "INTEL %p could not set MAC address: %s\n",
 | 
		
	
		
			
			|  | 119 | +		       intel, strerror ( rc ) );
 | 
		
	
		
			
			|  | 120 | +		goto err_mbox_set_mac;
 | 
		
	
		
			
			|  | 121 | +	}
 | 
		
	
		
			
			|  | 122 | +
 | 
		
	
		
			
			|  | 123 | +	/* Create transmit descriptor ring */
 | 
		
	
		
			
			|  | 124 | +	if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
 | 
		
	
		
			
			|  | 125 | +		goto err_create_tx;
 | 
		
	
		
			
			|  | 126 | +
 | 
		
	
		
			
			|  | 127 | +	/* Create receive descriptor ring */
 | 
		
	
		
			
			|  | 128 | +	if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 )
 | 
		
	
		
			
			|  | 129 | +		goto err_create_rx;
 | 
		
	
		
			
			|  | 130 | +
 | 
		
	
		
			
			|  | 131 | +	/* Allocate interrupt vectors */
 | 
		
	
		
			
			|  | 132 | +	writel ( ( INTELXVF_IVAR_RX0_DEFAULT | INTELXVF_IVAR_RX0_VALID |
 | 
		
	
		
			
			|  | 133 | +		   INTELXVF_IVAR_TX0_DEFAULT | INTELXVF_IVAR_TX0_VALID ),
 | 
		
	
		
			
			|  | 134 | +		 intel->regs + INTELXVF_IVAR );
 | 
		
	
		
			
			|  | 135 | +	writel ( ( INTELXVF_IVARM_MBOX_DEFAULT | INTELXVF_IVARM_MBOX_VALID ),
 | 
		
	
		
			
			|  | 136 | +		 intel->regs + INTELXVF_IVARM );
 | 
		
	
		
			
			|  | 137 | +
 | 
		
	
		
			
			|  | 138 | +	/* Configure receive buffer sizes and set receive descriptor type */
 | 
		
	
		
			
			|  | 139 | +	srrctl = readl ( intel->regs + INTELXVF_SRRCTL );
 | 
		
	
		
			
			|  | 140 | +	srrctl &= ~( INTELXVF_SRRCTL_BSIZE_MASK |
 | 
		
	
		
			
			|  | 141 | +		     INTELXVF_SRRCTL_DESCTYPE_MASK );
 | 
		
	
		
			
			|  | 142 | +	srrctl |= ( INTELXVF_SRRCTL_BSIZE_DEFAULT |
 | 
		
	
		
			
			|  | 143 | +		    INTELXVF_SRRCTL_DESCTYPE_DEFAULT );
 | 
		
	
		
			
			|  | 144 | +	writel ( srrctl, intel->regs + INTELXVF_SRRCTL );
 | 
		
	
		
			
			|  | 145 | +
 | 
		
	
		
			
			|  | 146 | +	/* Clear "must-be-zero" bit for direct cache access (DCA).  We
 | 
		
	
		
			
			|  | 147 | +	 * leave DCA disabled anyway, but if we do not clear this bit
 | 
		
	
		
			
			|  | 148 | +	 * then the received packets contain garbage data.
 | 
		
	
		
			
			|  | 149 | +	 */
 | 
		
	
		
			
			|  | 150 | +	dca_rxctrl = readl ( intel->regs + INTELXVF_DCA_RXCTRL );
 | 
		
	
		
			
			|  | 151 | +	dca_rxctrl &= ~INTELXVF_DCA_RXCTRL_MUST_BE_ZERO;
 | 
		
	
		
			
			|  | 152 | +	writel ( dca_rxctrl, intel->regs + INTELXVF_DCA_RXCTRL );
 | 
		
	
		
			
			|  | 153 | +
 | 
		
	
		
			
			|  | 154 | +	/* Fill receive ring */
 | 
		
	
		
			
			|  | 155 | +	intel_refill_rx ( intel );
 | 
		
	
		
			
			|  | 156 | +
 | 
		
	
		
			
			|  | 157 | +	/* Update link state */
 | 
		
	
		
			
			|  | 158 | +	intelxvf_check_link ( netdev );
 | 
		
	
		
			
			|  | 159 | +
 | 
		
	
		
			
			|  | 160 | +	return 0;
 | 
		
	
		
			
			|  | 161 | +
 | 
		
	
		
			
			|  | 162 | +	intel_destroy_ring ( intel, &intel->rx );
 | 
		
	
		
			
			|  | 163 | + err_create_rx:
 | 
		
	
		
			
			|  | 164 | +	intel_destroy_ring ( intel, &intel->tx );
 | 
		
	
		
			
			|  | 165 | + err_create_tx:
 | 
		
	
		
			
			|  | 166 | + err_mbox_set_mac:
 | 
		
	
		
			
			|  | 167 | + err_mbox_reset:
 | 
		
	
		
			
			|  | 168 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 169 | +	return rc;
 | 
		
	
		
			
			|  | 170 | +}
 | 
		
	
		
			
			|  | 171 | +
 | 
		
	
		
			
			|  | 172 | +/**
 | 
		
	
		
			
			|  | 173 | + * Close network device
 | 
		
	
		
			
			|  | 174 | + *
 | 
		
	
		
			
			|  | 175 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 176 | + */
 | 
		
	
		
			
			|  | 177 | +static void intelxvf_close ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 178 | +	struct intel_nic *intel = netdev->priv;
 | 
		
	
		
			
			|  | 179 | +
 | 
		
	
		
			
			|  | 180 | +	/* Destroy receive descriptor ring */
 | 
		
	
		
			
			|  | 181 | +	intel_destroy_ring ( intel, &intel->rx );
 | 
		
	
		
			
			|  | 182 | +
 | 
		
	
		
			
			|  | 183 | +	/* Discard any unused receive buffers */
 | 
		
	
		
			
			|  | 184 | +	intel_empty_rx ( intel );
 | 
		
	
		
			
			|  | 185 | +
 | 
		
	
		
			
			|  | 186 | +	/* Destroy transmit descriptor ring */
 | 
		
	
		
			
			|  | 187 | +	intel_destroy_ring ( intel, &intel->tx );
 | 
		
	
		
			
			|  | 188 | +
 | 
		
	
		
			
			|  | 189 | +	/* Reset the function */
 | 
		
	
		
			
			|  | 190 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 191 | +}
 | 
		
	
		
			
			|  | 192 | +
 | 
		
	
		
			
			|  | 193 | +/**
 | 
		
	
		
			
			|  | 194 | + * Poll for completed and received packets
 | 
		
	
		
			
			|  | 195 | + *
 | 
		
	
		
			
			|  | 196 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 197 | + */
 | 
		
	
		
			
			|  | 198 | +static void intelxvf_poll ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 199 | +	struct intel_nic *intel = netdev->priv;
 | 
		
	
		
			
			|  | 200 | +	uint32_t eicr;
 | 
		
	
		
			
			|  | 201 | +	int rc;
 | 
		
	
		
			
			|  | 202 | +
 | 
		
	
		
			
			|  | 203 | +	/* Check for and acknowledge interrupts */
 | 
		
	
		
			
			|  | 204 | +	eicr = readl ( intel->regs + INTELXVF_EICR );
 | 
		
	
		
			
			|  | 205 | +	if ( ! eicr )
 | 
		
	
		
			
			|  | 206 | +		return;
 | 
		
	
		
			
			|  | 207 | +
 | 
		
	
		
			
			|  | 208 | +	/* Poll for TX completions, if applicable */
 | 
		
	
		
			
			|  | 209 | +	if ( eicr & INTELXVF_EIRQ_TX0 )
 | 
		
	
		
			
			|  | 210 | +		intel_poll_tx ( netdev );
 | 
		
	
		
			
			|  | 211 | +
 | 
		
	
		
			
			|  | 212 | +	/* Poll for RX completions, if applicable */
 | 
		
	
		
			
			|  | 213 | +	if ( eicr & INTELXVF_EIRQ_RX0 )
 | 
		
	
		
			
			|  | 214 | +		intel_poll_rx ( netdev );
 | 
		
	
		
			
			|  | 215 | +
 | 
		
	
		
			
			|  | 216 | +	/* Poll for mailbox messages, if applicable */
 | 
		
	
		
			
			|  | 217 | +	if ( eicr & INTELXVF_EIRQ_MBOX ) {
 | 
		
	
		
			
			|  | 218 | +
 | 
		
	
		
			
			|  | 219 | +		/* Poll mailbox */
 | 
		
	
		
			
			|  | 220 | +		if ( ( rc = intelvf_mbox_poll ( intel ) ) != 0 ) {
 | 
		
	
		
			
			|  | 221 | +			DBGC ( intel, "INTEL %p mailbox poll failed!\n",
 | 
		
	
		
			
			|  | 222 | +			       intel );
 | 
		
	
		
			
			|  | 223 | +			netdev_rx_err ( netdev, NULL, rc );
 | 
		
	
		
			
			|  | 224 | +		}
 | 
		
	
		
			
			|  | 225 | +
 | 
		
	
		
			
			|  | 226 | +		/* Update link state */
 | 
		
	
		
			
			|  | 227 | +		intelxvf_check_link ( netdev );
 | 
		
	
		
			
			|  | 228 | +	}
 | 
		
	
		
			
			|  | 229 | +
 | 
		
	
		
			
			|  | 230 | +	/* Refill RX ring */
 | 
		
	
		
			
			|  | 231 | +	intel_refill_rx ( intel );
 | 
		
	
		
			
			|  | 232 | +}
 | 
		
	
		
			
			|  | 233 | +
 | 
		
	
		
			
			|  | 234 | +/**
 | 
		
	
		
			
			|  | 235 | + * Enable or disable interrupts
 | 
		
	
		
			
			|  | 236 | + *
 | 
		
	
		
			
			|  | 237 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 238 | + * @v enable		Interrupts should be enabled
 | 
		
	
		
			
			|  | 239 | + */
 | 
		
	
		
			
			|  | 240 | +static void intelxvf_irq ( struct net_device *netdev, int enable ) {
 | 
		
	
		
			
			|  | 241 | +	struct intel_nic *intel = netdev->priv;
 | 
		
	
		
			
			|  | 242 | +	uint32_t mask;
 | 
		
	
		
			
			|  | 243 | +
 | 
		
	
		
			
			|  | 244 | +	mask = ( INTELXVF_EIRQ_MBOX | INTELXVF_EIRQ_TX0 | INTELXVF_EIRQ_RX0 );
 | 
		
	
		
			
			|  | 245 | +	if ( enable ) {
 | 
		
	
		
			
			|  | 246 | +		writel ( mask, intel->regs + INTELXVF_EIMS );
 | 
		
	
		
			
			|  | 247 | +	} else {
 | 
		
	
		
			
			|  | 248 | +		writel ( mask, intel->regs + INTELXVF_EIMC );
 | 
		
	
		
			
			|  | 249 | +	}
 | 
		
	
		
			
			|  | 250 | +}
 | 
		
	
		
			
			|  | 251 | +
 | 
		
	
		
			
			|  | 252 | +/** Network device operations */
 | 
		
	
		
			
			|  | 253 | +static struct net_device_operations intelxvf_operations = {
 | 
		
	
		
			
			|  | 254 | +	.open		= intelxvf_open,
 | 
		
	
		
			
			|  | 255 | +	.close		= intelxvf_close,
 | 
		
	
		
			
			|  | 256 | +	.transmit	= intel_transmit,
 | 
		
	
		
			
			|  | 257 | +	.poll		= intelxvf_poll,
 | 
		
	
		
			
			|  | 258 | +	.irq		= intelxvf_irq,
 | 
		
	
		
			
			|  | 259 | +};
 | 
		
	
		
			
			|  | 260 | +
 | 
		
	
		
			
			|  | 261 | +/******************************************************************************
 | 
		
	
		
			
			|  | 262 | + *
 | 
		
	
		
			
			|  | 263 | + * PCI interface
 | 
		
	
		
			
			|  | 264 | + *
 | 
		
	
		
			
			|  | 265 | + ******************************************************************************
 | 
		
	
		
			
			|  | 266 | + */
 | 
		
	
		
			
			|  | 267 | +
 | 
		
	
		
			
			|  | 268 | +/**
 | 
		
	
		
			
			|  | 269 | + * Probe PCI device
 | 
		
	
		
			
			|  | 270 | + *
 | 
		
	
		
			
			|  | 271 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 272 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 273 | + */
 | 
		
	
		
			
			|  | 274 | +static int intelxvf_probe ( struct pci_device *pci ) {
 | 
		
	
		
			
			|  | 275 | +	struct net_device *netdev;
 | 
		
	
		
			
			|  | 276 | +	struct intel_nic *intel;
 | 
		
	
		
			
			|  | 277 | +	int rc;
 | 
		
	
		
			
			|  | 278 | +
 | 
		
	
		
			
			|  | 279 | +	/* Allocate and initialise net device */
 | 
		
	
		
			
			|  | 280 | +	netdev = alloc_etherdev ( sizeof ( *intel ) );
 | 
		
	
		
			
			|  | 281 | +	if ( ! netdev ) {
 | 
		
	
		
			
			|  | 282 | +		rc = -ENOMEM;
 | 
		
	
		
			
			|  | 283 | +		goto err_alloc;
 | 
		
	
		
			
			|  | 284 | +	}
 | 
		
	
		
			
			|  | 285 | +	netdev_init ( netdev, &intelxvf_operations );
 | 
		
	
		
			
			|  | 286 | +	intel = netdev->priv;
 | 
		
	
		
			
			|  | 287 | +	pci_set_drvdata ( pci, netdev );
 | 
		
	
		
			
			|  | 288 | +	netdev->dev = &pci->dev;
 | 
		
	
		
			
			|  | 289 | +	memset ( intel, 0, sizeof ( *intel ) );
 | 
		
	
		
			
			|  | 290 | +	intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM );
 | 
		
	
		
			
			|  | 291 | +	intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELXVF_TD,
 | 
		
	
		
			
			|  | 292 | +			  intel_describe_tx_adv );
 | 
		
	
		
			
			|  | 293 | +	intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELXVF_RD,
 | 
		
	
		
			
			|  | 294 | +			  intel_describe_rx );
 | 
		
	
		
			
			|  | 295 | +
 | 
		
	
		
			
			|  | 296 | +	/* Fix up PCI device */
 | 
		
	
		
			
			|  | 297 | +	adjust_pci_device ( pci );
 | 
		
	
		
			
			|  | 298 | +
 | 
		
	
		
			
			|  | 299 | +	/* Map registers */
 | 
		
	
		
			
			|  | 300 | +	intel->regs = ioremap ( pci->membase, INTELVF_BAR_SIZE );
 | 
		
	
		
			
			|  | 301 | +	if ( ! intel->regs ) {
 | 
		
	
		
			
			|  | 302 | +		rc = -ENODEV;
 | 
		
	
		
			
			|  | 303 | +		goto err_ioremap;
 | 
		
	
		
			
			|  | 304 | +	}
 | 
		
	
		
			
			|  | 305 | +
 | 
		
	
		
			
			|  | 306 | +	/* Reset the function */
 | 
		
	
		
			
			|  | 307 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 308 | +
 | 
		
	
		
			
			|  | 309 | +	/* Send reset message and fetch MAC address */
 | 
		
	
		
			
			|  | 310 | +	if ( ( rc = intelvf_mbox_reset ( intel, netdev->hw_addr ) ) != 0 ) {
 | 
		
	
		
			
			|  | 311 | +		DBGC ( intel, "INTEL %p could not reset and fetch MAC: %s\n",
 | 
		
	
		
			
			|  | 312 | +		       intel, strerror ( rc ) );
 | 
		
	
		
			
			|  | 313 | +		goto err_mbox_reset;
 | 
		
	
		
			
			|  | 314 | +	}
 | 
		
	
		
			
			|  | 315 | +
 | 
		
	
		
			
			|  | 316 | +	/* Reset the function (since we will not respond to Control
 | 
		
	
		
			
			|  | 317 | +	 * ("ping") mailbox messages until the network device is opened.
 | 
		
	
		
			
			|  | 318 | +	 */
 | 
		
	
		
			
			|  | 319 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 320 | +
 | 
		
	
		
			
			|  | 321 | +	/* Register network device */
 | 
		
	
		
			
			|  | 322 | +	if ( ( rc = register_netdev ( netdev ) ) != 0 )
 | 
		
	
		
			
			|  | 323 | +		goto err_register_netdev;
 | 
		
	
		
			
			|  | 324 | +
 | 
		
	
		
			
			|  | 325 | +	/* Set initial link state */
 | 
		
	
		
			
			|  | 326 | +	intelxvf_check_link ( netdev );
 | 
		
	
		
			
			|  | 327 | +
 | 
		
	
		
			
			|  | 328 | +	return 0;
 | 
		
	
		
			
			|  | 329 | +
 | 
		
	
		
			
			|  | 330 | +	unregister_netdev ( netdev );
 | 
		
	
		
			
			|  | 331 | + err_register_netdev:
 | 
		
	
		
			
			|  | 332 | + err_mbox_reset:
 | 
		
	
		
			
			|  | 333 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 334 | +	iounmap ( intel->regs );
 | 
		
	
		
			
			|  | 335 | + err_ioremap:
 | 
		
	
		
			
			|  | 336 | +	netdev_nullify ( netdev );
 | 
		
	
		
			
			|  | 337 | +	netdev_put ( netdev );
 | 
		
	
		
			
			|  | 338 | + err_alloc:
 | 
		
	
		
			
			|  | 339 | +	return rc;
 | 
		
	
		
			
			|  | 340 | +}
 | 
		
	
		
			
			|  | 341 | +
 | 
		
	
		
			
			|  | 342 | +/**
 | 
		
	
		
			
			|  | 343 | + * Remove PCI device
 | 
		
	
		
			
			|  | 344 | + *
 | 
		
	
		
			
			|  | 345 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 346 | + */
 | 
		
	
		
			
			|  | 347 | +static void intelxvf_remove ( struct pci_device *pci ) {
 | 
		
	
		
			
			|  | 348 | +	struct net_device *netdev = pci_get_drvdata ( pci );
 | 
		
	
		
			
			|  | 349 | +	struct intel_nic *intel = netdev->priv;
 | 
		
	
		
			
			|  | 350 | +
 | 
		
	
		
			
			|  | 351 | +	/* Unregister network device */
 | 
		
	
		
			
			|  | 352 | +	unregister_netdev ( netdev );
 | 
		
	
		
			
			|  | 353 | +
 | 
		
	
		
			
			|  | 354 | +	/* Reset the NIC */
 | 
		
	
		
			
			|  | 355 | +	intelxvf_reset ( intel );
 | 
		
	
		
			
			|  | 356 | +
 | 
		
	
		
			
			|  | 357 | +	/* Free network device */
 | 
		
	
		
			
			|  | 358 | +	iounmap ( intel->regs );
 | 
		
	
		
			
			|  | 359 | +	netdev_nullify ( netdev );
 | 
		
	
		
			
			|  | 360 | +	netdev_put ( netdev );
 | 
		
	
		
			
			|  | 361 | +}
 | 
		
	
		
			
			|  | 362 | +
 | 
		
	
		
			
			|  | 363 | +/** PCI device IDs */
 | 
		
	
		
			
			|  | 364 | +static struct pci_device_id intelxvf_nics[] = {
 | 
		
	
		
			
			|  | 365 | +	PCI_ROM ( 0x8086, 0x10ed, "82599-vf", "82599 VF", 0 ),
 | 
		
	
		
			
			|  | 366 | +	PCI_ROM ( 0x8086, 0x1515, "x540-vf", "X540 VF", 0 ),
 | 
		
	
		
			
			|  | 367 | +	PCI_ROM ( 0x8086, 0x1565, "x550-vf", "X550 VF", 0 ),
 | 
		
	
		
			
			|  | 368 | +	PCI_ROM ( 0x8086, 0x15a8, "x552-vf", "X552 VF", 0 ),
 | 
		
	
		
			
			|  | 369 | +};
 | 
		
	
		
			
			|  | 370 | +
 | 
		
	
		
			
			|  | 371 | +/** PCI driver */
 | 
		
	
		
			
			|  | 372 | +struct pci_driver intelxvf_driver __pci_driver = {
 | 
		
	
		
			
			|  | 373 | +	.ids = intelxvf_nics,
 | 
		
	
		
			
			|  | 374 | +	.id_count = ( sizeof ( intelxvf_nics ) / sizeof ( intelxvf_nics[0] ) ),
 | 
		
	
		
			
			|  | 375 | +	.probe = intelxvf_probe,
 | 
		
	
		
			
			|  | 376 | +	.remove = intelxvf_remove,
 | 
		
	
		
			
			|  | 377 | +};
 |