Browse Source

[intelxl] Add driver for Intel 40 Gigabit Ethernet NIC virtual functions

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 5 years ago
parent
commit
a95966955c
4 changed files with 989 additions and 2 deletions
  1. 183
    2
      src/drivers/net/intelxl.h
  2. 719
    0
      src/drivers/net/intelxlvf.c
  3. 86
    0
      src/drivers/net/intelxlvf.h
  4. 1
    0
      src/include/ipxe/errfile.h

+ 183
- 2
src/drivers/net/intelxl.h View File

@@ -20,9 +20,9 @@ struct intelxl_nic;
20 20
 
21 21
 /** Alignment
22 22
  *
23
- * No data structure requires greater than 128 byte alignment.
23
+ * No data structure requires greater than 256 byte alignment.
24 24
  */
25
-#define INTELXL_ALIGN 128
25
+#define INTELXL_ALIGN 256
26 26
 
27 27
 /******************************************************************************
28 28
  *
@@ -310,6 +310,166 @@ struct intelxl_admin_link_params {
310 310
 /** Admin queue Send Message to VF command */
311 311
 #define INTELXL_ADMIN_SEND_TO_VF 0x0802
312 312
 
313
+/** Admin Queue VF Reset opcode */
314
+#define INTELXL_ADMIN_VF_RESET 0x00000002
315
+
316
+/** Admin Queue VF Get Resources opcode */
317
+#define INTELXL_ADMIN_VF_GET_RESOURCES 0x00000003
318
+
319
+/** Admin Queue VF Get Resources data buffer */
320
+struct intelxl_admin_vf_get_resources_buffer {
321
+	/** Reserved */
322
+	uint8_t reserved_a[20];
323
+	/** VSI switching element ID */
324
+	uint16_t vsi;
325
+	/** Reserved */
326
+	uint8_t reserved_b[8];
327
+	/** MAC address */
328
+	uint8_t mac[ETH_ALEN];
329
+} __attribute__ (( packed ));
330
+
331
+/** Admin Queue VF Status Change Event opcode */
332
+#define INTELXL_ADMIN_VF_STATUS 0x00000011
333
+
334
+/** Link status change event type */
335
+#define INTELXL_ADMIN_VF_STATUS_LINK 0x00000001
336
+
337
+/** Link status change event data */
338
+struct intelxl_admin_vf_status_link {
339
+	/** Link speed */
340
+	uint32_t speed;
341
+	/** Link status */
342
+	uint8_t status;
343
+	/** Reserved */
344
+	uint8_t reserved[3];
345
+} __attribute__ (( packed ));
346
+
347
+/** Admin Queue VF Status Change Event data buffer */
348
+struct intelxl_admin_vf_status_buffer {
349
+	/** Event type */
350
+	uint32_t event;
351
+	/** Event data */
352
+	union {
353
+		/** Link change event data */
354
+		struct intelxl_admin_vf_status_link link;
355
+	} data;
356
+	/** Reserved */
357
+	uint8_t reserved[4];
358
+} __attribute__ (( packed ));
359
+
360
+/** Admin Queue VF Configure Queues opcode */
361
+#define INTELXL_ADMIN_VF_CONFIGURE 0x00000006
362
+
363
+/** Admin Queue VF Configure Queues data buffer */
364
+struct intelxl_admin_vf_configure_buffer {
365
+	/** VSI switching element ID */
366
+	uint16_t vsi;
367
+	/** Number of queue pairs */
368
+	uint16_t count;
369
+	/** Reserved */
370
+	uint8_t reserved_a[4];
371
+	/** Transmit queue */
372
+	struct {
373
+		/** VSI switching element ID */
374
+		uint16_t vsi;
375
+		/** Queue ID */
376
+		uint16_t id;
377
+		/** Queue count */
378
+		uint16_t count;
379
+		/** Reserved */
380
+		uint8_t reserved_a[2];
381
+		/** Base address */
382
+		uint64_t base;
383
+		/** Reserved */
384
+		uint8_t reserved_b[8];
385
+	} __attribute__ (( packed )) tx;
386
+	/** Receive queue */
387
+	struct {
388
+		/** VSI switching element ID */
389
+		uint16_t vsi;
390
+		/** Queue ID */
391
+		uint16_t id;
392
+		/** Queue count */
393
+		uint32_t count;
394
+		/** Reserved */
395
+		uint8_t reserved_a[4];
396
+		/** Data buffer length */
397
+		uint32_t len;
398
+		/** Maximum frame size */
399
+		uint32_t mfs;
400
+		/** Reserved */
401
+		uint8_t reserved_b[4];
402
+		/** Base address */
403
+		uint64_t base;
404
+		/** Reserved */
405
+		uint8_t reserved_c[8];
406
+	} __attribute__ (( packed )) rx;
407
+	/** Reserved
408
+	 *
409
+	 * This field exists only due to a bug in the PF driver's
410
+	 * message validation logic, which causes it to miscalculate
411
+	 * the expected message length.
412
+	 */
413
+	uint8_t reserved_b[64];
414
+} __attribute__ (( packed ));
415
+
416
+/** Admin Queue VF IRQ Map opcode */
417
+#define INTELXL_ADMIN_VF_IRQ_MAP 0x00000007
418
+
419
+/** Admin Queue VF IRQ Map data buffer */
420
+struct intelxl_admin_vf_irq_map_buffer {
421
+	/** Number of interrupt vectors */
422
+	uint16_t count;
423
+	/** VSI switching element ID */
424
+	uint16_t vsi;
425
+	/** Interrupt vector ID */
426
+	uint16_t vec;
427
+	/** Receive queue bitmap */
428
+	uint16_t rxmap;
429
+	/** Transmit queue bitmap */
430
+	uint16_t txmap;
431
+	/** Receive interrupt throttling index */
432
+	uint16_t rxitr;
433
+	/** Transmit interrupt throttling index */
434
+	uint16_t txitr;
435
+	/** Reserved
436
+	 *
437
+	 * This field exists only due to a bug in the PF driver's
438
+	 * message validation logic, which causes it to miscalculate
439
+	 * the expected message length.
440
+	 */
441
+	uint8_t reserved[12];
442
+} __attribute__ (( packed ));
443
+
444
+/** Admin Queue VF Enable Queues opcode */
445
+#define INTELXL_ADMIN_VF_ENABLE 0x00000008
446
+
447
+/** Admin Queue VF Disable Queues opcode */
448
+#define INTELXL_ADMIN_VF_DISABLE 0x00000009
449
+
450
+/** Admin Queue VF Enable/Disable Queues data buffer */
451
+struct intelxl_admin_vf_queues_buffer {
452
+	/** VSI switching element ID */
453
+	uint16_t vsi;
454
+	/** Reserved */
455
+	uint8_t reserved[2];
456
+	/** Receive queue bitmask */
457
+	uint32_t rx;
458
+	/** Transmit queue bitmask */
459
+	uint32_t tx;
460
+} __attribute__ (( packed ));
461
+
462
+/** Admin Queue VF Configure Promiscuous Mode opcode */
463
+#define INTELXL_ADMIN_VF_PROMISC 0x0000000e
464
+
465
+/** Admin Queue VF Configure Promiscuous Mode data buffer */
466
+struct intelxl_admin_vf_promisc_buffer {
467
+	/** VSI switching element ID */
468
+	uint16_t vsi;
469
+	/** Flags */
470
+	uint16_t flags;
471
+} __attribute__ (( packed ));
472
+
313 473
 /** Admin queue command parameters */
