|  | @@ -89,6 +89,12 @@ struct virtnet_nic {
 | 
		
	
		
			
			| 89 | 89 |  	/** Base pio register address */
 | 
		
	
		
			
			| 90 | 90 |  	unsigned long ioaddr;
 | 
		
	
		
			
			| 91 | 91 |  
 | 
		
	
		
			
			|  | 92 | +	/** 0 for legacy, 1 for virtio 1.0 */
 | 
		
	
		
			
			|  | 93 | +	int virtio_version;
 | 
		
	
		
			
			|  | 94 | +
 | 
		
	
		
			
			|  | 95 | +	/** Virtio 1.0 device data */
 | 
		
	
		
			
			|  | 96 | +	struct virtio_pci_modern_device vdev;
 | 
		
	
		
			
			|  | 97 | +
 | 
		
	
		
			
			| 92 | 98 |  	/** RX/TX virtqueues */
 | 
		
	
		
			
			| 93 | 99 |  	struct vring_virtqueue *virtqueue;
 | 
		
	
		
			
			| 94 | 100 |  
 | 
		
	
	
		
			
			|  | @@ -99,7 +105,7 @@ struct virtnet_nic {
 | 
		
	
		
			
			| 99 | 105 |  	unsigned int rx_num_iobufs;
 | 
		
	
		
			
			| 100 | 106 |  
 | 
		
	
		
			
			| 101 | 107 |  	/** Virtio net packet header, we only need one */
 | 
		
	
		
			
			| 102 |  | -	struct virtio_net_hdr empty_header;
 | 
		
	
		
			
			|  | 108 | +	struct virtio_net_hdr_modern empty_header;
 | 
		
	
		
			
			| 103 | 109 |  };
 | 
		
	
		
			
			| 104 | 110 |  
 | 
		
	
		
			
			| 105 | 111 |  /** Add an iobuf to a virtqueue
 | 
		
	
	
		
			
			|  | @@ -116,6 +122,9 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
 | 
		
	
		
			
			| 116 | 122 |  	struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx];
 | 
		
	
		
			
			| 117 | 123 |  	unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0;
 | 
		
	
		
			
			| 118 | 124 |  	unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2;
 | 
		
	
		
			
			|  | 125 | +	size_t header_len = virtnet->virtio_version
 | 
		
	
		
			
			|  | 126 | +		? sizeof ( virtnet->empty_header )
 | 
		
	
		
			
			|  | 127 | +		: sizeof ( virtnet->empty_header.legacy );
 | 
		
	
		
			
			| 119 | 128 |  	struct vring_list list[] = {
 | 
		
	
		
			
			| 120 | 129 |  		{
 | 
		
	
		
			
			| 121 | 130 |  			/* Share a single zeroed virtio net header between all
 | 
		
	
	
		
			
			|  | @@ -124,7 +133,7 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
 | 
		
	
		
			
			| 124 | 133 |  			 * header fields get used.
 | 
		
	
		
			
			| 125 | 134 |  			 */
 | 
		
	
		
			
			| 126 | 135 |  			.addr = ( char* ) &virtnet->empty_header,
 | 
		
	
		
			
			| 127 |  | -			.length = sizeof ( virtnet->empty_header ),
 | 
		
	
		
			
			|  | 136 | +			.length = header_len,
 | 
		
	
		
			
			| 128 | 137 |  		},
 | 
		
	
		
			
			| 129 | 138 |  		{
 | 
		
	
		
			
			| 130 | 139 |  			.addr = ( char* ) iobuf->data,
 | 
		
	
	
		
			
			|  | @@ -136,7 +145,8 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
 | 
		
	
		
			
			| 136 | 145 |  		virtnet, iobuf, vq_idx );
 | 
		
	
		
			
			| 137 | 146 |  
 | 
		
	
		
			
			| 138 | 147 |  	vring_add_buf ( vq, list, out, in, iobuf, 0 );
 | 
		
	
		
			
			| 139 |  | -	vring_kick ( NULL, virtnet->ioaddr, vq, 1 );
 | 
		
	
		
			
			|  | 148 | +	vring_kick ( virtnet->virtio_version ? &virtnet->vdev : NULL,
 | 
		
	
		
			
			|  | 149 | +		     virtnet->ioaddr, vq, 1 );
 | 
		
	
		
			
			| 140 | 150 |  }
 | 
		
	
		
			
			| 141 | 151 |  
 | 
		
	
		
			
			| 142 | 152 |  /** Try to keep rx virtqueue filled with iobufs
 | 
		
	
	
		
			
			|  | @@ -165,12 +175,12 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 165 | 175 |  	}
 | 
		
	
		
			
			| 166 | 176 |  }
 | 
		
	
		
			
			| 167 | 177 |  
 | 
		
	
		
			
			| 168 |  | -/** Open network device
 | 
		
	
		
			
			|  | 178 | +/** Open network device, legacy virtio 0.9.5
 | 
		
	
		
			
			| 169 | 179 |   *
 | 
		
	
		
			
			| 170 | 180 |   * @v netdev	Network device
 | 
		
	
		
			
			| 171 | 181 |   * @ret rc	Return status code
 | 
		
	
		
			
			| 172 | 182 |   */
 | 
		
	
		
			
			| 173 |  | -static int virtnet_open ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 183 | +static int virtnet_open_legacy ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 174 | 184 |  	struct virtnet_nic *virtnet = netdev->priv;
 | 
		
	
		
			
			| 175 | 185 |  	unsigned long ioaddr = virtnet->ioaddr;
 | 
		
	
		
			
			| 176 | 186 |  	u32 features;
 | 
		
	
	
		
			
			|  | @@ -211,6 +221,81 @@ static int virtnet_open ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 211 | 221 |  	return 0;
 | 
		
	
		
			
			| 212 | 222 |  }
 | 
		
	
		
			
			| 213 | 223 |  
 | 
		
	
		
			
			|  | 224 | +/** Open network device, modern virtio 1.0
 | 
		
	
		
			
			|  | 225 | + *
 | 
		
	
		
			
			|  | 226 | + * @v netdev	Network device
 | 
		
	
		
			
			|  | 227 | + * @ret rc	Return status code
 | 
		
	
		
			
			|  | 228 | + */
 | 
		
	
		
			
			|  | 229 | +static int virtnet_open_modern ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 230 | +	struct virtnet_nic *virtnet = netdev->priv;
 | 
		
	
		
			
			|  | 231 | +	u64 features;
 | 
		
	
		
			
			|  | 232 | +	u8 status;
 | 
		
	
		
			
			|  | 233 | +
 | 
		
	
		
			
			|  | 234 | +	/* Negotiate features */
 | 
		
	
		
			
			|  | 235 | +	features = vpm_get_features ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 236 | +	if ( ! ( features & VIRTIO_F_VERSION_1 ) ) {
 | 
		
	
		
			
			|  | 237 | +		vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FAILED );
 | 
		
	
		
			
			|  | 238 | +		return -EINVAL;
 | 
		
	
		
			
			|  | 239 | +	}
 | 
		
	
		
			
			|  | 240 | +	vpm_set_features ( &virtnet->vdev, features & (
 | 
		
	
		
			
			|  | 241 | +		( 1ULL << VIRTIO_NET_F_MAC ) |
 | 
		
	
		
			
			|  | 242 | +		( 1ULL << VIRTIO_F_VERSION_1 ) |
 | 
		
	
		
			
			|  | 243 | +		( 1ULL << VIRTIO_F_ANY_LAYOUT ) ) );
 | 
		
	
		
			
			|  | 244 | +	vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FEATURES_OK );
 | 
		
	
		
			
			|  | 245 | +
 | 
		
	
		
			
			|  | 246 | +	status = vpm_get_status ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 247 | +	if ( ! ( status & VIRTIO_CONFIG_S_FEATURES_OK ) ) {
 | 
		
	
		
			
			|  | 248 | +		DBGC ( virtnet, "VIRTIO-NET %p device didn't accept features\n",
 | 
		
	
		
			
			|  | 249 | +		       virtnet );
 | 
		
	
		
			
			|  | 250 | +		vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FAILED );
 | 
		
	
		
			
			|  | 251 | +		return -EINVAL;
 | 
		
	
		
			
			|  | 252 | +	}
 | 
		
	
		
			
			|  | 253 | +
 | 
		
	
		
			
			|  | 254 | +	/* Allocate virtqueues */
 | 
		
	
		
			
			|  | 255 | +	virtnet->virtqueue = zalloc ( QUEUE_NB *
 | 
		
	
		
			
			|  | 256 | +				      sizeof ( *virtnet->virtqueue ) );
 | 
		
	
		
			
			|  | 257 | +	if ( ! virtnet->virtqueue ) {
 | 
		
	
		
			
			|  | 258 | +		vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FAILED );
 | 
		
	
		
			
			|  | 259 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 260 | +	}
 | 
		
	
		
			
			|  | 261 | +
 | 
		
	
		
			
			|  | 262 | +	/* Initialize rx/tx virtqueues */
 | 
		
	
		
			
			|  | 263 | +	if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) {
 | 
		
	
		
			
			|  | 264 | +		DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n",
 | 
		
	
		
			
			|  | 265 | +		       virtnet );
 | 
		
	
		
			
			|  | 266 | +		free ( virtnet->virtqueue );
 | 
		
	
		
			
			|  | 267 | +		virtnet->virtqueue = NULL;
 | 
		
	
		
			
			|  | 268 | +		vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FAILED );
 | 
		
	
		
			
			|  | 269 | +		return -ENOENT;
 | 
		
	
		
			
			|  | 270 | +	}
 | 
		
	
		
			
			|  | 271 | +
 | 
		
	
		
			
			|  | 272 | +	/* Disable interrupts before starting */
 | 
		
	
		
			
			|  | 273 | +	netdev_irq ( netdev, 0 );
 | 
		
	
		
			
			|  | 274 | +
 | 
		
	
		
			
			|  | 275 | +	vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_DRIVER_OK );
 | 
		
	
		
			
			|  | 276 | +
 | 
		
	
		
			
			|  | 277 | +	/* Initialize rx packets */
 | 
		
	
		
			
			|  | 278 | +	INIT_LIST_HEAD ( &virtnet->rx_iobufs );
 | 
		
	
		
			
			|  | 279 | +	virtnet->rx_num_iobufs = 0;
 | 
		
	
		
			
			|  | 280 | +	virtnet_refill_rx_virtqueue ( netdev );
 | 
		
	
		
			
			|  | 281 | +	return 0;
 | 
		
	
		
			
			|  | 282 | +}
 | 
		
	
		
			
			|  | 283 | +
 | 
		
	
		
			
			|  | 284 | +/** Open network device
 | 
		
	
		
			
			|  | 285 | + *
 | 
		
	
		
			
			|  | 286 | + * @v netdev	Network device
 | 
		
	
		
			
			|  | 287 | + * @ret rc	Return status code
 | 
		
	
		
			
			|  | 288 | + */
 | 
		
	
		
			
			|  | 289 | +static int virtnet_open ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 290 | +	struct virtnet_nic *virtnet = netdev->priv;
 | 
		
	
		
			
			|  | 291 | +
 | 
		
	
		
			
			|  | 292 | +	if ( virtnet->virtio_version ) {
 | 
		
	
		
			
			|  | 293 | +		return virtnet_open_modern ( netdev );
 | 
		
	
		
			
			|  | 294 | +	} else {
 | 
		
	
		
			
			|  | 295 | +		return virtnet_open_legacy ( netdev );
 | 
		
	
		
			
			|  | 296 | +	}
 | 
		
	
		
			
			|  | 297 | +}
 | 
		
	
		
			
			|  | 298 | +
 | 
		
	
		
			
			| 214 | 299 |  /** Close network device
 | 
		
	
		
			
			| 215 | 300 |   *
 | 
		
	
		
			
			| 216 | 301 |   * @v netdev	Network device
 | 
		
	
	
		
			
			|  | @@ -219,10 +304,19 @@ static void virtnet_close ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 219 | 304 |  	struct virtnet_nic *virtnet = netdev->priv;
 | 
		
	
		
			
			| 220 | 305 |  	struct io_buffer *iobuf;
 | 
		
	
		
			
			| 221 | 306 |  	struct io_buffer *next_iobuf;
 | 
		
	
		
			
			|  | 307 | +	int i;
 | 
		
	
		
			
			| 222 | 308 |  
 | 
		
	
		
			
			| 223 |  | -	vp_reset ( virtnet->ioaddr );
 | 
		
	
		
			
			|  | 309 | +	if ( virtnet->virtio_version ) {
 | 
		
	
		
			
			|  | 310 | +		vpm_reset ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 311 | +	} else {
 | 
		
	
		
			
			|  | 312 | +		vp_reset ( virtnet->ioaddr );
 | 
		
	
		
			
			|  | 313 | +	}
 | 
		
	
		
			
			| 224 | 314 |  
 | 
		
	
		
			
			| 225 | 315 |  	/* Virtqueues can be freed now that NIC is reset */
 | 
		
	
		
			
			|  | 316 | +	for ( i = 0 ; i < QUEUE_NB ; i++ ) {
 | 
		
	
		
			
			|  | 317 | +		virtio_pci_unmap_capability ( &virtnet->virtqueue[i].notification );
 | 
		
	
		
			
			|  | 318 | +	}
 | 
		
	
		
			
			|  | 319 | +
 | 
		
	
		
			
			| 226 | 320 |  	free ( virtnet->virtqueue );
 | 
		
	
		
			
			| 227 | 321 |  	virtnet->virtqueue = NULL;
 | 
		
	
		
			
			| 228 | 322 |  
 | 
		
	
	
		
			
			|  | @@ -303,10 +397,14 @@ static void virtnet_poll ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 303 | 397 |  
 | 
		
	
		
			
			| 304 | 398 |  	/* Acknowledge interrupt.  This is necessary for UNDI operation and
 | 
		
	
		
			
			| 305 | 399 |  	 * interrupts that are raised despite VRING_AVAIL_F_NO_INTERRUPT being
 | 
		
	
		
			
			| 306 |  | -	 * set (that flag is just a hint and the hypervisor not not have to
 | 
		
	
		
			
			|  | 400 | +	 * set (that flag is just a hint and the hypervisor does not have to
 | 
		
	
		
			
			| 307 | 401 |  	 * honor it).
 | 
		
	
		
			
			| 308 | 402 |  	 */
 | 
		
	
		
			
			| 309 |  | -	vp_get_isr ( virtnet->ioaddr );
 | 
		
	
		
			
			|  | 403 | +	if ( virtnet->virtio_version ) {
 | 
		
	
		
			
			|  | 404 | +		vpm_get_isr ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 405 | +	} else {
 | 
		
	
		
			
			|  | 406 | +		vp_get_isr ( virtnet->ioaddr );
 | 
		
	
		
			
			|  | 407 | +	}
 | 
		
	
		
			
			| 310 | 408 |  
 | 
		
	
		
			
			| 311 | 409 |  	virtnet_process_tx_packets ( netdev );
 | 
		
	
		
			
			| 312 | 410 |  	virtnet_process_rx_packets ( netdev );
 | 
		
	
	
		
			
			|  | @@ -339,13 +437,12 @@ static struct net_device_operations virtnet_operations = {
 | 
		
	
		
			
			| 339 | 437 |  };
 | 
		
	
		
			
			| 340 | 438 |  
 | 
		
	
		
			
			| 341 | 439 |  /**
 | 
		
	
		
			
			| 342 |  | - * Probe PCI device
 | 
		
	
		
			
			|  | 440 | + * Probe PCI device, legacy virtio 0.9.5
 | 
		
	
		
			
			| 343 | 441 |   *
 | 
		
	
		
			
			| 344 | 442 |   * @v pci	PCI device
 | 
		
	
		
			
			| 345 |  | - * @v id	PCI ID
 | 
		
	
		
			
			| 346 | 443 |   * @ret rc	Return status code
 | 
		
	
		
			
			| 347 | 444 |   */
 | 
		
	
		
			
			| 348 |  | -static int virtnet_probe ( struct pci_device *pci ) {
 | 
		
	
		
			
			|  | 445 | +static int virtnet_probe_legacy ( struct pci_device *pci ) {
 | 
		
	
		
			
			| 349 | 446 |  	unsigned long ioaddr = pci->ioaddr;
 | 
		
	
		
			
			| 350 | 447 |  	struct net_device *netdev;
 | 
		
	
		
			
			| 351 | 448 |  	struct virtnet_nic *virtnet;
 | 
		
	
	
		
			
			|  | @@ -395,6 +492,143 @@ static int virtnet_probe ( struct pci_device *pci ) {
 | 
		
	
		
			
			| 395 | 492 |  	return rc;
 | 
		
	
		
			
			| 396 | 493 |  }
 | 
		
	
		
			
			| 397 | 494 |  
 | 
		
	
		
			
			|  | 495 | +/**
 | 
		
	
		
			
			|  | 496 | + * Probe PCI device, modern virtio 1.0
 | 
		
	
		
			
			|  | 497 | + *
 | 
		
	
		
			
			|  | 498 | + * @v pci	PCI device
 | 
		
	
		
			
			|  | 499 | + * @v found_dev	Set to non-zero if modern device was found (probe may still fail)
 | 
		
	
		
			
			|  | 500 | + * @ret rc	Return status code
 | 
		
	
		
			
			|  | 501 | + */
 | 
		
	
		
			
			|  | 502 | +static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
 | 
		
	
		
			
			|  | 503 | +	struct net_device *netdev;
 | 
		
	
		
			
			|  | 504 | +	struct virtnet_nic *virtnet;
 | 
		
	
		
			
			|  | 505 | +	u64 features;
 | 
		
	
		
			
			|  | 506 | +	int rc, common, isr, notify, config, device;
 | 
		
	
		
			
			|  | 507 | +
 | 
		
	
		
			
			|  | 508 | +	common = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_COMMON_CFG );
 | 
		
	
		
			
			|  | 509 | +	if ( ! common ) {
 | 
		
	
		
			
			|  | 510 | +		DBG ( "Common virtio capability not found!\n" );
 | 
		
	
		
			
			|  | 511 | +		return -ENODEV;
 | 
		
	
		
			
			|  | 512 | +	}
 | 
		
	
		
			
			|  | 513 | +	*found_dev = 1;
 | 
		
	
		
			
			|  | 514 | +
 | 
		
	
		
			
			|  | 515 | +	isr = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_ISR_CFG );
 | 
		
	
		
			
			|  | 516 | +	notify = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_NOTIFY_CFG );
 | 
		
	
		
			
			|  | 517 | +	config = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_PCI_CFG );
 | 
		
	
		
			
			|  | 518 | +	if ( ! isr || ! notify || ! config ) {
 | 
		
	
		
			
			|  | 519 | +		DBG ( "Missing virtio capabilities %i/%i/%i/%i\n",
 | 
		
	
		
			
			|  | 520 | +		      common, isr, notify, config );
 | 
		
	
		
			
			|  | 521 | +		return -EINVAL;
 | 
		
	
		
			
			|  | 522 | +	}
 | 
		
	
		
			
			|  | 523 | +	device = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_DEVICE_CFG );
 | 
		
	
		
			
			|  | 524 | +
 | 
		
	
		
			
			|  | 525 | +	/* Allocate and hook up net device */
 | 
		
	
		
			
			|  | 526 | +	netdev = alloc_etherdev ( sizeof ( *virtnet ) );
 | 
		
	
		
			
			|  | 527 | +	if ( ! netdev )
 | 
		
	
		
			
			|  | 528 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 529 | +	netdev_init ( netdev, &virtnet_operations );
 | 
		
	
		
			
			|  | 530 | +	virtnet = netdev->priv;
 | 
		
	
		
			
			|  | 531 | +
 | 
		
	
		
			
			|  | 532 | +	pci_set_drvdata ( pci, netdev );
 | 
		
	
		
			
			|  | 533 | +	netdev->dev = &pci->dev;
 | 
		
	
		
			
			|  | 534 | +
 | 
		
	
		
			
			|  | 535 | +	DBGC ( virtnet, "VIRTIO-NET modern %p busaddr=%s irq=%d\n",
 | 
		
	
		
			
			|  | 536 | +	       virtnet, pci->dev.name, pci->irq );
 | 
		
	
		
			
			|  | 537 | +
 | 
		
	
		
			
			|  | 538 | +	virtnet->vdev.pci = pci;
 | 
		
	
		
			
			|  | 539 | +	rc = virtio_pci_map_capability ( pci, common,
 | 
		
	
		
			
			|  | 540 | +		sizeof ( struct virtio_pci_common_cfg ), 4,
 | 
		
	
		
			
			|  | 541 | +		0, sizeof ( struct virtio_pci_common_cfg ),
 | 
		
	
		
			
			|  | 542 | +		&virtnet->vdev.common );
 | 
		
	
		
			
			|  | 543 | +	if ( rc )
 | 
		
	
		
			
			|  | 544 | +		goto err_map_common;
 | 
		
	
		
			
			|  | 545 | +
 | 
		
	
		
			
			|  | 546 | +	rc = virtio_pci_map_capability ( pci, isr, sizeof ( u8 ), 1,
 | 
		
	
		
			
			|  | 547 | +		0, 1,
 | 
		
	
		
			
			|  | 548 | +		&virtnet->vdev.isr );
 | 
		
	
		
			
			|  | 549 | +	if ( rc )
 | 
		
	
		
			
			|  | 550 | +		goto err_map_isr;
 | 
		
	
		
			
			|  | 551 | +
 | 
		
	
		
			
			|  | 552 | +	virtnet->vdev.notify_cap_pos = notify;
 | 
		
	
		
			
			|  | 553 | +	virtnet->vdev.cfg_cap_pos = config;
 | 
		
	
		
			
			|  | 554 | +
 | 
		
	
		
			
			|  | 555 | +	/* Map the device capability */
 | 
		
	
		
			
			|  | 556 | +	if ( device ) {
 | 
		
	
		
			
			|  | 557 | +		rc = virtio_pci_map_capability ( pci, device,
 | 
		
	
		
			
			|  | 558 | +			0, 4, 0, sizeof ( struct virtio_net_config ),
 | 
		
	
		
			
			|  | 559 | +			&virtnet->vdev.device );
 | 
		
	
		
			
			|  | 560 | +		if ( rc )
 | 
		
	
		
			
			|  | 561 | +			goto err_map_device;
 | 
		
	
		
			
			|  | 562 | +	}
 | 
		
	
		
			
			|  | 563 | +
 | 
		
	
		
			
			|  | 564 | +	/* Enable the PCI device */
 | 
		
	
		
			
			|  | 565 | +	adjust_pci_device ( pci );
 | 
		
	
		
			
			|  | 566 | +
 | 
		
	
		
			
			|  | 567 | +	/* Reset the device and set initial status bits */
 | 
		
	
		
			
			|  | 568 | +	vpm_reset ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 569 | +	vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE );
 | 
		
	
		
			
			|  | 570 | +	vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_DRIVER );
 | 
		
	
		
			
			|  | 571 | +
 | 
		
	
		
			
			|  | 572 | +	/* Load MAC address */
 | 
		
	
		
			
			|  | 573 | +	if ( device ) {
 | 
		
	
		
			
			|  | 574 | +		features = vpm_get_features ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 575 | +		if ( features & ( 1ULL << VIRTIO_NET_F_MAC ) ) {
 | 
		
	
		
			
			|  | 576 | +			vpm_get ( &virtnet->vdev,
 | 
		
	
		
			
			|  | 577 | +				  offsetof ( struct virtio_net_config, mac ),
 | 
		
	
		
			
			|  | 578 | +				  netdev->hw_addr, ETH_ALEN );
 | 
		
	
		
			
			|  | 579 | +			DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet,
 | 
		
	
		
			
			|  | 580 | +			       eth_ntoa ( netdev->hw_addr ) );
 | 
		
	
		
			
			|  | 581 | +		}
 | 
		
	
		
			
			|  | 582 | +	}
 | 
		
	
		
			
			|  | 583 | +
 | 
		
	
		
			
			|  | 584 | +	/* We need a valid MAC address */
 | 
		
	
		
			
			|  | 585 | +	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
 | 
		
	
		
			
			|  | 586 | +		rc = -EADDRNOTAVAIL;
 | 
		
	
		
			
			|  | 587 | +		goto err_mac_address;
 | 
		
	
		
			
			|  | 588 | +	}
 | 
		
	
		
			
			|  | 589 | +
 | 
		
	
		
			
			|  | 590 | +	/* Register network device */
 | 
		
	
		
			
			|  | 591 | +	if ( ( rc = register_netdev ( netdev ) ) != 0 )
 | 
		
	
		
			
			|  | 592 | +		goto err_register_netdev;
 | 
		
	
		
			
			|  | 593 | +
 | 
		
	
		
			
			|  | 594 | +	/* Mark link as up, control virtqueue is not used */
 | 
		
	
		
			
			|  | 595 | +	netdev_link_up ( netdev );
 | 
		
	
		
			
			|  | 596 | +
 | 
		
	
		
			
			|  | 597 | +	virtnet->virtio_version = 1;
 | 
		
	
		
			
			|  | 598 | +	return 0;
 | 
		
	
		
			
			|  | 599 | +
 | 
		
	
		
			
			|  | 600 | +	unregister_netdev ( netdev );
 | 
		
	
		
			
			|  | 601 | +err_register_netdev:
 | 
		
	
		
			
			|  | 602 | +err_mac_address:
 | 
		
	
		
			
			|  | 603 | +	vpm_reset ( &virtnet->vdev );
 | 
		
	
		
			
			|  | 604 | +	netdev_nullify ( netdev );
 | 
		
	
		
			
			|  | 605 | +	netdev_put ( netdev );
 | 
		
	
		
			
			|  | 606 | +
 | 
		
	
		
			
			|  | 607 | +	virtio_pci_unmap_capability ( &virtnet->vdev.device );
 | 
		
	
		
			
			|  | 608 | +err_map_device:
 | 
		
	
		
			
			|  | 609 | +	virtio_pci_unmap_capability ( &virtnet->vdev.isr );
 | 
		
	
		
			
			|  | 610 | +err_map_isr:
 | 
		
	
		
			
			|  | 611 | +	virtio_pci_unmap_capability ( &virtnet->vdev.common );
 | 
		
	
		
			
			|  | 612 | +err_map_common:
 | 
		
	
		
			
			|  | 613 | +	return rc;
 | 
		
	
		
			
			|  | 614 | +}
 | 
		
	
		
			
			|  | 615 | +
 | 
		
	
		
			
			|  | 616 | +/**
 | 
		
	
		
			
			|  | 617 | + * Probe PCI device
 | 
		
	
		
			
			|  | 618 | + *
 | 
		
	
		
			
			|  | 619 | + * @v pci	PCI device
 | 
		
	
		
			
			|  | 620 | + * @ret rc	Return status code
 | 
		
	
		
			
			|  | 621 | + */
 | 
		
	
		
			
			|  | 622 | +static int virtnet_probe ( struct pci_device *pci ) {
 | 
		
	
		
			
			|  | 623 | +	int found_modern = 0;
 | 
		
	
		
			
			|  | 624 | +	int rc = virtnet_probe_modern ( pci, &found_modern );
 | 
		
	
		
			
			|  | 625 | +	if ( ! found_modern && pci->device < 0x1040 ) {
 | 
		
	
		
			
			|  | 626 | +		/* fall back to the legacy probe */
 | 
		
	
		
			
			|  | 627 | +		rc = virtnet_probe_legacy ( pci );
 | 
		
	
		
			
			|  | 628 | +	}
 | 
		
	
		
			
			|  | 629 | +	return rc;
 | 
		
	
		
			
			|  | 630 | +}
 | 
		
	
		
			
			|  | 631 | +
 | 
		
	
		
			
			| 398 | 632 |  /**
 | 
		
	
		
			
			| 399 | 633 |   * Remove device
 | 
		
	
		
			
			| 400 | 634 |   *
 | 
		
	
	
		
			
			|  | @@ -402,6 +636,11 @@ static int virtnet_probe ( struct pci_device *pci ) {
 | 
		
	
		
			
			| 402 | 636 |   */
 | 
		
	
		
			
			| 403 | 637 |  static void virtnet_remove ( struct pci_device *pci ) {
 | 
		
	
		
			
			| 404 | 638 |  	struct net_device *netdev = pci_get_drvdata ( pci );
 | 
		
	
		
			
			|  | 639 | +	struct virtnet_nic *virtnet = netdev->priv;
 | 
		
	
		
			
			|  | 640 | +
 | 
		
	
		
			
			|  | 641 | +	virtio_pci_unmap_capability ( &virtnet->vdev.device );
 | 
		
	
		
			
			|  | 642 | +	virtio_pci_unmap_capability ( &virtnet->vdev.isr );
 | 
		
	
		
			
			|  | 643 | +	virtio_pci_unmap_capability ( &virtnet->vdev.common );
 | 
		
	
		
			
			| 405 | 644 |  
 | 
		
	
		
			
			| 406 | 645 |  	unregister_netdev ( netdev );
 | 
		
	
		
			
			| 407 | 646 |  	netdev_nullify ( netdev );
 | 
		
	
	
		
			
			|  | @@ -410,6 +649,7 @@ static void virtnet_remove ( struct pci_device *pci ) {
 | 
		
	
		
			
			| 410 | 649 |  
 | 
		
	
		
			
			| 411 | 650 |  static struct pci_device_id virtnet_nics[] = {
 | 
		
	
		
			
			| 412 | 651 |  PCI_ROM(0x1af4, 0x1000, "virtio-net", "Virtio Network Interface", 0),
 | 
		
	
		
			
			|  | 652 | +PCI_ROM(0x1af4, 0x1041, "virtio-net", "Virtio Network Interface 1.0", 0),
 | 
		
	
		
			
			| 413 | 653 |  };
 | 
		
	
		
			
			| 414 | 654 |  
 | 
		
	
		
			
			| 415 | 655 |  struct pci_driver virtnet_driver __pci_driver = {
 |