iPXE
intelvf.c
Go to the documentation of this file.
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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <string.h>
28#include <unistd.h>
29#include <errno.h>
30#include <ipxe/io.h>
31#include <ipxe/netdevice.h>
32#include <ipxe/ethernet.h>
33#include "intelvf.h"
34
35/** @file
36 *
37 * Intel 10/100/1000 virtual function network card driver
38 *
39 */
40
41/******************************************************************************
42 *
43 * Mailbox messages
44 *
45 ******************************************************************************
46 */
47
48/**
49 * Write message to mailbox
50 *
51 * @v intel Intel device
52 * @v msg Message
53 */
54static void intelvf_mbox_write ( struct intel_nic *intel,
55 const union intelvf_msg *msg ) {
56 const struct intelvf_msg_raw *raw = &msg->raw;
57 unsigned int i;
58
59 /* Write message */
60 DBGC2 ( intel, "INTEL %p sending message", intel );
61 for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( raw->dword[0] ) ) ; i++){
62 DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), raw->dword[i] );
63 writel ( raw->dword[i], ( intel->regs + intel->mbox.mem +
64 ( i * sizeof ( raw->dword[0] ) ) ) );
65 }
66 DBGC2 ( intel, "\n" );
67}
68
69/**
70 * Read message from mailbox
71 *
72 * @v intel Intel device
73 * @v msg Message
74 */
75static void intelvf_mbox_read ( struct intel_nic *intel,
76 union intelvf_msg *msg ) {
77 struct intelvf_msg_raw *raw = &msg->raw;
78 unsigned int i;
79
80 /* Read message */
81 DBGC2 ( intel, "INTEL %p received message", intel );
82 for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( raw->dword[0] ) ) ; i++){
83 raw->dword[i] = readl ( intel->regs + intel->mbox.mem +
84 ( i * sizeof ( raw->dword[0] ) ) );
85 DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), raw->dword[i] );
86 }
87 DBGC2 ( intel, "\n" );
88}
89
90/**
91 * Poll mailbox
92 *
93 * @v intel Intel device
94 * @ret rc Return status code
95 *
96 * Note that polling the mailbox may fail if the underlying PF is
97 * reset.
98 */
99int intelvf_mbox_poll ( struct intel_nic *intel ) {
100 struct intel_mailbox *mbox = &intel->mbox;
101 union intelvf_msg msg;
103
104 /* Get mailbox status */
105 ctrl = readl ( intel->regs + mbox->ctrl );
106
107 /* Fail if a reset is in progress */
109 return -EPIPE;
110
111 /* Acknowledge (and ignore) any received messages */
112 if ( ctrl & INTELVF_MBCTRL_PFSTS ) {
113 intelvf_mbox_read ( intel, &msg );
114 writel ( INTELVF_MBCTRL_ACK, intel->regs + mbox->ctrl );
115 }
116
117 return 0;
118}
119
120/**
121 * Wait for PF reset to complete
122 *
123 * @v intel Intel device
124 * @ret rc Return status code
125 */
126int intelvf_mbox_wait ( struct intel_nic *intel ) {
127 unsigned int i;
128 int rc;
129
130 /* Wait until a poll completes successfully */
131 for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
132
133 /* Check for successful poll */
134 if ( ( rc = intelvf_mbox_poll ( intel ) ) == 0 )
135 return 0;
136
137 /* Delay */
138 mdelay ( 1 );
139 }
140
141 DBGC ( intel, "INTEL %p timed out waiting for reset\n", intel );
142 return -ETIMEDOUT;
143}
144
145/**
146 * Send/receive mailbox message
147 *
148 * @v intel Intel device
149 * @v msg Message buffer
150 * @ret rc Return status code
151 */
152int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
153 struct intel_mailbox *mbox = &intel->mbox;
155 uint32_t seen = 0;
156 unsigned int i;
157
158 /* Sanity check */
159 assert ( ! ( msg->hdr & INTELVF_MSG_RESPONSE ) );
160
161 /* Handle mailbox */
162 for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
163
164 /* Attempt to claim mailbox, if we have not yet sent
165 * our message.
166 */
167 if ( ! ( seen & INTELVF_MBCTRL_VFU ) )
168 writel ( INTELVF_MBCTRL_VFU, intel->regs + mbox->ctrl );
169
170 /* Get mailbox status and record observed flags */
171 ctrl = readl ( intel->regs + mbox->ctrl );
172 seen |= ctrl;
173
174 /* If a reset is in progress, clear VFU and abort */
175 if ( ctrl & INTELVF_MBCTRL_RSTI ) {
176 writel ( 0, intel->regs + mbox->ctrl );
177 return -EPIPE;
178 }
179
180 /* Write message to mailbox, if applicable. This
181 * potentially overwrites a message sent by the PF (if
182 * the PF has simultaneously released PFU (thus
183 * allowing our VFU) and asserted PFSTS), but that
184 * doesn't really matter since there are no
185 * unsolicited PF->VF messages that require the actual
186 * message content to be observed.
187 */
188 if ( ctrl & INTELVF_MBCTRL_VFU )
189 intelvf_mbox_write ( intel, msg );
190
191 /* Read message from mailbox, if applicable. */
192 if ( ( seen & INTELVF_MBCTRL_VFU ) &&
193 ( seen & INTELVF_MBCTRL_PFACK ) &&
195 intelvf_mbox_read ( intel, msg );
196
197 /* Acknowledge received message (if applicable),
198 * release VFU lock, and send message (if applicable).
199 */
200 ctrl = ( ( ( ctrl & INTELVF_MBCTRL_PFSTS ) ?
201 INTELVF_MBCTRL_ACK : 0 ) |
202 ( ( ctrl & INTELVF_MBCTRL_VFU ) ?
203 INTELVF_MBCTRL_REQ : 0 ) );
204 writel ( ctrl, intel->regs + mbox->ctrl );
205
206 /* Exit successfully if we have received a response */
207 if ( msg->hdr & INTELVF_MSG_RESPONSE ) {
208
209 /* Sanity check */
210 assert ( seen & INTELVF_MBCTRL_VFU );
211 assert ( seen & INTELVF_MBCTRL_PFACK );
212 assert ( seen & INTELVF_MBCTRL_PFSTS );
213
214 return 0;
215 }
216
217 /* Delay */
218 mdelay ( 1 );
219 }
220
221 DBGC ( intel, "INTEL %p timed out waiting for mailbox (seen %08x)\n",
222 intel, seen );
223 return -ETIMEDOUT;
224}
225
226/**
227 * Send reset message and get initial MAC address
228 *
229 * @v intel Intel device
230 * @v hw_addr Hardware address to fill in, or NULL
231 * @ret rc Return status code
232 */
233int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr ) {
234 union intelvf_msg msg;
235 int rc;
236
237 /* Send reset message */
238 memset ( &msg, 0, sizeof ( msg ) );
240 if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
241 DBGC ( intel, "INTEL %p reset failed: %s\n",
242 intel, strerror ( rc ) );
243 return rc;
244 }
245
246 /* Check response */
248 DBGC ( intel, "INTEL %p reset unexpected response:\n", intel );
249 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
250 return -EPROTO;
251 }
252
253 /* Fill in MAC address, if applicable */
254 if ( hw_addr ) {
255 if ( msg.hdr & INTELVF_MSG_ACK ) {
256 memcpy ( hw_addr, msg.mac.mac, sizeof ( msg.mac.mac ) );
257 DBGC ( intel, "INTEL %p reset assigned MAC address "
258 "%s\n", intel, eth_ntoa ( hw_addr ) );
259 } else {
260 eth_random_addr ( hw_addr );
261 DBGC ( intel, "INTEL %p reset generated MAC address "
262 "%s\n", intel, eth_ntoa ( hw_addr ) );
263 }
264 }
265
266 return 0;
267}
268
269/**
270 * Send set MAC address message
271 *
272 * @v intel Intel device
273 * @v ll_addr Link-layer address
274 * @ret rc Return status code
275 */
276int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
277 union intelvf_msg msg;
278 int rc;
279
280 /* Send set MAC address message */
281 memset ( &msg, 0, sizeof ( msg ) );
283 memcpy ( msg.mac.mac, ll_addr, sizeof ( msg.mac.mac ) );
284 if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
285 DBGC ( intel, "INTEL %p set MAC address failed: %s\n",
286 intel, strerror ( rc ) );
287 return rc;
288 }
289
290 /* Check response */
292 DBGC ( intel, "INTEL %p set MAC address unexpected response:\n",
293 intel );
294 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
295 return -EPROTO;
296 }
297
298 /* Check that we were allowed to set the MAC address */
299 if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
300 DBGC ( intel, "INTEL %p set MAC address refused\n", intel );
301 return -EPERM;
302 }
303
304 return 0;
305}
306
307/**
308 * Send set MTU message
309 *
310 * @v intel Intel device
311 * @v mtu Maximum packet size
312 * @ret rc Return status code
313 */
314int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
315 union intelvf_msg msg;
316 int rc;
317
318 /* Send set MTU message */
319 memset ( &msg, 0, sizeof ( msg ) );
321 msg.mtu.mtu = mtu;
322 if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
323 DBGC ( intel, "INTEL %p set MTU failed: %s\n",
324 intel, strerror ( rc ) );
325 return rc;
326 }
327
328 /* Check response */
330 DBGC ( intel, "INTEL %p set MTU unexpected response:\n",
331 intel );
332 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
333 return -EPROTO;
334 }
335
336 /* Check that we were allowed to set the MTU */
337 if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
338 DBGC ( intel, "INTEL %p set MTU refused\n", intel );
339 return -EPERM;
340 }
341
342 return 0;
343}
__be32 raw[7]
Definition CIB_PRM.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint8_t ctrl
Ring control.
Definition dwmac.h:7
uint32_t mtu
Maximum MTU.
Definition ena.h:17
Error codes.
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition ethernet.c:176
void eth_random_addr(void *hw_addr)
Generate random Ethernet address.
Definition ethernet.c:160
Ethernet protocol.
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define EPROTO
Protocol error.
Definition errno.h:625
#define EPIPE
Broken pipe.
Definition errno.h:620
#define EPERM
Operation not permitted.
Definition errno.h:615
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
iPXE I/O API
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
int intelvf_mbox_poll(struct intel_nic *intel)
Poll mailbox.
Definition intelvf.c:99
static void intelvf_mbox_write(struct intel_nic *intel, const union intelvf_msg *msg)
Write message to mailbox.
Definition intelvf.c:54
int intelvf_mbox_set_mac(struct intel_nic *intel, const uint8_t *ll_addr)
Send set MAC address message.
Definition intelvf.c:276
int intelvf_mbox_reset(struct intel_nic *intel, uint8_t *hw_addr)
Send reset message and get initial MAC address.
Definition intelvf.c:233
static void intelvf_mbox_read(struct intel_nic *intel, union intelvf_msg *msg)
Read message from mailbox.
Definition intelvf.c:75
int intelvf_mbox_msg(struct intel_nic *intel, union intelvf_msg *msg)
Send/receive mailbox message.
Definition intelvf.c:152
int intelvf_mbox_wait(struct intel_nic *intel)
Wait for PF reset to complete.
Definition intelvf.c:126
int intelvf_mbox_set_mtu(struct intel_nic *intel, size_t mtu)
Send set MTU message.
Definition intelvf.c:314
Intel 10/100/1000 virtual function network card driver.
#define INTELVF_MSG_TYPE_RESET
Reset mailbox message.
Definition intelvf.h:33
#define INTELVF_MBCTRL_PFACK
PF acknowledged message.
Definition intelvf.h:25
#define INTELVF_MBCTRL_ACK
PF message received.
Definition intelvf.h:21
#define INTELVF_MSG_RESPONSE
Message is a response.
Definition intelvf.h:57
#define INTELVF_MBCTRL_VFU
Buffer taken by VF.
Definition intelvf.h:22
#define INTELVF_MBOX_MAX_WAIT_MS
Maximum time to wait for mailbox message.
Definition intelvf.h:149
#define INTELVF_MBCTRL_REQ
Request for PF ready.
Definition intelvf.h:20
#define INTELVF_MSG_TYPE_SET_MAC
Set MAC address mailbox message.
Definition intelvf.h:36
#define INTELVF_MSG_TYPE_SET_MTU
Set MTU mailbox message.
Definition intelvf.h:39
#define INTELVF_MSG_ACK
Message ACK flag.
Definition intelvf.h:54
#define INTELVF_MBCTRL_PFSTS
PF wrote a message.
Definition intelvf.h:24
#define INTELVF_MBCTRL_RSTI
PF reset in progress.
Definition intelvf.h:26
#define INTELVF_MSG_TYPE_MASK
Message type mask.
Definition intelvf.h:48
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition message.c:62
Network device management.
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An Intel virtual function mailbox.
Definition intel.h:266
unsigned int mem
Mailbox memory base.
Definition intel.h:270
An Intel network card.
Definition intel.h:289
struct intel_mailbox mbox
Mailbox.
Definition intel.h:309
void * regs
Registers.
Definition intel.h:291
Raw mailbox message.
Definition intelvf.h:124
Definition golan.c:120
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
Mailbox message.
Definition intelvf.h:130
#define readl
Definition w89c840.c:157
#define writel
Definition w89c840.c:160