314 474
 union intelxl_admin_params {
315 475
 	/** Additional data buffer command parameters */
@@ -342,6 +502,18 @@ union intelxl_admin_buffer {
342 502
 	struct intelxl_admin_switch_buffer sw;
343 503
 	/** Get VSI Parameters data buffer */
344 504
 	struct intelxl_admin_vsi_buffer vsi;
505
+	/** VF Get Resources data buffer */
506
+	struct intelxl_admin_vf_get_resources_buffer res;
507
+	/** VF Status Change Event data buffer */
508
+	struct intelxl_admin_vf_status_buffer stat;
509
+	/** VF Configure Queues data buffer */
510
+	struct intelxl_admin_vf_configure_buffer cfg;
511
+	/** VF Enable/Disable Queues data buffer */
512
+	struct intelxl_admin_vf_queues_buffer queues;
513
+	/** VF Configure Promiscuous Mode data buffer */
514
+	struct intelxl_admin_vf_promisc_buffer promisc;
515
+	/*** VF IRQ Map data buffer */
516
+	struct intelxl_admin_vf_irq_map_buffer irq;
345 517
 	/** Alignment padding */
346 518
 	uint8_t pad[INTELXL_ALIGN];
347 519
 } __attribute__ (( packed ));
@@ -867,12 +1039,21 @@ struct intelxl_nic {
867 1039
 	struct pci_msix msix;
868 1040
 	/** MSI-X dummy interrupt target */
869 1041
 	uint32_t msg;
1042
+	/** PCI Express capability offset */
1043
+	unsigned int exp;
870 1044
 
871 1045
 	/** Admin command queue */
872 1046
 	struct intelxl_admin command;
873 1047
 	/** Admin event queue */
874 1048
 	struct intelxl_admin event;
875 1049
 
1050
+	/** Current VF opcode */
1051
+	unsigned int vopcode;
1052
+	/** Current VF return value */
1053
+	int vret;
1054
+	/** Current VF event data buffer */
1055
+	union intelxl_admin_buffer vbuf;
1056
+
876 1057
 	/** Transmit descriptor ring */
877 1058
 	struct intelxl_ring tx;
878 1059
 	/** Receive descriptor ring */

+ 719
- 0
src/drivers/net/intelxlvf.c View File

@@ -0,0 +1,719 @@
1
+/*
2
+ * Copyright (C) 2019 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 <byteswap.h>
30
+#include <ipxe/pci.h>
31
+#include <ipxe/netdevice.h>
32
+#include <ipxe/ethernet.h>
33
+#include "intelxlvf.h"
34
+
35
+/** @file
36
+ *
37
+ * Intel 40 Gigabit Ethernet virtual function network card driver
38
+ *
39
+ */
40
+
41
+/******************************************************************************
42
+ *
43
+ * Device reset
44
+ *
45
+ ******************************************************************************
46
+ */
47
+
48
+/**
49
+ * Reset hardware via PCIe function-level reset
50
+ *
51
+ * @v intelxl		Intel device
52
+ */
53
+static void intelxlvf_reset_flr ( struct intelxl_nic *intelxl,
54
+				  struct pci_device *pci ) {
55
+	uint16_t control;
56
+
57
+	/* Perform a PCIe function-level reset */
58
+	pci_read_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
59
+			       &control );
60
+	pci_write_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
61
+				( control | PCI_EXP_DEVCTL_FLR ) );
62
+	mdelay ( INTELXL_RESET_DELAY_MS );
63
+}
64
+
65
+/**
66
+ * Wait for admin event queue to be torn down
67
+ *
68
+ * @v intelxl		Intel device
69
+ * @ret rc		Return status code
70
+ */
71
+static int intelxlvf_reset_wait_teardown ( struct intelxl_nic *intelxl ) {
72
+	uint32_t admin_evt_len;
73
+	unsigned int i;
74
+
75
+	/* Wait for admin event queue to be torn down */
76
+	for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
77
+
78
+		/* Check admin event queue length register */
79
+		admin_evt_len = readl ( intelxl->regs + INTELXLVF_ADMIN +
80
+					INTELXLVF_ADMIN_EVT_LEN );
81
+		if ( ! ( admin_evt_len & INTELXL_ADMIN_LEN_ENABLE ) )
82
+			return 0;
83
+
84
+		/* Delay */
85
+		mdelay ( 1 );
86
+	}
87
+
88
+	DBGC ( intelxl, "INTELXL %p timed out waiting for teardown (%#08x)\n",
89
+	       intelxl, admin_evt_len );
90
+	return -ETIMEDOUT;
91
+}
92
+
93
+/**
94
+ * Wait for virtual function to be marked as active
95
+ *
96
+ * @v intelxl		Intel device
97
+ * @ret rc		Return status code
98
+ */
99
+static int intelxlvf_reset_wait_active ( struct intelxl_nic *intelxl ) {
100
+	uint32_t vfgen_rstat;
101
+	unsigned int vfr_state;
102
+	unsigned int i;
103
+
104
+	/* Wait for virtual function to be marked as active */
105
+	for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
106
+
107
+		/* Check status as written by physical function driver */
108
+		vfgen_rstat = readl ( intelxl->regs + INTELXLVF_VFGEN_RSTAT );
109
+		vfr_state = INTELXLVF_VFGEN_RSTAT_VFR_STATE ( vfgen_rstat );
110
+		if ( vfr_state == INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE )
111
+			return 0;
112
+
113
+		/* Delay */
114
+		mdelay ( 1 );
115
+	}
116
+
117
+	DBGC ( intelxl, "INTELXL %p timed out waiting for activation "
118
+	       "(%#08x)\n", intelxl, vfgen_rstat );
119
+	return -ETIMEDOUT;
120
+}
121
+
122
+/**
123
+ * Reset hardware via admin queue
124
+ *
125
+ * @v intelxl		Intel device
126
+ * @ret rc		Return status code
127
+ */
128
+static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
129
+	struct intelxl_admin_descriptor *cmd;
130
+	int rc;
131
+
132
+	/* Populate descriptor */
133
+	cmd = intelxl_admin_command_descriptor ( intelxl );
134
+	cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
135
+	cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_RESET );
136
+
137
+	/* Issue command */
138
+	if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
139
+		goto err_command;
140
+
141
+	/* Wait for minimum reset time */
142
+	mdelay ( INTELXL_RESET_DELAY_MS );
143
+
144
+	/* Wait for reset to take effect */
145
+	if ( ( rc = intelxlvf_reset_wait_teardown ( intelxl ) ) != 0 )
146
+		goto err_teardown;
147
+
148
+	/* Wait for virtual function to become active */
149
+	if ( ( rc = intelxlvf_reset_wait_active ( intelxl ) ) != 0 )
150
+		goto err_active;
151
+
152
+ err_active:
153
+ err_teardown:
154
+	intelxl_reopen_admin ( intelxl );
155
+ err_command:
156
+	return rc;
157
+}
158
+
159
+/******************************************************************************
160
+ *
161
+ * Admin queue
162
+ *
163
+ ******************************************************************************
164
+ */
165
+
166
+/** Admin command queue register offsets */
167
+static const struct intelxl_admin_offsets intelxlvf_admin_command_offsets = {
168
+	.bal = INTELXLVF_ADMIN_CMD_BAL,
169
+	.bah = INTELXLVF_ADMIN_CMD_BAH,
170
+	.len = INTELXLVF_ADMIN_CMD_LEN,
171
+	.head = INTELXLVF_ADMIN_CMD_HEAD,
172
+	.tail = INTELXLVF_ADMIN_CMD_TAIL,
173
+};
174
+
175
+/** Admin event queue register offsets */
176
+static const struct intelxl_admin_offsets intelxlvf_admin_event_offsets = {
177
+	.bal = INTELXLVF_ADMIN_EVT_BAL,
178
+	.bah = INTELXLVF_ADMIN_EVT_BAH,
179
+	.len = INTELXLVF_ADMIN_EVT_LEN,
180
+	.head = INTELXLVF_ADMIN_EVT_HEAD,
181
+	.tail = INTELXLVF_ADMIN_EVT_TAIL,
182
+};
183
+
184
+/**
185
+ * Issue admin queue virtual function command
186
+ *
187
+ * @v netdev		Network device
188
+ * @ret rc		Return status code
189
+ */
190
+static int intelxlvf_admin_command ( struct net_device *netdev ) {
191
+	struct intelxl_nic *intelxl = netdev->priv;
192
+	struct intelxl_admin *admin = &intelxl->command;
193
+	struct intelxl_admin_descriptor *cmd;
194
+	unsigned int i;
195
+	int rc;
196
+
197
+	/* Populate descriptor */
198
+	cmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
199
+	cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
200
+
201
+	/* Record opcode */
202
+	intelxl->vopcode = le32_to_cpu ( cmd->vopcode );
203
+
204
+	/* Issue command */
205
+	if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
206
+		goto err_command;
207
+
208
+	/* Wait for response */
209
+	for ( i = 0 ; i < INTELXLVF_ADMIN_MAX_WAIT_MS ; i++ ) {
210
+
211
+		/* Poll admin event queue */
212
+		intelxl_poll_admin ( netdev );
213
+
214
+		/* If response has not arrived, delay 1ms and retry */
215
+		if ( intelxl->vopcode ) {
216
+			mdelay ( 1 );
217
+			continue;
218
+		}
219
+
220
+		/* Check for errors */
221
+		if ( intelxl->vret != 0 )
222
+			return -EIO;
223
+
224
+		return 0;
225
+	}
226
+
227
+	rc = -ETIMEDOUT;
228
+	DBGC ( intelxl, "INTELXL %p timed out waiting for admin VF command "
229
+	       "%#x\n", intelxl, intelxl->vopcode );
230
+ err_command:
231
+	intelxl->vopcode = 0;
232
+	return rc;
233
+}
234
+
235
+/**
236
+ * Handle link status event
237
+ *
238
+ * @v netdev		Network device
239
+ * @v link		Link status
240
+ */
241
+static void intelxlvf_admin_link ( struct net_device *netdev,
242
+				   struct intelxl_admin_vf_status_link *link ) {
243
+	struct intelxl_nic *intelxl = netdev->priv;
244
+
245
+	DBGC ( intelxl, "INTELXL %p link %#02x speed %#02x\n", intelxl,
246
+	       link->status, link->speed );
247
+
248
+	/* Update network device */
249
+	if ( link->status ) {
250
+		netdev_link_up ( netdev );
251
+	} else {
252
+		netdev_link_down ( netdev );
253
+	}
254
+}
255
+
256
+/**
257
+ * Handle status change event
258
+ *
259
+ * @v netdev		Network device
260
+ * @v stat		Status change event
261
+ */
262
+static void
263
+intelxlvf_admin_status ( struct net_device *netdev,
264
+			 struct intelxl_admin_vf_status_buffer *stat ) {
265
+	struct intelxl_nic *intelxl = netdev->priv;
266
+
267
+	/* Handle event */
268
+	switch ( stat->event ) {
269
+	case cpu_to_le32 ( INTELXL_ADMIN_VF_STATUS_LINK ):
270
+		intelxlvf_admin_link ( netdev, &stat->data.link );
271
+		break;
272
+	default:
273
+		DBGC ( intelxl, "INTELXL %p unrecognised status change "
274
+		       "event %#x:\n", intelxl, le32_to_cpu ( stat->event ) );
275
+		DBGC_HDA ( intelxl, 0, stat, sizeof ( *stat ) );
276
+		break;
277
+	}
278
+}
279
+
280
+/**
281
+ * Handle virtual function event
282
+ *
283
+ * @v netdev		Network device
284
+ * @v evt		Admin queue event descriptor
285
+ * @v buf		Admin queue event data buffer
286
+ */
287
+void intelxlvf_admin_event ( struct net_device *netdev,
288
+			     struct intelxl_admin_descriptor *evt,
289
+			     union intelxl_admin_buffer *buf ) {
290
+	struct intelxl_nic *intelxl = netdev->priv;
291
+	unsigned int vopcode = le32_to_cpu ( evt->vopcode );
292
+
293
+	/* Record command response if applicable */
294
+	if ( vopcode == intelxl->vopcode ) {
295
+		memcpy ( &intelxl->vbuf, buf, sizeof ( intelxl->vbuf ) );
296
+		intelxl->vopcode = 0;
297
+		intelxl->vret = le32_to_cpu ( evt->vret );
298
+		if ( intelxl->vret != 0 ) {
299
+			DBGC ( intelxl, "INTELXL %p admin VF command %#x "
300
+			       "error %d\n", intelxl, vopcode, intelxl->vret );
301
+			DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt,
302
+				   sizeof ( *evt ) );
303
+			DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf,
304
+				   le16_to_cpu ( evt->len ) );
305
+		}
306
+		return;
307
+	}
308
+
309
+	/* Handle unsolicited events */
310
+	switch ( vopcode ) {
311
+	case INTELXL_ADMIN_VF_STATUS:
312
+		intelxlvf_admin_status ( netdev, &buf->stat );
313
+		break;
314
+	default:
315
+		DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n",
316
+		       intelxl, vopcode );
317
+		DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) );
318
+		DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) );
319
+		break;
320
+	}
321
+}
322
+
323
+/**
324
+ * Get resources
325
+ *
326
+ * @v netdev		Network device
327
+ * @ret rc		Return status code
328
+ */
329
+static int intelxlvf_admin_get_resources ( struct net_device *netdev ) {
330
+	struct intelxl_nic *intelxl = netdev->priv;
331
+	struct intelxl_admin_descriptor *cmd;
332
+	struct intelxl_admin_vf_get_resources_buffer *res;
333
+	int rc;
334
+
335
+	/* Populate descriptor */
336
+	cmd = intelxl_admin_command_descriptor ( intelxl );
337
+	cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_GET_RESOURCES );
338
+
339
+	/* Issue command */
340
+	if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
341
+		return rc;
342
+
343
+	/* Parse response */
344
+	res = &intelxl->vbuf.res;
345
+	intelxl->vsi = le16_to_cpu ( res->vsi );
346
+	memcpy ( netdev->hw_addr, res->mac, ETH_ALEN );
347
+	DBGC ( intelxl, "INTELXL %p VSI %#04x\n", intelxl, intelxl->vsi );
348
+
349
+	return 0;
350
+}
351
+
352
+/******************************************************************************
353
+ *
354
+ * Network device interface
355
+ *
356
+ ******************************************************************************
357
+ */
358
+
359
+/**
360
+ * Configure queues
361
+ *
362
+ * @v netdev		Network device
363
+ * @ret rc		Return status code
364
+ */
365
+static int intelxlvf_admin_configure ( struct net_device *netdev ) {
366
+	struct intelxl_nic *intelxl = netdev->priv;
367
+	struct intelxl_admin_descriptor *cmd;
368
+	union intelxl_admin_buffer *buf;
369
+	int rc;
370
+
371
+	/* Populate descriptor */
372
+	cmd = intelxl_admin_command_descriptor ( intelxl );
373
+	cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_CONFIGURE );
374
+	cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
375
+	cmd->len = cpu_to_le16 ( sizeof ( buf->cfg ) );
376
+	buf = intelxl_admin_command_buffer ( intelxl );
377
+	buf->cfg.vsi = cpu_to_le16 ( intelxl->vsi );
378
+	buf->cfg.count = cpu_to_le16 ( 1 );
379
+	buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi );
380
+	buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC );
381
+	buf->cfg.tx.base = cpu_to_le64 ( virt_to_bus ( intelxl->tx.desc.raw ) );
382
+	buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi );
383
+	buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC );
384
+	buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs );
385
+	buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs );
386
+	buf->cfg.rx.base = cpu_to_le64 ( virt_to_bus ( intelxl->rx.desc.raw ) );
387
+
388
+	/* Issue command */
389
+	if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
390
+		return rc;
391
+
392
+	return 0;
393
+}
394
+
395
+/**
396
+ * Configure IRQ mapping
397
+ *
398
+ * @v netdev		Network device
399
+ * @ret rc		Return status code
400
+ */
401
+static int intelxlvf_admin_irq_map ( struct net_device *netdev ) {
402
+	struct intelxl_nic *intelxl = netdev->priv;
403
+	struct intelxl_admin_descriptor *cmd;
404
+	union intelxl_admin_buffer *buf;
405
+	int rc;
406
+
407
+	/* Populate descriptor */
408
+	cmd = intelxl_admin_command_descriptor ( intelxl );
409
+	cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_IRQ_MAP );
410
+	cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
411
+	cmd->len = cpu_to_le16 ( sizeof ( buf->irq ) );
412
+	buf = intelxl_admin_command_buffer ( intelxl );
413
+	buf->irq.count = cpu_to_le16 ( 1 );
414
+	buf->irq.vsi = cpu_to_le16 ( intelxl->vsi );
415
+	buf->irq.rxmap = cpu_to_le16 ( 0x0001 );
416
+	buf->irq.txmap = cpu_to_le16 ( 0x0001 );
417
+
418
+	/* Issue command */
419
+	if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
420
+		return rc;
421
+
422
+	return 0;
423
+}
424
+
425
+/**
426
+ * Enable/disable queues
427
+ *
428
+ * @v netdev		Network device
429
+ * @v enable		Enable queues
430
+ * @ret rc		Return status code
431
+ */
432
+static int intelxlvf_admin_queues ( struct net_device *netdev, int enable ) {
433
+	struct intelxl_nic *intelxl = netdev->priv;
434
+	struct intelxl_admin_descriptor *cmd;
435
+	union intelxl_admin_buffer *buf;
436
+	int rc;
437
+
438
+	/* Populate descriptor */
439
+	cmd = intelxl_admin_command_descriptor ( intelxl );
440
+	cmd->vopcode = ( enable ? cpu_to_le32 ( INTELXL_ADMIN_VF_ENABLE ) :
441
+			 cpu_to_le32 ( INTELXL_ADMIN_VF_DISABLE ) );
442
+	cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
443
+	cmd->len = cpu_to_le16 ( sizeof ( buf->queues ) );
444
+	buf = intelxl_admin_command_buffer ( intelxl );
445
+	buf->queues.vsi = cpu_to_le16 ( intelxl->vsi );
446
+	buf->queues.rx = cpu_to_le32 ( 1 );
447
+	buf->queues.tx = cpu_to_le32 ( 1 );
448
+
449
+	/* Issue command */
450
+	if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
451
+		return rc;
452
+
453
+	return 0;
454
+}
455
+
456
+/**
457
+ * Configure promiscuous mode
458
+ *
459
+ * @v netdev		Network device
460
+ * @ret rc		Return status code
461
+ */
462
+static int intelxlvf_admin_promisc ( struct net_device *netdev ) {
463
+	struct intelxl_nic *intelxl = netdev->priv;
464
+	struct intelxl_admin_descriptor *cmd;
465
+	union intelxl_admin_buffer *buf;
466
+	int rc;
467
+
468
+	/* Populate descriptor */
469
+	cmd = intelxl_admin_command_descriptor ( intelxl );
470
+	cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_PROMISC );
471
+	cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
472
+	cmd->len = cpu_to_le16 ( sizeof ( buf->promisc ) );
473
+	buf = intelxl_admin_command_buffer ( intelxl );
474
+	buf->promisc.vsi = cpu_to_le16 ( intelxl->vsi );
475
+	buf->promisc.flags = cpu_to_le16 ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
476
+					   INTELXL_ADMIN_PROMISC_FL_MULTICAST );
477
+
478
+	/* Issue command */
479
+	if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
480
+		return rc;
481
+
482
+	return 0;
483
+}
484
+
485
+/**
486
+ * Open network device
487
+ *
488
+ * @v netdev		Network device
489
+ * @ret rc		Return status code
490
+ */
491
+static int intelxlvf_open ( struct net_device *netdev ) {
492
+	struct intelxl_nic *intelxl = netdev->priv;
493
+	int rc;
494
+
495
+	/* Calculate maximum frame size */
496
+	intelxl->mfs = ( ( ETH_HLEN + netdev->mtu + 4 /* CRC */ +
497
+			   INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
498
+
499
+	/* Allocate transmit descriptor ring */
500
+	if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 )
501
+		goto err_alloc_tx;
502
+
503
+	/* Allocate receive descriptor ring */
504
+	if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 )
505
+		goto err_alloc_rx;
506
+
507
+	/* Configure queues */
508
+	if ( ( rc = intelxlvf_admin_configure ( netdev ) ) != 0 )
509
+		goto err_configure;
510
+
511
+	/* Configure IRQ map */
512
+	if ( ( rc = intelxlvf_admin_irq_map ( netdev ) ) != 0 )
513
+		goto err_irq_map;
514
+
515
+	/* Enable queues */
516
+	if ( ( rc = intelxlvf_admin_queues ( netdev, 1 ) ) != 0 )
517
+		goto err_enable;
518
+
519
+	/* Configure promiscuous mode */
520
+	if ( ( rc = intelxlvf_admin_promisc ( netdev ) ) != 0 )
521
+		goto err_promisc;
522
+
523
+	return 0;
524
+
525
+ err_promisc:
526
+	intelxlvf_admin_queues ( netdev, INTELXL_ADMIN_VF_DISABLE );
527
+ err_enable:
528
+ err_irq_map:
529
+ err_configure:
530
+	intelxl_free_ring ( intelxl, &intelxl->rx );
531
+ err_alloc_rx:
532
+	intelxl_free_ring ( intelxl, &intelxl->tx );
533
+ err_alloc_tx:
534
+	return rc;
535
+}
536
+
537
+/**
538
+ * Close network device
539
+ *
540
+ * @v netdev		Network device
541
+ */
542
+static void intelxlvf_close ( struct net_device *netdev ) {
543
+	struct intelxl_nic *intelxl = netdev->priv;
544
+	int rc;
545
+
546
+	/* Disable queues */
547
+	if ( ( rc = intelxlvf_admin_queues ( netdev, 0 ) ) != 0 ) {
548
+		/* Leak memory; there's nothing else we can do */
549
+		return;
550
+	}
551
+
552
+	/* Free receive descriptor ring */
553
+	intelxl_free_ring ( intelxl, &intelxl->rx );
554
+
555
+	/* Free transmit descriptor ring */
556
+	intelxl_free_ring ( intelxl, &intelxl->tx );
557
+
558
+	/* Discard any unused receive buffers */
559
+	intelxl_empty_rx ( intelxl );
560
+}
561
+
562
+/** Network device operations */
563
+static struct net_device_operations intelxlvf_operations = {
564
+	.open		= intelxlvf_open,
565
+	.close		= intelxlvf_close,
566
+	.transmit	= intelxl_transmit,
567
+	.poll		= intelxl_poll,
568
+};
569
+
570
+/******************************************************************************
571
+ *
572
+ * PCI interface
573
+ *
574
+ ******************************************************************************
575
+ */
576
+
577
+/**
578
+ * Probe PCI device
579
+ *
580
+ * @v pci		PCI device
581
+ * @ret rc		Return status code
582
+ */
583
+static int intelxlvf_probe ( struct pci_device *pci ) {
584
+	struct net_device *netdev;
585
+	struct intelxl_nic *intelxl;
586
+	int rc;
587
+
588
+	/* Allocate and initialise net device */
589
+	netdev = alloc_etherdev ( sizeof ( *intelxl ) );
590
+	if ( ! netdev ) {
591
+		rc = -ENOMEM;
592
+		goto err_alloc;
593
+	}
594
+	netdev_init ( netdev, &intelxlvf_operations );
595
+	intelxl = netdev->priv;
596
+	pci_set_drvdata ( pci, netdev );
597
+	netdev->dev = &pci->dev;
598
+	memset ( intelxl, 0, sizeof ( *intelxl ) );
599
+	intelxl->intr = INTELXLVF_VFINT_DYN_CTL0;
600
+	intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN,
601
+			     &intelxlvf_admin_command_offsets );
602
+	intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN,
603
+			     &intelxlvf_admin_event_offsets );
604
+	intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC,
605
+			      sizeof ( intelxl->tx.desc.tx[0] ),
606
+			      INTELXLVF_QTX_TAIL );
607
+	intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC,
608
+			      sizeof ( intelxl->rx.desc.rx[0] ),
609
+			      INTELXLVF_QRX_TAIL );
610
+
611
+	/* Fix up PCI device */
612
+	adjust_pci_device ( pci );
613
+
614
+	/* Map registers */
615
+	intelxl->regs = ioremap ( pci->membase, INTELXLVF_BAR_SIZE );
616
+	if ( ! intelxl->regs ) {
617
+		rc = -ENODEV;
618
+		goto err_ioremap;
619
+	}
620
+
621
+	/* Locate PCI Express capability */
622
+	intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP );
623
+	if ( ! intelxl->exp ) {
624
+		DBGC ( intelxl, "INTELXL %p missing PCIe capability\n",
625
+		       intelxl );
626
+		rc = -ENXIO;
627
+		goto err_exp;
628
+	}
629
+
630
+	/* Reset the function via PCIe FLR */
631
+	intelxlvf_reset_flr ( intelxl, pci );
632
+
633
+	/* Enable MSI-X dummy interrupt */
634
+	if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
635
+		goto err_msix;
636
+
637
+	/* Open admin queues */
638
+	if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
639
+		goto err_open_admin;
640
+
641
+	/* Reset the function via admin queue */
642
+	if ( ( rc = intelxlvf_reset_admin ( intelxl ) ) != 0 )
643
+		goto err_reset_admin;
644
+
645
+	/* Get MAC address */
646
+	if ( ( rc = intelxlvf_admin_get_resources ( netdev ) ) != 0 )
647
+		goto err_get_resources;
648
+
649
+	/* Register network device */
650
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
651
+		goto err_register_netdev;
652
+
653
+	return 0;
654
+
655
+	unregister_netdev ( netdev );
656
+ err_register_netdev:
657
+ err_get_resources:
658
+ err_reset_admin:
659
+	intelxl_close_admin ( intelxl );
660
+ err_open_admin:
661
+	intelxl_msix_disable ( intelxl, pci );
662
+ err_msix:
663
+	intelxlvf_reset_flr ( intelxl, pci );
664
+ err_exp:
665
+	iounmap ( intelxl->regs );
666
+ err_ioremap:
667
+	netdev_nullify ( netdev );
668
+	netdev_put ( netdev );
669
+ err_alloc:
670
+	return rc;
671
+}
672
+
673
+/**
674
+ * Remove PCI device
675
+ *
676
+ * @v pci		PCI device
677
+ */
678
+static void intelxlvf_remove ( struct pci_device *pci ) {
679
+	struct net_device *netdev = pci_get_drvdata ( pci );
680
+	struct intelxl_nic *intelxl = netdev->priv;
681
+
682
+	/* Unregister network device */
683
+	unregister_netdev ( netdev );
684
+
685
+	/* Reset the function via admin queue */
686
+	intelxlvf_reset_admin ( intelxl );
687
+
688
+	/* Close admin queues */
689
+	intelxl_close_admin ( intelxl );
690
+
691
+	/* Disable MSI-X dummy interrupt */
692
+	intelxl_msix_disable ( intelxl, pci );
693
+
694
+	/* Reset the function via PCIe FLR */
695
+	intelxlvf_reset_flr ( intelxl, pci );
696
+
697
+	/* Free network device */
698
+	iounmap ( intelxl->regs );
699
+	netdev_nullify ( netdev );
700
+	netdev_put ( netdev );
701
+}
702
+
703
+/** PCI device IDs */
704
+static struct pci_device_id intelxlvf_nics[] = {
705
+	PCI_ROM ( 0x8086, 0x154c, "xl710-vf", "XL710 VF", 0 ),
706
+	PCI_ROM ( 0x8086, 0x1571, "xl710-vf-hv", "XL710 VF (Hyper-V)", 0 ),
707
+	PCI_ROM ( 0x8086, 0x1889, "xl710-vf-ad", "XL710 VF (adaptive)", 0 ),
708
+	PCI_ROM ( 0x8086, 0x37cd, "x722-vf", "X722 VF", 0 ),
709
+	PCI_ROM ( 0x8086, 0x37d9, "x722-vf-hv", "X722 VF (Hyper-V)", 0 ),
710
+};
711
+
712
+/** PCI driver */
713
+struct pci_driver intelxlvf_driver __pci_driver = {
714
+	.ids = intelxlvf_nics,
715
+	.id_count = ( sizeof ( intelxlvf_nics ) /
716
+		      sizeof ( intelxlvf_nics[0] ) ),
717
+	.probe = intelxlvf_probe,
718
+	.remove = intelxlvf_remove,
719
+};

