Explorar el Código

[xen] Add support for Xen netfront virtual NICs

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown hace 9 años
padre
commit
793a806611
Se han modificado 4 ficheros con 1009 adiciones y 0 borrados
  1. 3
    0
      src/arch/x86/drivers/xen/hvm.c
  2. 852
    0
      src/drivers/net/netfront.c
  3. 153
    0
      src/drivers/net/netfront.h
  4. 1
    0
      src/include/ipxe/errfile.h

+ 3
- 0
src/arch/x86/drivers/xen/hvm.c Ver fichero

@@ -519,3 +519,6 @@ struct pci_driver hvm_driver __pci_driver = {
519 519
 	.probe = hvm_probe,
520 520
 	.remove = hvm_remove,
521 521
 };
522
+
523
+/* Drag in netfront driver */
524
+REQUIRE_OBJECT ( netfront );

+ 852
- 0
src/drivers/net/netfront.c Ver fichero

@@ -0,0 +1,852 @@
1
+/*
2
+ * Copyright (C) 2014 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
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <errno.h>
25
+#include <ipxe/netdevice.h>
26
+#include <ipxe/ethernet.h>
27
+#include <ipxe/if_ether.h>
28
+#include <ipxe/malloc.h>
29
+#include <ipxe/base16.h>
30
+#include <ipxe/xen.h>
31
+#include <ipxe/xenstore.h>
32
+#include <ipxe/xenbus.h>
33
+#include <ipxe/xengrant.h>
34
+#include <ipxe/xenevent.h>
35
+#include "netfront.h"
36
+
37
+/** @file
38
+ *
39
+ * Xen netfront driver
40
+ *
41
+ */
42
+
43
+/* Disambiguate the various error causes */
44
+#define EIO_NETIF_RSP_ERROR						\
45
+	__einfo_error ( EINFO_EIO_NETIF_RSP_ERROR )
46
+#define EINFO_EIO_NETIF_RSP_ERROR					\
47
+	__einfo_uniqify ( EINFO_EIO, -NETIF_RSP_ERROR,			\
48
+			  "Unspecified network error" )
49
+#define EIO_NETIF_RSP_DROPPED						\
50
+	__einfo_error ( EINFO_EIO_NETIF_RSP_DROPPED )
51
+#define EINFO_EIO_NETIF_RSP_DROPPED					\
52
+	__einfo_uniqify ( EINFO_EIO, -NETIF_RSP_DROPPED,		\
53
+			  "Packet dropped" )
54
+#define EIO_NETIF_RSP( status )						\
55
+	EUNIQ ( EINFO_EIO, -(status),					\
56
+		EIO_NETIF_RSP_ERROR, EIO_NETIF_RSP_DROPPED )
57
+
58
+/******************************************************************************
59
+ *
60
+ * XenStore interface
61
+ *
62
+ ******************************************************************************
63
+ */
64
+
65
+/**
66
+ * Fetch MAC address
67
+ *
68
+ * @v netfront		Netfront device
69
+ * @v hw_addr		Hardware address to fill in
70
+ * @ret rc		Return status code
71
+ */
72
+static int netfront_read_mac ( struct netfront_nic *netfront, void *hw_addr ) {
73
+	struct xen_device *xendev = netfront->xendev;
74
+	struct xen_hypervisor *xen = xendev->xen;
75
+	char *mac;
76
+	int len;
77
+	int rc;
78
+
79
+	/* Fetch MAC address */
80
+	if ( ( rc = xenstore_read ( xen, &mac, xendev->key, "mac", NULL ) )!=0){
81
+		DBGC ( netfront, "NETFRONT %s could not read MAC address: %s\n",
82
+		       xendev->key, strerror ( rc ) );
83
+		goto err_xenstore_read;
84
+	}
85
+	DBGC2 ( netfront, "NETFRONT %s has MAC address \"%s\"\n",
86
+		xendev->key, mac );
87
+
88
+	/* Decode MAC address */
89
+	len = hex_decode ( mac, ':', hw_addr, ETH_ALEN );
90
+	if ( len < 0 ) {
91
+		rc = len;
92
+		DBGC ( netfront, "NETFRONT %s could not decode MAC address "
93
+		       "\"%s\": %s\n", xendev->key, mac, strerror ( rc ) );
94
+		goto err_decode;
95
+	}
96
+
97
+	/* Success */
98
+	rc = 0;
99
+
100
+ err_decode:
101
+	free ( mac );
102
+ err_xenstore_read:
103
+	return rc;
104
+}
105
+
106
+/**
107
+ * Write XenStore numeric value
108
+ *
109
+ * @v netfront		Netfront device
110
+ * @v subkey		Subkey
111
+ * @v num		Numeric value
112
+ * @ret rc		Return status code
113
+ */
114
+static int netfront_write_num ( struct netfront_nic *netfront,
115
+				const char *subkey, unsigned long num ) {
116
+	struct xen_device *xendev = netfront->xendev;
117
+	struct xen_hypervisor *xen = xendev->xen;
118
+	int rc;
119
+
120
+	/* Write value */
121
+	if ( ( rc = xenstore_write_num ( xen, num, xendev->key, subkey,
122
+					 NULL ) ) != 0 ) {
123
+		DBGC ( netfront, "NETFRONT %s could not set %s=\"%ld\": %s\n",
124
+		       xendev->key, subkey, num, strerror ( rc ) );
125
+		return rc;
126
+	}
127
+
128
+	return 0;
129
+}
130
+
131
+/**
132
+ * Write XenStore flag value
133
+ *
134
+ * @v netfront		Netfront device
135
+ * @v subkey		Subkey
136
+ * @v num		Numeric value
137
+ * @ret rc		Return status code
138
+ */
139
+static int netfront_write_flag ( struct netfront_nic *netfront,
140
+				 const char *subkey ) {
141
+
142
+	return netfront_write_num ( netfront, subkey, 1 );
143
+}
144
+
145
+/**
146
+ * Delete XenStore value
147
+ *
148
+ * @v netfront		Netfront device
149
+ * @v subkey		Subkey
150
+ * @ret rc		Return status code
151
+ */
152
+static int netfront_rm ( struct netfront_nic *netfront, const char *subkey ) {
153
+	struct xen_device *xendev = netfront->xendev;
154
+	struct xen_hypervisor *xen = xendev->xen;
155
+	int rc;
156
+
157
+	/* Remove value */
158
+	if ( ( rc = xenstore_rm ( xen, xendev->key, subkey, NULL ) ) != 0 ) {
159
+		DBGC ( netfront, "NETFRONT %s could not delete %s: %s\n",
160
+		       xendev->key, subkey, strerror ( rc ) );
161
+		return rc;
162
+	}
163
+
164
+	return 0;
165
+}
166
+
167
+/******************************************************************************
168
+ *
169
+ * Events
170
+ *
171
+ ******************************************************************************
172
+ */
173
+
174
+/**
175
+ * Create event channel
176
+ *
177
+ * @v netfront		Netfront device
178
+ * @ret rc		Return status code
179
+ */
180
+static int netfront_create_event ( struct netfront_nic *netfront ) {
181
+	struct xen_device *xendev = netfront->xendev;
182
+	struct xen_hypervisor *xen = xendev->xen;
183
+	struct evtchn_alloc_unbound alloc_unbound;
184
+	struct evtchn_close close;
185
+	int xenrc;
186
+	int rc;
187
+
188
+	/* Allocate event */
189
+	alloc_unbound.dom = DOMID_SELF;
190
+	alloc_unbound.remote_dom = xendev->backend_id;
191
+	if ( ( xenrc = xenevent_alloc_unbound ( xen, &alloc_unbound ) ) != 0 ) {
192
+		rc = -EXEN ( xenrc );
193
+		DBGC ( netfront, "NETFRONT %s could not allocate event: %s\n",
194
+		       xendev->key, strerror ( rc ) );
195
+		goto err_alloc_unbound;
196
+	}
197
+	netfront->event.port = alloc_unbound.port;
198
+
199
+	/* Publish event channel */
200
+	if ( ( rc = netfront_write_num ( netfront, "event-channel",
201
+					 netfront->event.port ) ) != 0 )
202
+		goto err_write_num;
203
+
204
+	DBGC ( netfront, "NETFRONT %s event-channel=\"%d\"\n",
205
+	       xendev->key, netfront->event.port );
206
+	return 0;
207
+
208
+	netfront_rm ( netfront, "event-channel" );
209
+ err_write_num:
210
+	close.port = netfront->event.port;
211
+	xenevent_close ( xen, &close );
212
+ err_alloc_unbound:
213
+	return rc;
214
+}
215
+
216
+/**
217
+ * Send event
218
+ *
219
+ * @v netfront		Netfront device
220
+ * @ret rc		Return status code
221
+ */
222
+static inline __attribute__ (( always_inline )) int
223
+netfront_send_event ( struct netfront_nic *netfront ) {
224
+	struct xen_device *xendev = netfront->xendev;
225
+	struct xen_hypervisor *xen = xendev->xen;
226
+	int xenrc;
227
+	int rc;
228
+
229
+	/* Send event */
230
+	if ( ( xenrc = xenevent_send ( xen, &netfront->event ) ) != 0 ) {
231
+		rc = -EXEN ( xenrc );
232
+		DBGC ( netfront, "NETFRONT %s could not send event: %s\n",
233
+		       xendev->key, strerror ( rc ) );
234
+		return rc;
235
+	}
236
+
237
+	return 0;
238
+}
239
+
240
+/**
241
+ * Destroy event channel
242
+ *
243
+ * @v netfront		Netfront device
244
+ */
245
+static void netfront_destroy_event ( struct netfront_nic *netfront ) {
246
+	struct xen_device *xendev = netfront->xendev;
247
+	struct xen_hypervisor *xen = xendev->xen;
248
+	struct evtchn_close close;
249
+
250
+	/* Unpublish event channel */
251
+	netfront_rm ( netfront, "event-channel" );
252
+
253
+	/* Close event channel */
254
+	close.port = netfront->event.port;
255
+	xenevent_close ( xen, &close );
256
+}
257
+
258
+/******************************************************************************
259
+ *
260
+ * Descriptor rings
261
+ *
262
+ ******************************************************************************
263
+ */
264
+
265
+/**
266
+ * Create descriptor ring
267
+ *
268
+ * @v netfront		Netfront device
269
+ * @v ring		Descriptor ring
270
+ * @ret rc		Return status code
271
+ */
272
+static int netfront_create_ring ( struct netfront_nic *netfront,
273
+				  struct netfront_ring *ring ) {
274
+	struct xen_device *xendev = netfront->xendev;
275
+	struct xen_hypervisor *xen = xendev->xen;
276
+	unsigned int i;
277
+	int rc;
278
+
279
+	/* Initialise buffer ID ring */
280
+	for ( i = 0 ; i < ring->count ; i++ ) {
281
+		ring->ids[i] = i;
282
+		assert ( ring->iobufs[i] == NULL );
283
+	}
284
+	ring->id_prod = 0;
285
+	ring->id_cons = 0;
286
+
287
+	/* Allocate and initialise shared ring */
288
+	ring->sring.raw = malloc_dma ( PAGE_SIZE, PAGE_SIZE );
289
+	if ( ! ring->sring.raw ) {
290
+		rc = -ENOMEM;
291
+		goto err_alloc;
292
+	}
293
+
294
+	/* Grant access to shared ring */
295
+	xengrant_permit_access ( xen, ring->ref, xendev->backend_id, 0,
296
+				 ring->sring.raw );
297
+
298
+	/* Publish shared ring reference */
299
+	if ( ( rc = netfront_write_num ( netfront, ring->ref_key,
300
+					 ring->ref ) ) != 0 )
301
+		goto err_write_num;
302
+
303
+	DBGC ( netfront, "NETFRONT %s %s=\"%d\" [%08lx,%08lx)\n",
304
+	       xendev->key, ring->ref_key, ring->ref,
305
+	       virt_to_phys ( ring->sring.raw ),
306
+	       ( virt_to_phys ( ring->sring.raw ) + PAGE_SIZE ) );
307
+	return 0;
308
+
309
+	netfront_rm ( netfront, ring->ref_key );
310
+ err_write_num:
311
+	xengrant_invalidate ( xen, ring->ref );
312
+	free_dma ( ring->sring.raw, PAGE_SIZE );
313
+ err_alloc:
314
+	return rc;
315
+}
316
+
317
+/**
318
+ * Add buffer to descriptor ring
319
+ *
320
+ * @v netfront		Netfront device
321
+ * @v ring		Descriptor ring
322
+ * @v iobuf		I/O buffer
323
+ * @v ref		Grant reference to fill in
324
+ * @ret id		Buffer ID
325
+ *
326
+ * The caller is responsible for ensuring that there is space in the
327
+ * ring.
328
+ */
329
+static unsigned int netfront_push ( struct netfront_nic *netfront,
330
+				    struct netfront_ring *ring,
331
+				    struct io_buffer *iobuf,
332
+				    grant_ref_t *ref ) {
333
+	struct xen_device *xendev = netfront->xendev;
334
+	struct xen_hypervisor *xen = xendev->xen;
335
+	unsigned int id;
336
+
337
+	/* Sanity check */
338
+	assert ( ! netfront_ring_is_full ( ring ) );
339
+
340
+	/* Allocate buffer ID */
341
+	id = ring->ids[ ( ring->id_prod++ ) & ( ring->count - 1 ) ];
342
+
343
+	/* Store I/O buffer */
344
+	assert ( ring->iobufs[id] == NULL );
345
+	ring->iobufs[id] = iobuf;
346
+
347
+	/* Grant access to I/O buffer page.  I/O buffers are naturally
348
+	 * aligned, so we never need to worry about crossing a page
349
+	 * boundary.
350
+	 */
351
+	*ref = ring->refs[id];
352
+	xengrant_permit_access ( xen, ring->refs[id], xendev->backend_id, 0,
353
+				 iobuf->data );
354
+
355
+	return id;
356
+}
357
+
358
+/**
359
+ * Remove buffer from descriptor ring
360
+ *
361
+ * @v netfront		Netfront device
362
+ * @v ring		Descriptor ring
363
+ * @v id		Buffer ID
364
+ * @ret iobuf		I/O buffer
365
+ */
366
+static struct io_buffer * netfront_pull ( struct netfront_nic *netfront,
367
+					  struct netfront_ring *ring,
368
+					  unsigned int id ) {
369
+	struct xen_device *xendev = netfront->xendev;
370
+	struct xen_hypervisor *xen = xendev->xen;
371
+	struct io_buffer *iobuf;
372
+
373
+	/* Sanity check */
374
+	assert ( id < ring->count );
375
+
376
+	/* Revoke access from I/O buffer page */
377
+	xengrant_invalidate ( xen, ring->refs[id] );
378
+
379
+	/* Retrieve I/O buffer */
380
+	iobuf = ring->iobufs[id];
381
+	assert ( iobuf != NULL );
382
+	ring->iobufs[id] = NULL;
383
+
384
+	/* Free buffer ID */
385
+	ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = id;
386
+
387
+	return iobuf;
388
+}
389
+
390
+/**
391
+ * Destroy descriptor ring
392
+ *
393
+ * @v netfront		Netfront device
394
+ * @v ring		Descriptor ring
395
+ * @v discard		Method used to discard outstanding buffer, or NULL
396
+ */
397
+static void netfront_destroy_ring ( struct netfront_nic *netfront,
398
+				    struct netfront_ring *ring,
399
+				    void ( * discard ) ( struct io_buffer * ) ){
400
+	struct xen_device *xendev = netfront->xendev;
401
+	struct xen_hypervisor *xen = xendev->xen;
402
+	struct io_buffer *iobuf;
403
+	unsigned int id;
404
+
405
+	/* Flush any outstanding buffers */
406
+	while ( ! netfront_ring_is_empty ( ring ) ) {
407
+		id = ring->ids[ ring->id_cons & ( ring->count - 1 ) ];
408
+		iobuf = netfront_pull ( netfront, ring, id );
409
+		if ( discard )
410
+			discard ( iobuf );
411
+	}
412
+
413
+	/* Unpublish shared ring reference */
414
+	netfront_rm ( netfront, ring->ref_key );
415
+
416
+	/* Revoke access from shared ring */
417
+	xengrant_invalidate ( xen, ring->ref );
418
+
419
+	/* Free page */
420
+	free_dma ( ring->sring.raw, PAGE_SIZE );
421
+	ring->sring.raw = NULL;
422
+}
423
+
424
+/******************************************************************************
425
+ *
426
+ * Network device interface
427
+ *
428
+ ******************************************************************************
429
+ */
430
+
431
+/**
432
+ * Refill receive descriptor ring
433
+ *
434
+ * @v netfront		Netfront device
435
+ */
436
+static void netfront_refill_rx ( struct netfront_nic *netfront ) {
437
+	struct xen_device *xendev = netfront->xendev;
438
+	struct io_buffer *iobuf;
439
+	struct netif_rx_request *request;
440
+	int notify;
441
+
442
+	/* Do nothing if ring is already full */
443
+	if ( netfront_ring_is_full ( &netfront->rx ) )
444
+		return;
445
+
446
+	/* Refill ring */
447
+	do {
448
+
449
+		/* Allocate I/O buffer */
450
+		iobuf = alloc_iob ( PAGE_SIZE );
451
+		if ( ! iobuf ) {
452
+			/* Wait for next refill */
453
+			break;
454
+		}
455
+
456
+		/* Add to descriptor ring */
457
+		request = RING_GET_REQUEST ( &netfront->rx_fring,
458
+					     netfront->rx_fring.req_prod_pvt++);
459
+		request->id = netfront_push ( netfront, &netfront->rx, iobuf,
460
+					      &request->gref );
461
+		DBGC2 ( netfront, "NETFRONT %s RX id %d ref %d is %#08lx+%zx\n",
462
+			xendev->key, request->id, request->gref,
463
+			virt_to_phys ( iobuf->data ), iob_tailroom ( iobuf ) );
464
+
465
+	} while ( ! netfront_ring_is_full ( &netfront->rx ) );
466
+
467
+	/* Push new descriptors and notify backend if applicable */
468
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring, notify );
469
+	if ( notify )
470
+		netfront_send_event ( netfront );
471
+}
472
+
473
+/**
474
+ * Open network device
475
+ *
476
+ * @v netdev		Network device
477
+ * @ret rc		Return status code
478
+ */
479
+static int netfront_open ( struct net_device *netdev ) {
480
+	struct netfront_nic *netfront = netdev->priv;
481
+	struct xen_device *xendev = netfront->xendev;
482
+	int rc;
483
+
484
+	/* Create transmit descriptor ring */
485
+	if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 )
486
+		goto err_create_tx;
487
+	SHARED_RING_INIT ( netfront->tx_sring );
488
+	FRONT_RING_INIT ( &netfront->tx_fring, netfront->tx_sring, PAGE_SIZE );
489
+	assert ( RING_SIZE ( &netfront->tx_fring ) >= netfront->tx.count );
490
+
491
+	/* Create receive descriptor ring */
492
+	if ( ( rc = netfront_create_ring ( netfront, &netfront->rx ) ) != 0 )
493
+		goto err_create_rx;
494
+	SHARED_RING_INIT ( netfront->rx_sring );
495
+	FRONT_RING_INIT ( &netfront->rx_fring, netfront->rx_sring, PAGE_SIZE );
496
+	assert ( RING_SIZE ( &netfront->rx_fring ) >= netfront->rx.count );
497
+
498
+	/* Create event channel */
499
+	if ( ( rc = netfront_create_event ( netfront ) ) != 0 )
500
+		goto err_create_event;
501
+
502
+	/* "Request" the rx-copy feature.  Current versions of
503
+	 * xen_netback.ko will fail silently if this parameter is not
504
+	 * present.
505
+	 */
506
+	if ( ( rc = netfront_write_flag ( netfront, "request-rx-copy" ) ) != 0 )
507
+		goto err_request_rx_copy;
508
+
509
+	/* Disable checksum offload, since we will always do the work anyway */
510
+	if ( ( rc = netfront_write_flag ( netfront,
511
+					  "feature-no-csum-offload" ) ) != 0 )
512
+		goto err_feature_no_csum_offload;
513
+
514
+	/* Set state to Connected */
515
+	if ( ( rc = xenbus_set_state ( xendev, XenbusStateConnected ) ) != 0 ) {
516
+		DBGC ( netfront, "NETFRONT %s could not set state=\"%d\": %s\n",
517
+		       xendev->key, XenbusStateConnected, strerror ( rc ) );
518
+		goto err_set_state;
519
+	}
520
+
521
+	/* Wait for backend to connect */
522
+	if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateConnected ) ) !=0){
523
+		DBGC ( netfront, "NETFRONT %s could not connect to backend: "
524
+		       "%s\n", xendev->key, strerror ( rc ) );
525
+		goto err_backend_wait;
526
+	}
527
+
528
+	/* Refill receive descriptor ring */
529
+	netfront_refill_rx ( netfront );
530
+
531
+	/* Set link up */
532
+	netdev_link_up ( netdev );
533
+
534
+	return 0;
535
+
536
+ err_backend_wait:
537
+	xenbus_set_state ( xendev, XenbusStateInitialising );
538
+ err_set_state:
539
+	netfront_rm ( netfront, "feature-no-csum-offload" );
540
+ err_feature_no_csum_offload:
541
+	netfront_rm ( netfront, "request-rx-copy" );
542
+ err_request_rx_copy:
543
+	netfront_destroy_event ( netfront );
544
+ err_create_event:
545
+	netfront_destroy_ring ( netfront, &netfront->rx, NULL );
546
+ err_create_rx:
547
+	netfront_destroy_ring ( netfront, &netfront->tx, NULL );
548
+ err_create_tx:
549
+	return rc;
550
+}
551
+
552
+/**
553
+ * Close network device
554
+ *
555
+ * @v netdev		Network device
556
+ */
557
+static void netfront_close ( struct net_device *netdev ) {
558
+	struct netfront_nic *netfront = netdev->priv;
559
+	struct xen_device *xendev = netfront->xendev;
560
+	int rc;
561
+
562
+	/* Set state to Closed */
563
+	xenbus_set_state ( xendev, XenbusStateClosed );
564
+
565
+	/* Wait for backend to close, thereby ensuring that grant
566
+	 * references are no longer in use, etc.
567
+	 */
568
+	if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateClosed ) ) != 0 ) {
569
+		DBGC ( netfront, "NETFRONT %s could not disconnect from "
570
+		       "backend: %s\n", xendev->key, strerror ( rc ) );
571
+		/* Things will probably go _very_ badly wrong if this
572
+		 * happens, since it means the backend may still write
573
+		 * to the outstanding RX buffers that we are about to
574
+		 * free.  The best we can do is report the error via
575
+		 * the link status, but there's a good chance the
576
+		 * machine will crash soon.
577
+		 */
578
+		netdev_link_err ( netdev, rc );
579
+	} else {
580
+		netdev_link_down ( netdev );
581
+	}
582
+
583
+	/* Reset state to Initialising */
584
+	xenbus_set_state ( xendev, XenbusStateInitialising );
585
+
586
+	/* Delete flags */
587
+	netfront_rm ( netfront, "feature-no-csum-offload" );
588
+	netfront_rm ( netfront, "request-rx-copy" );
589
+
590
+	/* Destroy event channel */
591
+	netfront_destroy_event ( netfront );
592
+
593
+	/* Destroy receive descriptor ring, freeing any outstanding
594
+	 * I/O buffers.
595
+	 */
596
+	netfront_destroy_ring ( netfront, &netfront->rx, free_iob );
597
+
598
+	/* Destroy transmit descriptor ring.  Leave any outstanding
599
+	 * I/O buffers to be freed by netdev_tx_flush().
600
+	 */
601
+	netfront_destroy_ring ( netfront, &netfront->tx, NULL );
602
+}
603
+
604
+/**
605
+ * Transmit packet
606
+ *
607
+ * @v netdev		Network device
608
+ * @v iobuf		I/O buffer
609
+ * @ret rc		Return status code
610
+ */
611
+static int netfront_transmit ( struct net_device *netdev,
612
+			       struct io_buffer *iobuf ) {
613
+	struct netfront_nic *netfront = netdev->priv;
614
+	struct xen_device *xendev = netfront->xendev;
615
+	struct netif_tx_request *request;
616
+	int notify;
617
+
618
+	/* Check that we have space in the ring */
619
+	if ( netfront_ring_is_full ( &netfront->tx ) ) {
620
+		DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n",
621
+		       xendev->key );
622
+		return -ENOBUFS;
623
+	}
624
+
625
+	/* Add to descriptor ring */
626
+	request = RING_GET_REQUEST ( &netfront->tx_fring,
627
+				     netfront->tx_fring.req_prod_pvt++ );
628
+	request->id = netfront_push ( netfront, &netfront->tx, iobuf,
629
+				      &request->gref );
630
+	request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) );
631
+	request->flags = NETTXF_data_validated;
632
+	request->size = iob_len ( iobuf );
633
+	DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n",
634
+		xendev->key, request->id, request->gref,
635
+		virt_to_phys ( iobuf->data ), iob_len ( iobuf ) );
636
+
637
+	/* Push new descriptor and notify backend if applicable */
638
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify );
639
+	if ( notify )
640
+		netfront_send_event ( netfront );
641
+
642
+	return 0;
643
+}
644
+
645
+/**
646
+ * Poll for completed packets
647
+ *
648
+ * @v netdev		Network device
649
+ */
650
+static void netfront_poll_tx ( struct net_device *netdev ) {
651
+	struct netfront_nic *netfront = netdev->priv;
652
+	struct xen_device *xendev = netfront->xendev;
653
+	struct netif_tx_response *response;
654
+	struct io_buffer *iobuf;
655
+	unsigned int status;
656
+	int rc;
657
+
658
+	/* Consume any unconsumed responses */
659
+	while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->tx_fring ) ) {
660
+
661
+		/* Get next response */
662
+		response = RING_GET_RESPONSE ( &netfront->tx_fring,
663
+					       netfront->tx_fring.rsp_cons++ );
664
+
665
+		/* Retrieve from descriptor ring */
666
+		iobuf = netfront_pull ( netfront, &netfront->tx, response->id );
667
+		status = response->status;
668
+		if ( status == NETIF_RSP_OKAY ) {
669
+			DBGC2 ( netfront, "NETFRONT %s TX id %d complete\n",
670
+				xendev->key, response->id );
671
+			netdev_tx_complete ( netdev, iobuf );
672
+		} else {
673
+			rc = -EIO_NETIF_RSP ( status );
674
+			DBGC2 ( netfront, "NETFRONT %s TX id %d error %d: %s\n",
675
+				xendev->key, response->id, status,
676
+				strerror ( rc ) );
677
+			netdev_tx_complete_err ( netdev, iobuf, rc );
678
+		}
679
+	}
680
+}
681
+
682
+/**
683
+ * Poll for received packets
684
+ *
685
+ * @v netdev		Network device
686
+ */
687
+static void netfront_poll_rx ( struct net_device *netdev ) {
688
+	struct netfront_nic *netfront = netdev->priv;
689
+	struct xen_device *xendev = netfront->xendev;
690
+	struct netif_rx_response *response;
691
+	struct io_buffer *iobuf;
692
+	int status;
693
+	size_t len;
694
+	int rc;
695
+
696
+	/* Consume any unconsumed responses */
697
+	while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->rx_fring ) ) {
698
+
699
+		/* Get next response */
700
+		response = RING_GET_RESPONSE ( &netfront->rx_fring,
701
+					       netfront->rx_fring.rsp_cons++ );
702
+
703
+		/* Retrieve from descriptor ring */
704
+		iobuf = netfront_pull ( netfront, &netfront->rx, response->id );
705
+		status = response->status;
706
+		if ( status >= 0 ) {
707
+			len = status;
708
+			iob_reserve ( iobuf, response->offset );
709
+			iob_put ( iobuf, len );
710
+			DBGC2 ( netfront, "NETFRONT %s RX id %d complete "
711
+				"%#08lx+%zx\n", xendev->key, response->id,
712
+				virt_to_phys ( iobuf->data ), len );
713
+			netdev_rx ( netdev, iobuf );
714
+		} else {
715
+			rc = -EIO_NETIF_RSP ( status );
716
+			DBGC2 ( netfront, "NETFRONT %s RX id %d error %d: %s\n",
717
+				xendev->key, response->id, status,
718
+				strerror ( rc ) );
719
+			netdev_rx_err ( netdev, iobuf, rc );
720
+		}
721
+	}
722
+}
723
+
724
+/**
725
+ * Poll for completed and received packets
726
+ *
727
+ * @v netdev		Network device
728
+ */
729
+static void netfront_poll ( struct net_device *netdev ) {
730
+	struct netfront_nic *netfront = netdev->priv;
731
+
732
+	/* Poll for TX completions */
733
+	netfront_poll_tx ( netdev );
734
+
735
+	/* Poll for RX completions */
736
+	netfront_poll_rx ( netdev );
737
+
738
+	/* Refill RX descriptor ring */
739
+	netfront_refill_rx ( netfront );
740
+}
741
+
742
+/** Network device operations */
743
+static struct net_device_operations netfront_operations = {
744
+	.open		= netfront_open,
745
+	.close		= netfront_close,
746
+	.transmit	= netfront_transmit,
747
+	.poll		= netfront_poll,
748
+};
749
+
750
+/******************************************************************************
751
+ *
752
+ * Xen device bus interface
753
+ *
754
+ ******************************************************************************
755
+ */
756
+
757
+/**
758
+ * Probe Xen device
759
+ *
760
+ * @v xendev		Xen device
761
+ * @ret rc		Return status code
762
+ */
763
+static int netfront_probe ( struct xen_device *xendev ) {
764
+	struct xen_hypervisor *xen = xendev->xen;
765
+	struct net_device *netdev;
766
+	struct netfront_nic *netfront;
767
+	int rc;
768
+
769
+	/* Allocate and initialise structure */
770
+	netdev = alloc_etherdev ( sizeof ( *netfront ) );
771
+	if ( ! netdev ) {
772
+		rc = -ENOMEM;
773
+		goto err_alloc;
774
+	}
775
+	netdev_init ( netdev, &netfront_operations );
776
+	netdev->dev = &xendev->dev;
777
+	netfront = netdev->priv;
778
+	netfront->xendev = xendev;
779
+	DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n",
780
+	       xendev->key, xendev->backend, xendev->backend_id );
781
+
782
+	/* Allocate grant references and initialise descriptor rings */
783
+	if ( ( rc = xengrant_alloc ( xen, netfront->refs,
784
+				     NETFRONT_REF_COUNT ) ) != 0 ) {
785
+		DBGC ( netfront, "NETFRONT %s could not allocate grant "
786
+		       "references: %s\n", xendev->key, strerror ( rc ) );
787
+		goto err_grant_alloc;
788
+	}
789
+	netfront_init_ring ( &netfront->tx, "tx-ring-ref",
790
+			     netfront->refs[NETFRONT_REF_TX_RING],
791
+			     NETFRONT_NUM_TX_DESC, netfront->tx_iobufs,
792
+			     &netfront->refs[NETFRONT_REF_TX_BASE],
793
+			     netfront->tx_ids );
794
+	netfront_init_ring ( &netfront->rx, "rx-ring-ref",
795
+			     netfront->refs[NETFRONT_REF_RX_RING],
796
+			     NETFRONT_NUM_RX_DESC, netfront->rx_iobufs,
797
+			     &netfront->refs[NETFRONT_REF_RX_BASE],
798
+			     netfront->rx_ids );
799
+
800
+	/* Fetch MAC address */
801
+	if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 )
802
+		goto err_read_mac;
803
+
804
+	/* Register network device */
805
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
806
+		goto err_register_netdev;
807
+
808
+	/* Set initial link state */
809
+	netdev_link_down ( netdev );
810
+
811
+	xen_set_drvdata ( xendev, netdev );
812
+	return 0;
813
+
814
+	unregister_netdev ( netdev );
815
+ err_register_netdev:
816
+ err_read_mac:
817
+	xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT );
818
+ err_grant_alloc:
819
+	netdev_nullify ( netdev );
820
+	netdev_put ( netdev );
821
+ err_alloc:
822
+	return rc;
823
+}
824
+
825
+/**
826
+ * Remove Xen device
827
+ *
828
+ * @v xendev		Xen device
829
+ */
830
+static void netfront_remove ( struct xen_device *xendev ) {
831
+	struct net_device *netdev = xen_get_drvdata ( xendev );
832
+	struct netfront_nic *netfront = netdev->priv;
833
+	struct xen_hypervisor *xen = xendev->xen;
834
+
835
+	/* Unregister network device */
836
+	unregister_netdev ( netdev );
837
+
838
+	/* Free resources */
839
+	xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT );
840
+
841
+	/* Free network device */
842
+	netdev_nullify ( netdev );
843
+	netdev_put ( netdev );
844
+}
845
+
846
+/** Xen netfront driver */
847
+struct xen_driver netfront_driver __xen_driver = {
848
+	.name = "netfront",
849
+	.type = "vif",
850
+	.probe = netfront_probe,
851
+	.remove = netfront_remove,
852
+};

