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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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  */
54 static 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  */
75 static 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  */
99 int intelvf_mbox_poll ( struct intel_nic *intel ) {
100  struct intel_mailbox *mbox = &intel->mbox;
101  union intelvf_msg msg;
102  uint32_t ctrl;
103 
104  /* Get mailbox status */
105  ctrl = readl ( intel->regs + mbox->ctrl );
106 
107  /* Fail if a reset is in progress */
108  if ( ctrl & INTELVF_MBCTRL_RSTI )
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  */
126 int 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  */
152 int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
153  struct intel_mailbox *mbox = &intel->mbox;
154  uint32_t ctrl;
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 ) &&
194  ( ctrl & INTELVF_MBCTRL_PFSTS ) )
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  */
233 int 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 */
247  if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_RESET ) {
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  */
276 int 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  */
314 int 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 }
void * regs
Registers.
Definition: intel.h:292
#define INTELVF_MSG_TYPE_SET_MAC
Set MAC address mailbox message.
Definition: intelvf.h:36
iPXE I/O API
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
int intelvf_mbox_set_mtu(struct intel_nic *intel, size_t mtu)
Send set MTU message.
Definition: intelvf.c:314
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition: message.c:62
static void intelvf_mbox_write(struct intel_nic *intel, const union intelvf_msg *msg)
Write message to mailbox.
Definition: intelvf.c:54
Error codes.
struct intel_mailbox mbox
Mailbox.
Definition: intel.h:310
#define EPIPE
Broken pipe.
Definition: errno.h:620
uint32_t readl(volatile uint32_t *io_addr)
Read 32-bit dword from memory-mapped device.
#define DBGC(...)
Definition: compiler.h:505
Raw mailbox message.
Definition: intelvf.h:124
Mailbox message.
Definition: intelvf.h:130
#define INTELVF_MBCTRL_PFACK
PF acknowledged message.
Definition: intelvf.h:25
int intelvf_mbox_set_mac(struct intel_nic *intel, const uint8_t *ll_addr)
Send set MAC address message.
Definition: intelvf.c:276
void * memcpy(void *dest, const void *src, size_t len) __nonnull
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Ethernet protocol.
#define DBGC_HDA(...)
Definition: compiler.h:506
void writel(uint32_t data, volatile uint32_t *io_addr)
Write 32-bit dword to memory-mapped device.
Definition: golan.c:120
#define INTELVF_MBCTRL_REQ
Request for PF ready.
Definition: intelvf.h:20
#define EPROTO
Protocol error.
Definition: errno.h:625
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
#define INTELVF_MBCTRL_PFSTS
PF wrote a message.
Definition: intelvf.h:24
#define INTELVF_MSG_ACK
Message ACK flag.
Definition: intelvf.h:54
int intelvf_mbox_msg(struct intel_nic *intel, union intelvf_msg *msg)
Send/receive mailbox message.
Definition: intelvf.c:152
An Intel virtual function mailbox.
Definition: intel.h:267
int intelvf_mbox_reset(struct intel_nic *intel, uint8_t *hw_addr)
Send reset message and get initial MAC address.
Definition: intelvf.c:233
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:176
unsigned char uint8_t
Definition: stdint.h:10
#define INTELVF_MSG_TYPE_SET_MTU
Set MTU mailbox message.
Definition: intelvf.h:39
#define INTELVF_MBCTRL_ACK
PF message received.
Definition: intelvf.h:21
#define INTELVF_MSG_RESPONSE
Message is a response.
Definition: intelvf.h:57
unsigned int uint32_t
Definition: stdint.h:12
#define INTELVF_MBCTRL_RSTI
PF reset in progress.
Definition: intelvf.h:26
unsigned int mem
Mailbox memory base.
Definition: intel.h:271
#define EPERM
Operation not permitted.
Definition: errno.h:615
Network device management.
#define INTELVF_MBCTRL_VFU
Buffer taken by VF.
Definition: intelvf.h:22
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define INTELVF_MBOX_MAX_WAIT_MS
Maximum time to wait for mailbox message.
Definition: intelvf.h:149
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:79
#define INTELVF_MSG_TYPE_MASK
Message type mask.
Definition: intelvf.h:48
#define DBGC2(...)
Definition: compiler.h:522
static void intelvf_mbox_read(struct intel_nic *intel, union intelvf_msg *msg)
Read message from mailbox.
Definition: intelvf.c:75
uint32_t mtu
Maximum MTU.
Definition: ena.h:28
int intelvf_mbox_poll(struct intel_nic *intel)
Poll mailbox.
Definition: intelvf.c:99
#define INTELVF_MSG_TYPE_RESET
Reset mailbox message.
Definition: intelvf.h:33
uint8_t ctrl
Ring control.
Definition: dwmac.h:18
An Intel network card.
Definition: intel.h:290
__be32 raw[7]
Definition: CIB_PRM.h:28
FILE_SECBOOT(PERMITTED)
Intel 10/100/1000 virtual function network card driver.
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:670
String functions.
void eth_random_addr(void *hw_addr)
Generate random Ethernet address.
Definition: ethernet.c:160
int intelvf_mbox_wait(struct intel_nic *intel)
Wait for PF reset to complete.
Definition: intelvf.c:126
void * memset(void *dest, int character, size_t len) __nonnull