+ 86
- 0
src/drivers/net/intelxlvf.h View File

@@ -0,0 +1,86 @@
1
+#ifndef _INTELXLVF_H
2
+#define _INTELXLVF_H
3
+
4
+/** @file
5
+ *
6
+ * Intel 40 Gigabit Ethernet virtual function network card driver
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include "intelxl.h"
13
+
14
+/** BAR size */
15
+#define INTELXLVF_BAR_SIZE 0x10000
16
+
17
+/** Transmit Queue Tail Register */
18
+#define INTELXLVF_QTX_TAIL 0x00000
19
+
20
+/** Receive Queue Tail Register */
21
+#define INTELXLVF_QRX_TAIL 0x02000
22
+
23
+/** VF Interrupt Zero Dynamic Control Register */
24
+#define INTELXLVF_VFINT_DYN_CTL0 0x5c00
25
+
26
+/** VF Admin Queue register block */
27
+#define INTELXLVF_ADMIN 0x6000
28
+
29
+/** Admin Command Queue Base Address Low Register (offset) */
30
+#define INTELXLVF_ADMIN_CMD_BAL 0x1c00
31
+
32
+/** Admin Command Queue Base Address High Register (offset) */
33
+#define INTELXLVF_ADMIN_CMD_BAH 0x1800
34
+
35
+/** Admin Command Queue Length Register (offset) */
36
+#define INTELXLVF_ADMIN_CMD_LEN 0x0800
37
+
38
+/** Admin Command Queue Head Register (offset) */
39
+#define INTELXLVF_ADMIN_CMD_HEAD 0x0400
40
+
41
+/** Admin Command Queue Tail Register (offset) */
42
+#define INTELXLVF_ADMIN_CMD_TAIL 0x2400
43
+
44
+/** Admin Event Queue Base Address Low Register (offset) */
45
+#define INTELXLVF_ADMIN_EVT_BAL 0x0c00
46
+
47
+/** Admin Event Queue Base Address High Register (offset) */
48
+#define INTELXLVF_ADMIN_EVT_BAH 0x0000
49
+
50
+/** Admin Event Queue Length Register (offset) */
51
+#define INTELXLVF_ADMIN_EVT_LEN 0x2000
52
+
53
+/** Admin Event Queue Head Register (offset) */
54
+#define INTELXLVF_ADMIN_EVT_HEAD 0x1400
55
+
56
+/** Admin Event Queue Tail Register (offset) */
57
+#define INTELXLVF_ADMIN_EVT_TAIL 0x1000
58
+
59
+/** Maximum time to wait for a VF admin request to complete */
60
+#define INTELXLVF_ADMIN_MAX_WAIT_MS 2000
61
+
62
+/** VF Reset Status Register */
63
+#define INTELXLVF_VFGEN_RSTAT 0x8800
64
+#define INTELXLVF_VFGEN_RSTAT_VFR_STATE(x) ( (x) & 0x3 )
65
+#define INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE 0x2
66
+
67
+/** Maximum time to wait for reset to complete */
68
+#define INTELXLVF_RESET_MAX_WAIT_MS 1000
69
+
70
+/**
71
+ * Initialise descriptor ring
72
+ *
73
+ * @v ring		Descriptor ring
74
+ * @v count		Number of descriptors
75
+ * @v len		Length of a single descriptor
76
+ * @v tail		Tail register offset
77
+ */
78
+static inline __attribute__ (( always_inline)) void
79
+intelxlvf_init_ring ( struct intelxl_ring *ring, unsigned int count,
80
+		      size_t len, unsigned int tail ) {
81
+
82
+	ring->len = ( count * len );
83
+	ring->tail = tail;
84
+}
85
+
86
+#endif /* _INTELXLVF_H */

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -206,6 +206,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
206 206
 #define ERRFILE_icplus		     ( ERRFILE_DRIVER | 0x00ca0000 )
207 207
 #define ERRFILE_intelxl		     ( ERRFILE_DRIVER | 0x00cb0000 )
208 208
 #define ERRFILE_pcimsix		     ( ERRFILE_DRIVER | 0x00cc0000 )
209
+#define ERRFILE_intelxlvf	     ( ERRFILE_DRIVER | 0x00cd0000 )
209 210
 
210 211
 #define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
211 212
 #define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )

Loading…
Cancel
Save