aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2015-05-19 12:20:37 +0100
committerMichael Brown <mcb30@ipxe.org>2015-05-19 13:03:02 +0100
commit99f87b23382ab9cf1d071f4efea834e18d4511e0 (patch)
treec8e9ddc4f34af6b51fe3c632d66507dd2600626b /src
parent51b6a1c835656903ccf9162b61e0c3cc673bbbe8 (diff)
downloadipxe-99f87b23382ab9cf1d071f4efea834e18d4511e0.zip
ipxe-99f87b23382ab9cf1d071f4efea834e18d4511e0.tar.gz
ipxe-99f87b23382ab9cf1d071f4efea834e18d4511e0.tar.bz2
[intel] Fix operation when physical function has jumbo frames enabled
When jumbo frames are enabled, the Linux ixgbe physical function driver will disable the virtual function's receive datapath by default, and will enable it only if the virtual function negotiates API version 1.1 (or higher) and explicitly selects an MTU. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r--src/drivers/net/intelvf.c41
-rw-r--r--src/drivers/net/intelvf.h25
-rw-r--r--src/drivers/net/intelxvf.c64
-rw-r--r--src/drivers/net/intelxvf.h6
4 files changed, 134 insertions, 2 deletions
diff --git a/src/drivers/net/intelvf.c b/src/drivers/net/intelvf.c
index c8d3a4d..ac6fea7 100644
--- a/src/drivers/net/intelvf.c
+++ b/src/drivers/net/intelvf.c
@@ -146,8 +146,7 @@ int intelvf_mbox_wait ( struct intel_nic *intel ) {
* @v msg Message buffer
* @ret rc Return status code
*/
-static int intelvf_mbox_msg ( struct intel_nic *intel,
- union intelvf_msg *msg ) {
+int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
struct intel_mailbox *mbox = &intel->mbox;
uint32_t ctrl;
uint32_t seen = 0;
@@ -301,3 +300,41 @@ int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
return 0;
}
+
+/**
+ * Send set MTU message
+ *
+ * @v intel Intel device
+ * @v mtu Maximum packet size
+ * @ret rc Return status code
+ */
+int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send set MTU message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELVF_MSG_TYPE_SET_MTU;
+ msg.mtu.mtu = mtu;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p set MTU failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MTU ) {
+ DBGC ( intel, "INTEL %p set MTU unexpected response:\n",
+ intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that we were allowed to set the MTU */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p set MTU refused\n", intel );
+ return -EPERM;
+ }
+
+ return 0;
+}
diff --git a/src/drivers/net/intelvf.h b/src/drivers/net/intelvf.h
index d03a7f1..d2f98d8 100644
--- a/src/drivers/net/intelvf.h
+++ b/src/drivers/net/intelvf.h
@@ -34,6 +34,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Set MAC address mailbox message */
#define INTELVF_MSG_TYPE_SET_MAC 0x00000002UL
+/** Set MTU mailbox message */
+#define INTELVF_MSG_TYPE_SET_MTU 0x00000005UL
+
/** Control ("ping") mailbox message */
#define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
@@ -59,12 +62,32 @@ struct intelvf_msg_mac {
uint8_t reserved[ (-ETH_ALEN) & 0x3 ];
} __attribute__ (( packed ));
+/** Version number mailbox message */
+struct intelvf_msg_version {
+ /** Message header */
+ uint32_t hdr;
+ /** API version */
+ uint32_t version;
+} __attribute__ (( packed ));
+
+/** MTU mailbox message */
+struct intelvf_msg_mtu {
+ /** Message header */
+ uint32_t hdr;
+ /** Maximum packet size */
+ uint32_t mtu;
+} __attribute__ (( packed ));
+
/** Mailbox message */
union intelvf_msg {
/** Message header */
uint32_t hdr;
/** MAC address message */
struct intelvf_msg_mac mac;
+ /** Version number message */
+ struct intelvf_msg_version version;
+ /** MTU message */
+ struct intelvf_msg_mtu mtu;
/** Raw dwords */
uint32_t dword[0];
};
@@ -75,10 +98,12 @@ union intelvf_msg {
*/
#define INTELVF_MBOX_MAX_WAIT_MS 500
+extern int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg );
extern int intelvf_mbox_poll ( struct intel_nic *intel );
extern int intelvf_mbox_wait ( struct intel_nic *intel );
extern int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr );
extern int intelvf_mbox_set_mac ( struct intel_nic *intel,
const uint8_t *ll_addr );
+extern int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu );
#endif /* _INTELVF_H */
diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c
index c03fbe8..05e34c1 100644
--- a/src/drivers/net/intelxvf.c
+++ b/src/drivers/net/intelxvf.c
@@ -111,6 +111,53 @@ static void intelxvf_check_link ( struct net_device *netdev ) {
/******************************************************************************
*
+ * Mailbox messages
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Send negotiate API version message
+ *
+ * @v intel Intel device
+ * @v version Requested version
+ * @ret rc Return status code
+ */
+static int intelxvf_mbox_version ( struct intel_nic *intel,
+ unsigned int version ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send set MTU message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELXVF_MSG_TYPE_VERSION;
+ msg.version.version = version;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p negotiate API version failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELXVF_MSG_TYPE_VERSION ){
+ DBGC ( intel, "INTEL %p negotiate API version unexpected "
+ "response:\n", intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that this version is supported */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p negotiate API version failed\n",
+ intel );
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
* Network device interface
*
******************************************************************************
@@ -138,6 +185,15 @@ static int intelxvf_open ( struct net_device *netdev ) {
goto err_mbox_reset;
}
+ /* Negotiate API version 1.1. If we do not negotiate at least
+ * this version, then the RX datapath will remain disabled if
+ * the PF has jumbo frames enabled.
+ *
+ * Ignore failures, since the host may not actually support
+ * v1.1.
+ */
+ intelxvf_mbox_version ( intel, INTELXVF_MSG_VERSION_1_1 );
+
/* Set MAC address */
if ( ( rc = intelvf_mbox_set_mac ( intel, netdev->ll_addr ) ) != 0 ) {
DBGC ( intel, "INTEL %p could not set MAC address: %s\n",
@@ -145,6 +201,13 @@ static int intelxvf_open ( struct net_device *netdev ) {
goto err_mbox_set_mac;
}
+ /* Set MTU */
+ if ( ( rc = intelvf_mbox_set_mtu ( intel, netdev->max_pkt_len ) ) != 0){
+ DBGC ( intel, "INTEL %p could not set MTU %zd: %s\n",
+ intel, netdev->max_pkt_len, strerror ( rc ) );
+ goto err_mbox_set_mtu;
+ }
+
/* Create transmit descriptor ring */
if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
goto err_create_tx;
@@ -188,6 +251,7 @@ static int intelxvf_open ( struct net_device *netdev ) {
err_create_rx:
intel_destroy_ring ( intel, &intel->tx );
err_create_tx:
+ err_mbox_set_mtu:
err_mbox_set_mac:
err_mbox_reset:
intelxvf_reset ( intel );
diff --git a/src/drivers/net/intelxvf.h b/src/drivers/net/intelxvf.h
index aae58c9..ad046a6 100644
--- a/src/drivers/net/intelxvf.h
+++ b/src/drivers/net/intelxvf.h
@@ -95,4 +95,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Good Packets Transmitted Count High */
#define INTELXVF_GOTCH 0x2024
+/** Negotiate API version mailbox message */
+#define INTELXVF_MSG_TYPE_VERSION 0x00000008UL
+
+/** API version 1.1 */
+#define INTELXVF_MSG_VERSION_1_1 0x00000002UL
+
#endif /* _INTELXVF_H */