Browse Source

[intel] Add support for mailbox used by virtual functions

Virtual functions use a mailbox to communicate with the physical
function driver: this covers functionality such as obtaining the MAC
address.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
bb1e1048f6
4 changed files with 414 additions and 0 deletions
  1. 26
    0
      src/drivers/net/intel.h
  2. 303
    0
      src/drivers/net/intelvf.c
  3. 84
    0
      src/drivers/net/intelvf.h
  4. 1
    0
      src/include/ipxe/errfile.h

+ 26
- 0
src/drivers/net/intel.h View File

@@ -243,6 +243,29 @@ intel_init_ring ( struct intel_ring *ring, unsigned int count, unsigned int reg,
243 243
 	ring->describe = describe;
244 244
 }
245 245
 
246
+/** An Intel virtual function mailbox */
247
+struct intel_mailbox {
248
+	/** Mailbox control register */
249
+	unsigned int ctrl;
250
+	/** Mailbox memory base */
251
+	unsigned int mem;
252
+};
253
+
254
+/**
255
+ * Initialise mailbox
256
+ *
257
+ * @v mbox		Mailbox
258
+ * @v ctrl		Mailbox control register
259
+ * @v mem		Mailbox memory register base
260
+ */
261
+static inline __attribute__ (( always_inline )) void
262
+intel_init_mbox ( struct intel_mailbox *mbox, unsigned int ctrl,
263
+		  unsigned int mem ) {
264
+
265
+	mbox->ctrl = ctrl;
266
+	mbox->mem = mem;
267
+}
268
+
246 269
 /** An Intel network card */
