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  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 int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
150  struct intel_mailbox *mbox = &intel->mbox;
151  uint32_t ctrl;
152  uint32_t seen = 0;
153  unsigned int i;
154 
155  /* Sanity check */
156  assert ( ! ( msg->hdr & INTELVF_MSG_RESPONSE ) );
157 
158  /* Handle mailbox */
159  for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
160 
161  /* Attempt to claim mailbox, if we have not yet sent
162  * our message.
163  */
164  if ( ! ( seen & INTELVF_MBCTRL_VFU ) )
165  writel ( INTELVF_MBCTRL_VFU, intel->regs + mbox->ctrl );
166 
167  /* Get mailbox status and record observed flags */
168  ctrl = readl ( intel->regs + mbox->ctrl );
169  seen |= ctrl;
170 
171  /* If a reset is in progress, clear VFU and abort */
172  if ( ctrl & INTELVF_MBCTRL_RSTI ) {
173  writel ( 0, intel->regs + mbox->ctrl );
174  return -EPIPE;
175  }
176 
177  /* Write message to mailbox, if applicable. This
178  * potentially overwrites a message sent by the PF (if
179  * the PF has simultaneously released PFU (thus
180  * allowing our VFU) and asserted PFSTS), but that
181  * doesn't really matter since there are no
182  * unsolicited PF->VF messages that require the actual
183  * message content to be observed.
184  */
185  if ( ctrl & INTELVF_MBCTRL_VFU )
186  intelvf_mbox_write ( intel, msg );
187 
188  /* Read message from mailbox, if applicable. */
189  if ( ( seen & INTELVF_MBCTRL_VFU ) &&
190  ( seen & INTELVF_MBCTRL_PFACK ) &&
191  ( ctrl & INTELVF_MBCTRL_PFSTS ) )
192  intelvf_mbox_read ( intel, msg );
193 
194  /* Acknowledge received message (if applicable),
195  * release VFU lock, and send message (if applicable).
196  */
197  ctrl = ( ( ( ctrl & INTELVF_MBCTRL_PFSTS ) ?
198  INTELVF_MBCTRL_ACK : 0 ) |
199  ( ( ctrl & INTELVF_MBCTRL_VFU ) ?
200  INTELVF_MBCTRL_REQ : 0 ) );
201  writel ( ctrl, intel->regs + mbox->ctrl );
202 
203  /* Exit successfully if we have received a response */
204  if ( msg->hdr & INTELVF_MSG_RESPONSE ) {
205 
206  /* Sanity check */
207  assert ( seen & INTELVF_MBCTRL_VFU );
208  assert ( seen & INTELVF_MBCTRL_PFACK );
209  assert ( seen & INTELVF_MBCTRL_PFSTS );
210 
211  return 0;
212  }
213 
214  /* Delay */
215  mdelay ( 1 );
216  }
217 
218  DBGC ( intel, "INTEL %p timed out waiting for mailbox (seen %08x)\n",
219  intel, seen );
220  return -ETIMEDOUT;
221 }
222 
223 /**
224  * Send reset message and get initial MAC address
225  *
226  * @v intel Intel device
227  * @v hw_addr Hardware address to fill in, or NULL
228  * @ret rc Return status code
229  */
230 int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr ) {
231  union intelvf_msg msg;
232  int rc;
233 
234  /* Send reset message */
235  memset ( &msg, 0, sizeof ( msg ) );
237  if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
238  DBGC ( intel, "INTEL %p reset failed: %s\n",
239  intel, strerror ( rc ) );
240  return rc;
241  }
242 
243  /* Check response */
244  if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_RESET ) {
245  DBGC ( intel, "INTEL %p reset unexpected response:\n", intel );
246  DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
247  return -EPROTO;
248  }
249 
250  /* Fill in MAC address, if applicable */
251  if ( hw_addr ) {
252  if ( msg.hdr & INTELVF_MSG_ACK ) {
253  memcpy ( hw_addr, msg.mac.mac, sizeof ( msg.mac.mac ) );
254  DBGC ( intel, "INTEL %p reset assigned MAC address "
255  "%s\n", intel, eth_ntoa ( hw_addr ) );
256  } else {
257  eth_random_addr ( hw_addr );
258  DBGC ( intel, "INTEL %p reset generated MAC address "
259  "%s\n", intel, eth_ntoa ( hw_addr ) );
260  }
261  }
262 
263  return 0;
264 }
265 
266 /**
267  * Send set MAC address message
268  *
269  * @v intel Intel device
270  * @v ll_addr Link-layer address
271  * @ret rc Return status code
272  */
273 int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
274  union intelvf_msg msg;
275  int rc;
276 
277  /* Send set MAC address message */
278  memset ( &msg, 0, sizeof ( msg ) );
280  memcpy ( msg.mac.mac, ll_addr, sizeof ( msg.mac.mac ) );
281  if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
282  DBGC ( intel, "INTEL %p set MAC address failed: %s\n",
283  intel, strerror ( rc ) );
284  return rc;
285  }
286 
287  /* Check response */
289  DBGC ( intel, "INTEL %p set MAC address unexpected response:\n",
290  intel );
291  DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
292  return -EPROTO;
293  }
294 
295  /* Check that we were allowed to set the MAC address */
296  if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
297  DBGC ( intel, "INTEL %p set MAC address refused\n", intel );
298  return -EPERM;
299  }
300 
301  return 0;
302 }
303 
304 /**
305  * Send set MTU message
306  *
307  * @v intel Intel device
308  * @v mtu Maximum packet size
309  * @ret rc Return status code
310  */
311 int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
312  union intelvf_msg msg;
313  int rc;
314 
315  /* Send set MTU message */
316  memset ( &msg, 0, sizeof ( msg ) );
318  msg.mtu.mtu = mtu;
319  if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
320  DBGC ( intel, "INTEL %p set MTU failed: %s\n",
321  intel, strerror ( rc ) );
322  return rc;
323  }
324 
325  /* Check response */
327  DBGC ( intel, "INTEL %p set MTU unexpected response:\n",
328  intel );
329  DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
330  return -EPROTO;
331  }
332 
333  /* Check that we were allowed to set the MTU */
334  if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
335  DBGC ( intel, "INTEL %p set MTU refused\n", intel );
336  return -EPERM;
337  }
338 
339  return 0;
340 }
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:311
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
Mailbox message.
Definition: intelvf.h:123
#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:273
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:149
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:230
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:142
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:73
uint32_t mtu
Maximum MTU.
Definition: ena.h:28
int intelvf_mbox_poll(struct intel_nic *intel)
Poll mailbox.
Definition: intelvf.c:96
#define INTELVF_MSG_TYPE_RESET
Reset mailbox message.
Definition: intelvf.h:32
An Intel network card.
Definition: intel.h:278
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:123
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