iPXE
intelvf.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <errno.h>
00029 #include <ipxe/io.h>
00030 #include <ipxe/netdevice.h>
00031 #include <ipxe/ethernet.h>
00032 #include "intelvf.h"
00033 
00034 /** @file
00035  *
00036  * Intel 10/100/1000 virtual function network card driver
00037  *
00038  */
00039 
00040 /******************************************************************************
00041  *
00042  * Mailbox messages
00043  *
00044  ******************************************************************************
00045  */
00046 
00047 /**
00048  * Write message to mailbox
00049  *
00050  * @v intel             Intel device
00051  * @v msg               Message
00052  */
00053 static void intelvf_mbox_write ( struct intel_nic *intel,
00054                                  const union intelvf_msg *msg ) {
00055         unsigned int i;
00056 
00057         /* Write message */
00058         DBGC2 ( intel, "INTEL %p sending message", intel );
00059         for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( msg->dword[0] ) ) ; i++){
00060                 DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), msg->dword[i] );
00061                 writel ( msg->dword[i], ( intel->regs + intel->mbox.mem +
00062                                           ( i * sizeof ( msg->dword[0] ) ) ) );
00063         }
00064         DBGC2 ( intel, "\n" );
00065 }
00066 
00067 /**
00068  * Read message from mailbox
00069  *
00070  * @v intel             Intel device
00071  * @v msg               Message
00072  */
00073 static void intelvf_mbox_read ( struct intel_nic *intel,
00074                                 union intelvf_msg *msg ) {
00075         unsigned int i;
00076 
00077         /* Read message */
00078         DBGC2 ( intel, "INTEL %p received message", intel );
00079         for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( msg->dword[0] ) ) ; i++){
00080                 msg->dword[i] = readl ( intel->regs + intel->mbox.mem +
00081                                         ( i * sizeof ( msg->dword[0] ) ) );
00082                 DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), msg->dword[i] );
00083         }
00084         DBGC2 ( intel, "\n" );
00085 }
00086 
00087 /**
00088  * Poll mailbox
00089  *
00090  * @v intel             Intel device
00091  * @ret rc              Return status code
00092  *
00093  * Note that polling the mailbox may fail if the underlying PF is
00094  * reset.
00095  */
00096 int intelvf_mbox_poll ( struct intel_nic *intel ) {
00097         struct intel_mailbox *mbox = &intel->mbox;
00098         union intelvf_msg msg;
00099         uint32_t ctrl;
00100 
00101         /* Get mailbox status */
00102         ctrl = readl ( intel->regs + mbox->ctrl );
00103 
00104         /* Fail if a reset is in progress */
00105         if ( ctrl & INTELVF_MBCTRL_RSTI )
00106                 return -EPIPE;
00107 
00108         /* Acknowledge (and ignore) any received messages */
00109         if ( ctrl & INTELVF_MBCTRL_PFSTS ) {
00110                 intelvf_mbox_read ( intel, &msg );
00111                 writel ( INTELVF_MBCTRL_ACK, intel->regs + mbox->ctrl );
00112         }
00113 
00114         return 0;
00115 }
00116 
00117 /**
00118  * Wait for PF reset to complete
00119  *
00120  * @v intel             Intel device
00121  * @ret rc              Return status code
00122  */
00123 int intelvf_mbox_wait ( struct intel_nic *intel ) {
00124         unsigned int i;
00125         int rc;
00126 
00127         /* Wait until a poll completes successfully */
00128         for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
00129 
00130                 /* Check for successful poll */
00131                 if ( ( rc = intelvf_mbox_poll ( intel ) ) == 0 )
00132                         return 0;
00133 
00134                 /* Delay */
00135                 mdelay ( 1 );
00136         }
00137 
00138         DBGC ( intel, "INTEL %p timed out waiting for reset\n", intel );
00139         return -ETIMEDOUT;
00140 }
00141 
00142 /**
00143  * Send/receive mailbox message
00144  *
00145  * @v intel             Intel device
00146  * @v msg               Message buffer
00147  * @ret rc              Return status code
00148  */
00149 int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
00150         struct intel_mailbox *mbox = &intel->mbox;
00151         uint32_t ctrl;
00152         uint32_t seen = 0;
00153         unsigned int i;
00154 
00155         /* Sanity check */
00156         assert ( ! ( msg->hdr & INTELVF_MSG_RESPONSE ) );
00157 
00158         /* Handle mailbox */
00159         for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
00160 
00161                 /* Attempt to claim mailbox, if we have not yet sent
00162                  * our message.
00163                  */
00164                 if ( ! ( seen & INTELVF_MBCTRL_VFU ) )
00165                         writel ( INTELVF_MBCTRL_VFU, intel->regs + mbox->ctrl );
00166 
00167                 /* Get mailbox status and record observed flags */
00168                 ctrl = readl ( intel->regs + mbox->ctrl );
00169                 seen |= ctrl;
00170 
00171                 /* If a reset is in progress, clear VFU and abort */
00172                 if ( ctrl & INTELVF_MBCTRL_RSTI ) {
00173                         writel ( 0, intel->regs + mbox->ctrl );
00174                         return -EPIPE;
00175                 }
00176 
00177                 /* Write message to mailbox, if applicable.  This
00178                  * potentially overwrites a message sent by the PF (if
00179                  * the PF has simultaneously released PFU (thus
00180                  * allowing our VFU) and asserted PFSTS), but that
00181                  * doesn't really matter since there are no
00182                  * unsolicited PF->VF messages that require the actual
00183                  * message content to be observed.
00184                  */
00185                 if ( ctrl & INTELVF_MBCTRL_VFU )
00186                         intelvf_mbox_write ( intel, msg );
00187 
00188                 /* Read message from mailbox, if applicable. */
00189                 if ( ( seen & INTELVF_MBCTRL_VFU ) &&
00190                      ( seen & INTELVF_MBCTRL_PFACK ) &&
00191                      ( ctrl & INTELVF_MBCTRL_PFSTS ) )
00192                         intelvf_mbox_read ( intel, msg );
00193 
00194                 /* Acknowledge received message (if applicable),
00195                  * release VFU lock, and send message (if applicable).
00196                  */
00197                 ctrl = ( ( ( ctrl & INTELVF_MBCTRL_PFSTS ) ?
00198                            INTELVF_MBCTRL_ACK : 0 ) |
00199                          ( ( ctrl & INTELVF_MBCTRL_VFU ) ?
00200                            INTELVF_MBCTRL_REQ : 0 ) );
00201                 writel ( ctrl, intel->regs + mbox->ctrl );
00202 
00203                 /* Exit successfully if we have received a response */
00204                 if ( msg->hdr & INTELVF_MSG_RESPONSE ) {
00205 
00206                         /* Sanity check */
00207                         assert ( seen & INTELVF_MBCTRL_VFU );
00208                         assert ( seen & INTELVF_MBCTRL_PFACK );
00209                         assert ( seen & INTELVF_MBCTRL_PFSTS );
00210 
00211                         return 0;
00212                 }
00213 
00214                 /* Delay */
00215                 mdelay ( 1 );
00216         }
00217 
00218         DBGC ( intel, "INTEL %p timed out waiting for mailbox (seen %08x)\n",
00219                intel, seen );
00220         return -ETIMEDOUT;
00221 }
00222 
00223 /**
00224  * Send reset message and get initial MAC address
00225  *
00226  * @v intel             Intel device
00227  * @v hw_addr           Hardware address to fill in, or NULL
00228  * @ret rc              Return status code
00229  */
00230 int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr ) {
00231         union intelvf_msg msg;
00232         int rc;
00233 
00234         /* Send reset message */
00235         memset ( &msg, 0, sizeof ( msg ) );
00236         msg.hdr = INTELVF_MSG_TYPE_RESET;
00237         if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
00238                 DBGC ( intel, "INTEL %p reset failed: %s\n",
00239                        intel, strerror ( rc ) );
00240                 return rc;
00241         }
00242 
00243         /* Check response */
00244         if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_RESET ) {
00245                 DBGC ( intel, "INTEL %p reset unexpected response:\n", intel );
00246                 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
00247                 return -EPROTO;
00248         }
00249 
00250         /* Fill in MAC address, if applicable */
00251         if ( hw_addr ) {
00252                 if ( msg.hdr & INTELVF_MSG_ACK ) {
00253                         memcpy ( hw_addr, msg.mac.mac, sizeof ( msg.mac.mac ) );
00254                         DBGC ( intel, "INTEL %p reset assigned MAC address "
00255                                "%s\n", intel, eth_ntoa ( hw_addr ) );
00256                 } else {
00257                         eth_random_addr ( hw_addr );
00258                         DBGC ( intel, "INTEL %p reset generated MAC address "
00259                                "%s\n", intel, eth_ntoa ( hw_addr ) );
00260                 }
00261         }
00262 
00263         return 0;
00264 }
00265 
00266 /**
00267  * Send set MAC address message
00268  *
00269  * @v intel             Intel device
00270  * @v ll_addr           Link-layer address
00271  * @ret rc              Return status code
00272  */
00273 int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
00274         union intelvf_msg msg;
00275         int rc;
00276 
00277         /* Send set MAC address message */
00278         memset ( &msg, 0, sizeof ( msg ) );
00279         msg.hdr = INTELVF_MSG_TYPE_SET_MAC;
00280         memcpy ( msg.mac.mac, ll_addr, sizeof ( msg.mac.mac ) );
00281         if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
00282                 DBGC ( intel, "INTEL %p set MAC address failed: %s\n",
00283                        intel, strerror ( rc ) );
00284                 return rc;
00285         }
00286 
00287         /* Check response */
00288         if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MAC ) {
00289                 DBGC ( intel, "INTEL %p set MAC address unexpected response:\n",
00290                        intel );
00291                 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
00292                 return -EPROTO;
00293         }
00294 
00295         /* Check that we were allowed to set the MAC address */
00296         if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
00297                 DBGC ( intel, "INTEL %p set MAC address refused\n", intel );
00298                 return -EPERM;
00299         }
00300 
00301         return 0;
00302 }
00303 
00304 /**
00305  * Send set MTU message
00306  *
00307  * @v intel             Intel device
00308  * @v mtu               Maximum packet size
00309  * @ret rc              Return status code
00310  */
00311 int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
00312         union intelvf_msg msg;
00313         int rc;
00314 
00315         /* Send set MTU message */
00316         memset ( &msg, 0, sizeof ( msg ) );
00317         msg.hdr = INTELVF_MSG_TYPE_SET_MTU;
00318         msg.mtu.mtu = mtu;
00319         if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
00320                 DBGC ( intel, "INTEL %p set MTU failed: %s\n",
00321                        intel, strerror ( rc ) );
00322                 return rc;
00323         }
00324 
00325         /* Check response */
00326         if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MTU ) {
00327                 DBGC ( intel, "INTEL %p set MTU unexpected response:\n",
00328                        intel );
00329                 DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
00330                 return -EPROTO;
00331         }
00332 
00333         /* Check that we were allowed to set the MTU */
00334         if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
00335                 DBGC ( intel, "INTEL %p set MTU refused\n", intel );
00336                 return -EPERM;
00337         }
00338 
00339         return 0;
00340 }