247 270
 struct intel_nic {
248 271
 	/** Registers */
@@ -261,6 +284,9 @@ struct intel_nic {
261 284
 	/** EEPROM address shift */
262 285
 	unsigned int eerd_addr_shift;
263 286
 
287
+	/** Mailbox */
288
+	struct intel_mailbox mbox;
289
+
264 290
 	/** Transmit descriptor ring */
265 291
 	struct intel_ring tx;
266 292
 	/** Receive descriptor ring */

+ 303
- 0
src/drivers/net/intelvf.c View File

@@ -0,0 +1,303 @@
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/netdevice.h>
31
+#include <ipxe/ethernet.h>
32
+#include "intelvf.h"
33
+
34
+/** @file
35
+ *
36
+ * Intel 10/100/1000 virtual function network card driver
37
+ *
38
+ */
39
+
40
+/******************************************************************************
41
+ *
42
+ * Mailbox messages
43
+ *
44
+ ******************************************************************************
45
+ */
46
+
47
+/**
48
+ * Write message to mailbox
49
+ *
50
+ * @v intel		Intel device
51
+ * @v msg		Message
52
+ */
53
+static void intelvf_mbox_write ( struct intel_nic *intel,
54
+				 const union intelvf_msg *msg ) {
55
+	unsigned int i;
56
+
57
+	/* Write message */
58
+	DBGC2 ( intel, "INTEL %p sending message", intel );
59
+	for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( msg->dword[0] ) ) ; i++){
60
+		DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), msg->dword[i] );
61
+		writel ( msg->dword[i], ( intel->regs + intel->mbox.mem +
62
+					  ( i * sizeof ( msg->dword[0] ) ) ) );
63
+	}
64
+	DBGC2 ( intel, "\n" );
65
+}
66
+
67
+/**
68
+ * Read message from mailbox
69
+ *
70
+ * @v intel		Intel device
71
+ * @v msg		Message
72
+ */
73
+static void intelvf_mbox_read ( struct intel_nic *intel,
74
+				union intelvf_msg *msg ) {
75
+	unsigned int i;
76
+
77
+	/* Read message */
78
+	DBGC2 ( intel, "INTEL %p received message", intel );
79
+	for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( msg->dword[0] ) ) ; i++){
80
+		msg->dword[i] = readl ( intel->regs + intel->mbox.mem +
81
+					( i * sizeof ( msg->dword[0] ) ) );
82
+		DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), msg->dword[i] );
83
+	}
84
+	DBGC2 ( intel, "\n" );
85
+}
86
+
87
+/**
88
+ * Poll mailbox
89
+ *
90
+ * @v intel		Intel device
91
+ * @ret rc		Return status code
92
+ *
93
+ * Note that polling the mailbox may fail if the underlying PF is
94
+ * reset.
95
+ */
96
+int intelvf_mbox_poll ( struct intel_nic *intel ) {
97
+	struct intel_mailbox *mbox = &intel->mbox;
98
+	union intelvf_msg msg;
99
+	uint32_t ctrl;
100
+
101
+	/* Get mailbox status */
102
+	ctrl = readl ( intel->regs + mbox->ctrl );
103
+
104
+	/* Fail if a reset is in progress */
105
+	if ( ctrl & INTELVF_MBCTRL_RSTI )
106
+		return -EPIPE;
107
+
108
+	/* Acknowledge (and ignore) any received messages */
109
+	if ( ctrl & INTELVF_MBCTRL_PFSTS ) {
110
+		intelvf_mbox_read ( intel, &msg );
111
+		writel ( INTELVF_MBCTRL_ACK, intel->regs + mbox->ctrl );
112
+	}
113
+
114
+	return 0;
115
+}
116
+
117
+/**
118
+ * Wait for PF reset to complete
119
+ *
120
+ * @v intel		Intel device
121
+ * @ret rc		Return status code
122
+ */
123
+int intelvf_mbox_wait ( struct intel_nic *intel ) {
124
+	unsigned int i;
125
+	int rc;
126
+
127
+	/* Wait until a poll completes successfully */
128
+	for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
129
+
130
+		/* Check for successful poll */
131
+		if ( ( rc = intelvf_mbox_poll ( intel ) ) == 0 )
132
+			return 0;
133
+
134
+		/* Delay */
135
+		mdelay ( 1 );
136
+	}
137
+
138
+	DBGC ( intel, "INTEL %p timed out waiting for reset\n", intel );
139
+	return -ETIMEDOUT;
140
+}
141
+
142
+/**
143
+ * Send/receive mailbox message
144
+ *
145
+ * @v intel		Intel device
146
+ * @v msg		Message buffer
147
+ * @ret rc		Return status code
148
+ */
149
+static int intelvf_mbox_msg ( struct intel_nic *intel,
150
+			      union intelvf_msg *msg ) {
151
+	struct intel_mailbox *mbox = &intel->mbox;
152
+	uint32_t ctrl;
153
+	uint32_t seen = 0;
154
+	unsigned int i;
155
+
156
+	/* Sanity check */
157
+	assert ( ! ( msg->hdr & INTELVF_MSG_RESPONSE ) );
158
+
159
+	/* Handle mailbox */
160
+	for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
161
+
162
+		/* Attempt to claim mailbox, if we have not yet sent
163
+		 * our message.
164
+		 */
165
+		if ( ! ( seen & INTELVF_MBCTRL_VFU ) )
166
+			writel ( INTELVF_MBCTRL_VFU, intel->regs + mbox->ctrl );
167
+
168
+		/* Get mailbox status and record observed flags */
169
+		ctrl = readl ( intel->regs + mbox->ctrl );
170
+		seen |= ctrl;
171
+
172
+		/* If a reset is in progress, clear VFU and abort */
173
+		if ( ctrl & INTELVF_MBCTRL_RSTI ) {
174
+			writel ( 0, intel->regs + mbox->ctrl );
175
+			return -EPIPE;
176
+		}
177
+
178
+		/* Write message to mailbox, if applicable.  This
179
+		 * potentially overwrites a message sent by the PF (if
180
+		 * the PF has simultaneously released PFU (thus
181
+		 * allowing our VFU) and asserted PFSTS), but that
182
+		 * doesn't really matter since there are no
183
+		 * unsolicited PF->VF messages that require the actual
184
+		 * message content to be observed.
185
+		 */
186
+		if ( ctrl & INTELVF_MBCTRL_VFU )
187
+			intelvf_mbox_write ( intel, msg );
188
+
189
+		/* Read message from mailbox, if applicable. */
190
+		if ( ( seen & INTELVF_MBCTRL_VFU ) &&
191
+		     ( seen & INTELVF_MBCTRL_PFACK ) &&
192
+		     ( ctrl & INTELVF_MBCTRL_PFSTS ) )
193
+			intelvf_mbox_read ( intel, msg );
194
+
195
+		/* Acknowledge received message (if applicable),
196
+		 * release VFU lock, and send message (if applicable).
197
+		 */
198
+		ctrl = ( ( ( ctrl & INTELVF_MBCTRL_PFSTS ) ?
199
+			   INTELVF_MBCTRL_ACK : 0 ) |
200
+			 ( ( ctrl & INTELVF_MBCTRL_VFU ) ?
201
+			   INTELVF_MBCTRL_REQ : 0 ) );
202
+		writel ( ctrl, intel->regs + mbox->ctrl );
203
+
204
+		/* Exit successfully if we have received a response */
205
+		if ( msg->hdr & INTELVF_MSG_RESPONSE ) {
206
+
207
+			/* Sanity check */
208
+			assert ( seen & INTELVF_MBCTRL_VFU );
209
+			assert ( seen & INTELVF_MBCTRL_PFACK );
210
+			assert ( seen & INTELVF_MBCTRL_PFSTS );
211
+
212
+			return 0;
213
+		}
214
+
215
+		/* Delay */
216
+		mdelay ( 1 );
217
+	}
218
+
219
+	DBGC ( intel, "INTEL %p timed out waiting for mailbox (seen %08x)\n",
220
+	       intel, seen );
221
+	return -ETIMEDOUT;
222
+}
223
+
224
+/**
225
+ * Send reset message and get initial MAC address
226
+ *
227
+ * @v intel		Intel device
228
+ * @v hw_addr		Hardware address to fill in, or NULL
229
+ * @ret rc		Return status code
230
+ */
231
+int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr ) {
232
+	union intelvf_msg msg;
233
+	int rc;
234
+
235
+	/* Send reset message */
236
+	memset ( &msg, 0, sizeof ( msg ) );
237
+	msg.hdr = INTELVF_MSG_TYPE_RESET;
238
+	if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
239
+		DBGC ( intel, "INTEL %p reset failed: %s\n",
240
+		       intel, strerror ( rc ) );
241
+		return rc;
242
+	}
243
+
244
+	/* Check response */
245
+	if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_RESET ) {
246
+		DBGC ( intel, "INTEL %p reset unexpected response:\n", intel );
247
+		DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
248
+		return -EPROTO;
249
+	}
250
+
251
+	/* Fill in MAC address, if applicable */
252
+	if ( hw_addr ) {
253
+		if ( msg.hdr & INTELVF_MSG_ACK ) {
254
+			memcpy ( hw_addr, msg.mac.mac, sizeof ( msg.mac.mac ) );
255
+			DBGC ( intel, "INTEL %p reset assigned MAC address "
256
+			       "%s\n", intel, eth_ntoa ( hw_addr ) );
257
+		} else {
258
+			eth_random_addr ( hw_addr );
259
+			DBGC ( intel, "INTEL %p reset generated MAC address "
260
+			       "%s\n", intel, eth_ntoa ( hw_addr ) );
261
+		}
262
+	}
263
+
264
+	return 0;
265
+}
266
+
267
+/**
268
+ * Send set MAC address message
269
+ *
270
+ * @v intel		Intel device
271
+ * @v ll_addr		Link-layer address
272
+ * @ret rc		Return status code
273
+ */
274
+int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
275
+	union intelvf_msg msg;
276
+	int rc;
277
+
278
+	/* Send set MAC address message */
279
+	memset ( &msg, 0, sizeof ( msg ) );
280
+	msg.hdr = INTELVF_MSG_TYPE_SET_MAC;
281
+	memcpy ( msg.mac.mac, ll_addr, sizeof ( msg.mac.mac ) );
282
+	if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
283
+		DBGC ( intel, "INTEL %p set MAC address failed: %s\n",
284
+		       intel, strerror ( rc ) );
285
+		return rc;
286
+	}
287
+
288
+	/* Check response */
289
+	if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MAC ) {
290
+		DBGC ( intel, "INTEL %p set MAC address unexpected response:\n",
291
+		       intel );
292
+		DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
293
+		return -EPROTO;
294
+	}
295
+
296
+	/* Check that we were allowed to set the MAC address */
297
+	if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
298
+		DBGC ( intel, "INTEL %p set MAC address refused\n", intel );
299
+		return -EPERM;
300
+	}
301
+
302
+	return 0;
303
+}