+ 153
- 0
src/drivers/net/netfront.h Ver fichero

@@ -0,0 +1,153 @@
1
+#ifndef _NETFRONT_H
2
+#define _NETFRONT_H
3
+
4
+/** @file
5
+ *
6
+ * Xen netfront driver
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <ipxe/xen.h>
13
+#include <xen/io/netif.h>
14
+
15
+/** Number of transmit ring entries */
16
+#define NETFRONT_NUM_TX_DESC 16
17
+
18
+/** Number of receive ring entries */
19
+#define NETFRONT_NUM_RX_DESC 8
20
+
21
+/** Grant reference indices */
22
+enum netfront_ref_index {
23
+	/** Transmit ring grant reference index */
24
+	NETFRONT_REF_TX_RING = 0,
25
+	/** Transmit descriptor grant reference base index */
26
+	NETFRONT_REF_TX_BASE,
27
+	/** Receive ring grant reference index */
28
+	NETFRONT_REF_RX_RING = ( NETFRONT_REF_TX_BASE + NETFRONT_NUM_TX_DESC ),
29
+	/** Receive descriptor grant reference base index */
30
+	NETFRONT_REF_RX_BASE,
31
+	/** Total number of grant references required */
32
+	NETFRONT_REF_COUNT = ( NETFRONT_REF_RX_BASE + NETFRONT_NUM_RX_DESC )
33
+};
34
+
35
+/** A netfront descriptor ring */
36
+struct netfront_ring {
37
+	/** Shared ring */
38
+	union {
39
+		/** Transmit shared ring */
40
+		netif_tx_sring_t *tx;
41
+		/** Receive shared ring */
42
+		netif_rx_sring_t *rx;
43
+		/** Raw pointer */
44
+		void *raw;
45
+	} sring;
46
+	/** Shared ring grant reference key */
47
+	const char *ref_key;
48
+	/** Shared ring grant reference */
49
+	grant_ref_t ref;
50
+
51
+	/** Maximum number of used descriptors */
52
+	size_t count;
53
+	/** I/O buffers, indexed by buffer ID */
54
+	struct io_buffer **iobufs;
55
+	/** I/O buffer grant references, indexed by buffer ID */
56
+	grant_ref_t *refs;
57
+
58
+	/** Buffer ID ring */
59
+	uint8_t *ids;
60
+	/** Buffer ID ring producer counter */
61
+	unsigned int id_prod;
62
+	/** Buffer ID ring consumer counter */
63
+	unsigned int id_cons;
64
+};
65
+
66
+/**
67
+ * Initialise descriptor ring
68
+ *
69
+ * @v ring		Descriptor ring
70
+ * @v ref_key		Shared ring grant reference key
71
+ * @v ref		Shared ring grant reference
72
+ * @v count		Maxium number of used descriptors
73
+ * @v iobufs		I/O buffers
74
+ * @v refs		I/O buffer grant references
75
+ * @v ids		Buffer IDs
76
+ */
77
+static inline __attribute__ (( always_inline )) void
78
+netfront_init_ring ( struct netfront_ring *ring, const char *ref_key,
79
+		     grant_ref_t ref, unsigned int count,
80
+		     struct io_buffer **iobufs, grant_ref_t *refs,
81
+		     uint8_t *ids ) {
82
+
83
+	ring->ref_key = ref_key;
84
+	ring->ref = ref;
85
+	ring->count = count;
86
+	ring->iobufs = iobufs;
87
+	ring->refs = refs;
88
+	ring->ids = ids;
89
+}
90
+
91
+/**
92
+ * Check whether or not descriptor ring is full
93
+ *
94
+ * @v ring		Descriptor ring
95
+ * @v is_full		Ring is full
96
+ */
97
+static inline __attribute__ (( always_inline )) int
98
+netfront_ring_is_full ( struct netfront_ring *ring ) {
99
+	unsigned int fill_level;
100
+
101
+	fill_level = ( ring->id_prod - ring->id_cons );
102
+	assert ( fill_level <= ring->count );
103
+	return ( fill_level >= ring->count );
104
+}
105
+
106
+/**
107
+ * Check whether or not descriptor ring is empty
108
+ *
109
+ * @v ring		Descriptor ring
110
+ * @v is_empty		Ring is empty
111
+ */
112
+static inline __attribute__ (( always_inline )) int
113
+netfront_ring_is_empty ( struct netfront_ring *ring ) {
114
+
115
+	return ( ring->id_prod == ring->id_cons );
116
+}
117
+
118
+/** A netfront NIC */
119
+struct netfront_nic {
120
+	/** Xen device */
121
+	struct xen_device *xendev;
122
+	/** Grant references */
123
+	grant_ref_t refs[NETFRONT_REF_COUNT];
124
+
125
+	/** Transmit ring */
126
+	struct netfront_ring tx;
127
+	/** Transmit front ring */
128
+	netif_tx_front_ring_t tx_fring;
129
+	/** Transmit I/O buffers */
130
+	struct io_buffer *tx_iobufs[NETFRONT_NUM_TX_DESC];
131
+	/** Transmit I/O buffer IDs */
132
+	uint8_t tx_ids[NETFRONT_NUM_TX_DESC];
133
+
134
+	/** Receive ring */
135
+	struct netfront_ring rx;
136
+	/** Receive front ring */
137
+	netif_rx_front_ring_t rx_fring;
138
+	/** Receive I/O buffers */
139
+	struct io_buffer *rx_iobufs[NETFRONT_NUM_RX_DESC];
140
+	/** Receive I/O buffer IDs */
141
+	uint8_t rx_ids[NETFRONT_NUM_RX_DESC];
142
+
143
+	/** Event channel */
144
+	struct evtchn_send event;
145
+};
146
+
147
+/** Transmit shared ring field */
148
+#define tx_sring tx.sring.tx
149
+
150
+/** Receive shared ring field */
151
+#define rx_sring rx.sring.rx
152
+
153
+#endif /* _NETFRONT_H */

+ 1
- 0
src/include/ipxe/errfile.h Ver fichero

@@ -155,6 +155,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
155 155
 #define ERRFILE_myson		     ( ERRFILE_DRIVER | 0x00660000 )
156 156
 #define ERRFILE_intelx		     ( ERRFILE_DRIVER | 0x00670000 )
157 157
 #define ERRFILE_snp		     ( ERRFILE_DRIVER | 0x00680000 )
158
+#define ERRFILE_netfront	     ( ERRFILE_DRIVER | 0x00690000 )
158 159
 
159 160
 #define ERRFILE_scsi		     ( ERRFILE_DRIVER | 0x00700000 )
160 161
 #define ERRFILE_arbel		     ( ERRFILE_DRIVER | 0x00710000 )

Loading…
Cancelar
Guardar