2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
30 #include <ipxe/netdevice.h>
31 #include <ipxe/ethernet.h>
36 * Intel 10/100/1000 virtual function network card driver
40 /******************************************************************************
44 ******************************************************************************
48 * Write message to mailbox
50 * @v intel Intel device
53 static void intelvf_mbox_write ( struct intel_nic *intel,
54 const union intelvf_msg *msg ) {
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] ) ) ) );
64 DBGC2 ( intel, "\n" );
68 * Read message from mailbox
70 * @v intel Intel device
73 static void intelvf_mbox_read ( struct intel_nic *intel,
74 union intelvf_msg *msg ) {
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] );
84 DBGC2 ( intel, "\n" );
90 * @v intel Intel device
91 * @ret rc Return status code
93 * Note that polling the mailbox may fail if the underlying PF is
96 int intelvf_mbox_poll ( struct intel_nic *intel ) {
97 struct intel_mailbox *mbox = &intel->mbox;
98 union intelvf_msg msg;
101 /* Get mailbox status */
102 ctrl = readl ( intel->regs + mbox->ctrl );
104 /* Fail if a reset is in progress */
105 if ( ctrl & INTELVF_MBCTRL_RSTI )
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 );
118 * Wait for PF reset to complete
120 * @v intel Intel device
121 * @ret rc Return status code
123 int intelvf_mbox_wait ( struct intel_nic *intel ) {
127 /* Wait until a poll completes successfully */
128 for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
130 /* Check for successful poll */
131 if ( ( rc = intelvf_mbox_poll ( intel ) ) == 0 )
138 DBGC ( intel, "INTEL %p timed out waiting for reset\n", intel );
143 * Send/receive mailbox message
145 * @v intel Intel device
146 * @v msg Message buffer
147 * @ret rc Return status code
149 int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
150 struct intel_mailbox *mbox = &intel->mbox;
156 assert ( ! ( msg->hdr & INTELVF_MSG_RESPONSE ) );
159 for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
161 /* Attempt to claim mailbox, if we have not yet sent
164 if ( ! ( seen & INTELVF_MBCTRL_VFU ) )
165 writel ( INTELVF_MBCTRL_VFU, intel->regs + mbox->ctrl );
167 /* Get mailbox status and record observed flags */
168 ctrl = readl ( intel->regs + mbox->ctrl );
171 /* If a reset is in progress, clear VFU and abort */
172 if ( ctrl & INTELVF_MBCTRL_RSTI ) {
173 writel ( 0, intel->regs + mbox->ctrl );
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.
185 if ( ctrl & INTELVF_MBCTRL_VFU )
186 intelvf_mbox_write ( intel, msg );
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 );
194 /* Acknowledge received message (if applicable),
195 * release VFU lock, and send message (if applicable).
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 );
203 /* Exit successfully if we have received a response */
204 if ( msg->hdr & INTELVF_MSG_RESPONSE ) {
207 assert ( seen & INTELVF_MBCTRL_VFU );
208 assert ( seen & INTELVF_MBCTRL_PFACK );
209 assert ( seen & INTELVF_MBCTRL_PFSTS );
218 DBGC ( intel, "INTEL %p timed out waiting for mailbox (seen %08x)\n",
224 * Send reset message and get initial MAC address
226 * @v intel Intel device
227 * @v hw_addr Hardware address to fill in, or NULL
228 * @ret rc Return status code
230 int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr ) {
231 union intelvf_msg msg;
234 /* Send reset message */
235 memset ( &msg, 0, sizeof ( msg ) );
236 msg.hdr = INTELVF_MSG_TYPE_RESET;
237 if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
238 DBGC ( intel, "INTEL %p reset failed: %s\n",
239 intel, strerror ( rc ) );
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 ) );
250 /* Fill in MAC address, if applicable */
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 ) );
257 eth_random_addr ( hw_addr );
258 DBGC ( intel, "INTEL %p reset generated MAC address "
259 "%s\n", intel, eth_ntoa ( hw_addr ) );
267 * Send set MAC address message
269 * @v intel Intel device
270 * @v ll_addr Link-layer address
271 * @ret rc Return status code
273 int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
274 union intelvf_msg msg;
277 /* Send set MAC address message */
278 memset ( &msg, 0, sizeof ( msg ) );
279 msg.hdr = INTELVF_MSG_TYPE_SET_MAC;
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 ) );
288 if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MAC ) {
289 DBGC ( intel, "INTEL %p set MAC address unexpected response:\n",
291 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
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 );
305 * Send set MTU message
307 * @v intel Intel device
308 * @v mtu Maximum packet size
309 * @ret rc Return status code
311 int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
312 union intelvf_msg msg;
315 /* Send set MTU message */
316 memset ( &msg, 0, sizeof ( msg ) );
317 msg.hdr = INTELVF_MSG_TYPE_SET_MTU;
319 if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
320 DBGC ( intel, "INTEL %p set MTU failed: %s\n",
321 intel, strerror ( rc ) );
326 if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MTU ) {
327 DBGC ( intel, "INTEL %p set MTU unexpected response:\n",
329 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
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 );