+ 84
- 0
src/drivers/net/intelvf.h View File

@@ -0,0 +1,84 @@
1
+#ifndef _INTELVF_H
2
+#define _INTELVF_H
3
+
4
+/** @file
5
+ *
6
+ * Intel 10/100/1000 virtual function network card driver
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include "intel.h"
13
+
14
+/** Intel VF BAR size */
15
+#define INTELVF_BAR_SIZE ( 16 * 1024 )
16
+
17
+/** Mailbox Control Register */
18
+#define INTELVF_MBCTRL 0x0c40UL
19
+#define INTELVF_MBCTRL_REQ	0x00000001UL	/**< Request for PF ready */
20
+#define INTELVF_MBCTRL_ACK	0x00000002UL	/**< PF message received */
21
+#define INTELVF_MBCTRL_VFU	0x00000004UL	/**< Buffer taken by VF */
22
+#define INTELVF_MBCTRL_PFU	0x00000008UL	/**< Buffer taken to PF */
23
+#define INTELVF_MBCTRL_PFSTS	0x00000010UL	/**< PF wrote a message */
24
+#define INTELVF_MBCTRL_PFACK	0x00000020UL	/**< PF acknowledged message */
25
+#define INTELVF_MBCTRL_RSTI	0x00000040UL	/**< PF reset in progress */
26
+#define INTELVF_MBCTRL_RSTD	0x00000080UL	/**< PF reset complete */
27
+
28
+/** Mailbox Memory Register Base */
29
+#define INTELVF_MBMEM 0x0800UL
30
+
31
+/** Reset mailbox message */
32
+#define INTELVF_MSG_TYPE_RESET 0x00000001UL
33
+
34
+/** Set MAC address mailbox message */
35
+#define INTELVF_MSG_TYPE_SET_MAC 0x00000002UL
36
+
37
+/** Control ("ping") mailbox message */
38
+#define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
39
+
40
+/** Message type mask */
41
+#define INTELVF_MSG_TYPE_MASK 0x0000ffffUL
42
+
43
+/** Message NACK flag */
44
+#define INTELVF_MSG_NACK 0x40000000UL
45
+
46
+/** Message ACK flag */
47
+#define INTELVF_MSG_ACK 0x80000000UL
48
+
49
+/** Message is a response */
50
+#define INTELVF_MSG_RESPONSE ( INTELVF_MSG_ACK | INTELVF_MSG_NACK )
51
+
52
+/** MAC address mailbox message */
53
+struct intelvf_msg_mac {
54
+	/** Message header */
55
+	uint32_t hdr;
56
+	/** MAC address */
57
+	uint8_t mac[ETH_ALEN];
58
+	/** Alignment padding */
59
+	uint8_t reserved[ (-ETH_ALEN) & 0x3 ];
60
+} __attribute__ (( packed ));
61
+
62
+/** Mailbox message */
63
+union intelvf_msg {
64
+	/** Message header */
65
+	uint32_t hdr;
66
+	/** MAC address message */
67
+	struct intelvf_msg_mac mac;
68
+	/** Raw dwords */
69
+	uint32_t dword[0];
70
+};
71
+
72
+/** Maximum time to wait for mailbox message
73
+ *
74
+ * This is a policy decision.
75
+ */
76
+#define INTELVF_MBOX_MAX_WAIT_MS 500
77
+
78
+extern int intelvf_mbox_poll ( struct intel_nic *intel );
79
+extern int intelvf_mbox_wait ( struct intel_nic *intel );
80
+extern int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr );
81
+extern int intelvf_mbox_set_mac ( struct intel_nic *intel,
82
+				  const uint8_t *ll_addr );
83
+
84
+#endif /* _INTELVF_H */

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

@@ -177,6 +177,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
177 177
 #define ERRFILE_srp		     ( ERRFILE_DRIVER | 0x00750000 )
178 178
 #define ERRFILE_qib7322		     ( ERRFILE_DRIVER | 0x00760000 )
179 179
 #define ERRFILE_smsc75xx	     ( ERRFILE_DRIVER | 0x00770000 )
180
+#define ERRFILE_intelvf		     ( ERRFILE_DRIVER | 0x00780000 )
180 181
 
181 182
 #define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
182 183
 #define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )

Loading…
Cancel
Save