return 0;
}
+
+/**
+ * Get queue configuration
+ *
+ * @v intel Intel device
+ * @v vlan_thing VLAN hand-waving thing to fill in
+ * @ret rc Return status code
+ */
+int intelvf_mbox_queues ( struct intel_nic *intel, int *vlan_thing ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send queue configuration message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELVF_MSG_TYPE_GET_QUEUES;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p get queue configuration failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) !=INTELVF_MSG_TYPE_GET_QUEUES){
+ DBGC ( intel, "INTEL %p get queue configuration unexpected "
+ "response:\n", intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that we were allowed to get the queue configuration */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p get queue configuration refused\n",
+ intel );
+ return -EPERM;
+ }
+
+ /* Extract VLAN hand-waving thing */
+ *vlan_thing = msg.queues.vlan_thing;
+
+ return 0;
+}
/** Set MTU mailbox message */
#define INTELVF_MSG_TYPE_SET_MTU 0x00000005UL
+/** Get queue configuration message */
+#define INTELVF_MSG_TYPE_GET_QUEUES 0x00000009UL
+
/** Control ("ping") mailbox message */
#define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
uint32_t mtu;
} __attribute__ (( packed ));
+/** Queue configuration mailbox message (API v1.1+ only) */
+struct intelvf_msg_queues {
+ /** Message header */
+ uint32_t hdr;
+ /** Maximum number of transmit queues */
+ uint32_t tx;
+ /** Maximum number of receive queues */
+ uint32_t rx;
+ /** VLAN hand-waving thing
+ *
+ * This is labelled IXGBE_VF_TRANS_VLAN in the Linux driver.
+ *
+ * A comment in the Linux PF driver describes it as "notify VF
+ * of need for VLAN tag stripping, and correct queue". It
+ * will be filled with a non-zero value if the PF is enforcing
+ * the use of a single VLAN tag. It will also be filled with
+ * a non-zero value if the PF is using multiple traffic
+ * classes.
+ *
+ * The Linux VF driver seems to treat this field as being
+ * simply the number of traffic classes, and gives it no
+ * VLAN-related interpretation.
+ *
+ * If the PF is enforcing the use of a single VLAN tag for the
+ * VF, then the VLAN tag will be transparently inserted in
+ * transmitted packets (via the PFVMVIR register) but will
+ * still be visible in received packets. The Linux VF driver
+ * handles this unexpected VLAN tag by simply ignoring any
+ * unrecognised VLAN tags.
+ *
+ * We choose to strip and ignore the VLAN tag if this field
+ * has a non-zero value.
+ */
+ uint32_t vlan_thing;
+ /** Default queue */
+ uint32_t dflt;
+} __attribute__ (( packed ));
+
/** Mailbox message */
union intelvf_msg {
/** Message header */
struct intelvf_msg_version version;
/** MTU message */
struct intelvf_msg_mtu mtu;
+ /** Queue configuration message */
+ struct intelvf_msg_queues queues;
/** Raw dwords */
uint32_t dword[0];
};
/** Receive Descriptor register block */
#define INTELX_RD 0x01000UL
+/** Receive Descriptor Control Register */
+#define INTELX_RXDCTL_VME 0x40000000UL /**< Strip VLAN tag */
+
/** Split Receive Control Register */
#define INTELX_SRRCTL 0x02100UL
#define INTELX_SRRCTL_BSIZE(kb) ( (kb) << 0 ) /**< Receive buffer size */
#include <ipxe/pci.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
+#include "intelx.h"
#include "intelxvf.h"
/** @file
return 0;
}
+/**
+ * Get queue configuration
+ *
+ * @v intel Intel device
+ * @v vlan_thing VLAN hand-waving thing to fill in
+ * @ret rc Return status code
+ */
+static int intelxvf_mbox_queues ( struct intel_nic *intel, int *vlan_thing ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send queue configuration message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELVF_MSG_TYPE_GET_QUEUES;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p get queue configuration failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) !=INTELVF_MSG_TYPE_GET_QUEUES){
+ DBGC ( intel, "INTEL %p get queue configuration unexpected "
+ "response:\n", intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that we were allowed to get the queue configuration */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p get queue configuration refused\n",
+ intel );
+ return -EPERM;
+ }
+
+ /* Extract VLAN hand-waving thing */
+ *vlan_thing = msg.queues.vlan_thing;
+
+ return 0;
+}
+
/******************************************************************************
*
* Network device interface
*/
static int intelxvf_open ( struct net_device *netdev ) {
struct intel_nic *intel = netdev->priv;
+ uint32_t rxdctl;
uint32_t srrctl;
uint32_t dca_rxctrl;
+ int vlan_thing;
int rc;
/* Reset the function */
goto err_mbox_set_mtu;
}
+ /* Get queue configuration. Ignore failures, since the host
+ * may not support this message.
+ */
+ vlan_thing = 0;
+ intelxvf_mbox_queues ( intel, &vlan_thing );
+ if ( vlan_thing ) {
+ DBGC ( intel, "INTEL %p stripping VLAN tags (thing=%d)\n",
+ intel, vlan_thing );
+ rxdctl = readl ( intel->regs + INTELXVF_RD + INTEL_xDCTL );
+ rxdctl |= INTELX_RXDCTL_VME;
+ writel ( rxdctl, intel->regs + INTELXVF_RD + INTEL_xDCTL );
+ }
+
/* Create transmit descriptor ring */
if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
goto err_create_tx;