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