summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2015-05-16 15:26:00 +0200
committerMichael Brown2015-05-16 15:54:31 +0200
commit9e2121be0d5d2b25173503c4f577471bec618928 (patch)
tree3361e62b094fbde0bc5b994a054171ca2a06197a
parent[intel] Expose intel_diag() for use by other Intel NIC drivers (diff)
downloadipxe-9e2121be0d5d2b25173503c4f577471bec618928.tar.gz
ipxe-9e2121be0d5d2b25173503c4f577471bec618928.tar.xz
ipxe-9e2121be0d5d2b25173503c4f577471bec618928.zip
[intel] Allow for the use of advanced TX descriptors
Intel virtual function NICs almost work with the use of "legacy" transmit and receive descriptors (which are backwards compatible right back to the original Intel Gigabit NICs). Unfortunately the "TX switching" feature (which allows for VM<->VM traffic to be looped back within the NIC itself) does not work when a legacy TX descriptor is used: the packet is instead sent onto the wire. Fix by allowing for the use of an "advanced" TX descriptor (containing exactly the same information as is found in the "legacy" descriptor). Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/drivers/net/intel.c92
-rw-r--r--src/drivers/net/intel.h70
-rw-r--r--src/drivers/net/intelx.c6
3 files changed, 126 insertions, 42 deletions
diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c
index 4b0e4c0e..6309e9aa 100644
--- a/src/drivers/net/intel.c
+++ b/src/drivers/net/intel.c
@@ -349,6 +349,67 @@ static void intel_check_link ( struct net_device *netdev ) {
/******************************************************************************
*
+ * Descriptors
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Populate transmit descriptor
+ *
+ * @v tx Transmit descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+void intel_describe_tx ( struct intel_descriptor *tx, physaddr_t addr,
+ size_t len ) {
+
+ /* Populate transmit descriptor */
+ tx->address = cpu_to_le64 ( addr );
+ tx->length = cpu_to_le16 ( len );
+ tx->flags = 0;
+ tx->command = ( INTEL_DESC_CMD_RS | INTEL_DESC_CMD_IFCS |
+ INTEL_DESC_CMD_EOP );
+ tx->status = 0;
+}
+
+/**
+ * Populate advanced transmit descriptor
+ *
+ * @v tx Transmit descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+void intel_describe_tx_adv ( struct intel_descriptor *tx, physaddr_t addr,
+ size_t len ) {
+
+ /* Populate advanced transmit descriptor */
+ tx->address = cpu_to_le64 ( addr );
+ tx->length = cpu_to_le16 ( len );
+ tx->flags = INTEL_DESC_FL_DTYP_DATA;
+ tx->command = ( INTEL_DESC_CMD_DEXT | INTEL_DESC_CMD_RS |
+ INTEL_DESC_CMD_IFCS | INTEL_DESC_CMD_EOP );
+ tx->status = cpu_to_le32 ( INTEL_DESC_STATUS_PAYLEN ( len ) );
+}
+
+/**
+ * Populate receive descriptor
+ *
+ * @v rx Receive descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+void intel_describe_rx ( struct intel_descriptor *rx, physaddr_t addr,
+ size_t len __unused ) {
+
+ /* Populate transmit descriptor */
+ rx->address = cpu_to_le64 ( addr );
+ rx->length = 0;
+ rx->status = 0;
+}
+
+/******************************************************************************
+ *
* Network device interface
*
******************************************************************************
@@ -457,10 +518,7 @@ void intel_refill_rx ( struct intel_nic *intel ) {
/* Populate receive descriptor */
address = virt_to_bus ( iobuf->data );
- rx->address = cpu_to_le64 ( address );
- rx->length = 0;
- rx->status = 0;
- rx->errors = 0;
+ intel->rx.describe ( rx, address, 0 );
/* Record I/O buffer */
assert ( intel->rx_iobuf[rx_idx] == NULL );
@@ -602,6 +660,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
unsigned int tx_idx;
unsigned int tx_tail;
physaddr_t address;
+ size_t len;
/* Get next transmit descriptor */
if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) {
@@ -614,11 +673,8 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
/* Populate transmit descriptor */
address = virt_to_bus ( iobuf->data );
- tx->address = cpu_to_le64 ( address );
- tx->length = cpu_to_le16 ( iob_len ( iobuf ) );
- tx->command = ( INTEL_DESC_CMD_RS | INTEL_DESC_CMD_IFCS |
- INTEL_DESC_CMD_EOP );
- tx->status = 0;
+ len = iob_len ( iobuf );
+ intel->tx.describe ( tx, address, len );
wmb();
/* Notify card that there are packets ready to transmit */
@@ -629,7 +685,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx,
( ( unsigned long long ) address ),
- ( ( unsigned long long ) address + iob_len ( iobuf ) ) );
+ ( ( unsigned long long ) address + len ) );
return 0;
}
@@ -652,7 +708,7 @@ void intel_poll_tx ( struct net_device *netdev ) {
tx = &intel->tx.desc[tx_idx];
/* Stop if descriptor is still in use */
- if ( ! ( tx->status & INTEL_DESC_STATUS_DD ) )
+ if ( ! ( tx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) )
return;
DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx );
@@ -683,7 +739,7 @@ void intel_poll_rx ( struct net_device *netdev ) {
rx = &intel->rx.desc[rx_idx];
/* Stop if descriptor is still in use */
- if ( ! ( rx->status & INTEL_DESC_STATUS_DD ) )
+ if ( ! ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) )
return;
/* Populate I/O buffer */
@@ -693,10 +749,10 @@ void intel_poll_rx ( struct net_device *netdev ) {
iob_put ( iobuf, len );
/* Hand off to network stack */
- if ( rx->errors ) {
+ if ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_RXE ) ) {
DBGC ( intel, "INTEL %p RX %d error (length %zd, "
- "errors %02x)\n",
- intel, rx_idx, len, rx->errors );
+ "status %08x)\n", intel, rx_idx, len,
+ le32_to_cpu ( rx->status ) );
netdev_rx_err ( netdev, iobuf, -EIO );
} else {
DBGC2 ( intel, "INTEL %p RX %d complete (length %zd)\n",
@@ -811,8 +867,10 @@ static int intel_probe ( struct pci_device *pci ) {
memset ( intel, 0, sizeof ( *intel ) );
intel->port = PCI_FUNC ( pci->busdevfn );
intel->flags = pci->id->driver_data;
- intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD );
- intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD );
+ intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD,
+ intel_describe_tx );
+ intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD,
+ intel_describe_rx );
/* Fix up PCI device */
adjust_pci_device ( pci );
diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h
index 621ee2e7..2656cda5 100644
--- a/src/drivers/net/intel.h
+++ b/src/drivers/net/intel.h
@@ -22,33 +22,38 @@ struct intel_descriptor {
uint64_t address;
/** Length */
uint16_t length;
- /** Reserved */
- uint8_t reserved_a;
+ /** Flags */
+ uint8_t flags;
/** Command */
uint8_t command;
/** Status */
- uint8_t status;
- /** Errors */
- uint8_t errors;
- /** Reserved */
- uint16_t reserved_b;
+ uint32_t status;
} __attribute__ (( packed ));
-/** Packet descriptor command bits */
-enum intel_descriptor_command {
- /** Report status */
- INTEL_DESC_CMD_RS = 0x08,
- /** Insert frame checksum (CRC) */
- INTEL_DESC_CMD_IFCS = 0x02,
- /** End of packet */
- INTEL_DESC_CMD_EOP = 0x01,
-};
+/** Descriptor type */
+#define INTEL_DESC_FL_DTYP( dtyp ) ( (dtyp) << 4 )
+#define INTEL_DESC_FL_DTYP_DATA INTEL_DESC_FL_DTYP ( 0x03 )
-/** Packet descriptor status bits */
-enum intel_descriptor_status {
- /** Descriptor done */
- INTEL_DESC_STATUS_DD = 0x01,
-};
+/** Descriptor extension */
+#define INTEL_DESC_CMD_DEXT 0x20
+
+/** Report status */
+#define INTEL_DESC_CMD_RS 0x08
+
+/** Insert frame checksum (CRC) */
+#define INTEL_DESC_CMD_IFCS 0x02
+
+/** End of packet */
+#define INTEL_DESC_CMD_EOP 0x01
+
+/** Descriptor done */
+#define INTEL_DESC_STATUS_DD 0x00000001UL
+
+/** Receive error */
+#define INTEL_DESC_STATUS_RXE 0x00000100UL
+
+/** Payload length */
+#define INTEL_DESC_STATUS_PAYLEN( len ) ( (len) << 14 )
/** Device Control Register */
#define INTEL_CTRL 0x00000UL
@@ -209,6 +214,15 @@ struct intel_ring {
unsigned int reg;
/** Length (in bytes) */
size_t len;
+
+ /** Populate descriptor
+ *
+ * @v desc Descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+ void ( * describe ) ( struct intel_descriptor *desc, physaddr_t addr,
+ size_t len );
};
/**
@@ -217,12 +231,16 @@ struct intel_ring {
* @v ring Descriptor ring
* @v count Number of descriptors
* @v reg Descriptor register block
+ * @v describe Method to populate descriptor
*/
static inline __attribute__ (( always_inline)) void
-intel_init_ring ( struct intel_ring *ring, unsigned int count,
- unsigned int reg ) {
+intel_init_ring ( struct intel_ring *ring, unsigned int count, unsigned int reg,
+ void ( * describe ) ( struct intel_descriptor *desc,
+ physaddr_t addr, size_t len ) ) {
+
ring->len = ( count * sizeof ( ring->desc[0] ) );
ring->reg = reg;
+ ring->describe = describe;
}
/** An Intel network card */
@@ -278,6 +296,12 @@ static inline void intel_diag ( struct intel_nic *intel ) {
readl ( intel->regs + intel->rx.reg + INTEL_xDT ) );
}
+extern void intel_describe_tx ( struct intel_descriptor *tx,
+ physaddr_t addr, size_t len );
+extern void intel_describe_tx_adv ( struct intel_descriptor *tx,
+ physaddr_t addr, size_t len );
+extern void intel_describe_rx ( struct intel_descriptor *rx,
+ physaddr_t addr, size_t len );
extern int intel_create_ring ( struct intel_nic *intel,
struct intel_ring *ring );
extern void intel_destroy_ring ( struct intel_nic *intel,
diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c
index d2bb19b0..982b74f1 100644
--- a/src/drivers/net/intelx.c
+++ b/src/drivers/net/intelx.c
@@ -396,8 +396,10 @@ static int intelx_probe ( struct pci_device *pci ) {
netdev->dev = &pci->dev;
memset ( intel, 0, sizeof ( *intel ) );
intel->port = PCI_FUNC ( pci->busdevfn );
- intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD );
- intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD );
+ intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD,
+ intel_describe_tx );
+ intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD,
+ intel_describe_rx );
/* Fix up PCI device */
adjust_pci_device ( pci );