Skip to content

Commit

Permalink
[intel] Allow for the use of advanced TX descriptors
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed May 16, 2015
1 parent 28ce9b6 commit 9e2121b
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 42 deletions.
92 changes: 75 additions & 17 deletions src/drivers/net/intel.c
Expand Up @@ -347,6 +347,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
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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 ) {
Expand All @@ -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 */
Expand All @@ -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;
}
Expand All @@ -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 );
Expand Down Expand Up @@ -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 */
Expand All @@ -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",
Expand Down Expand Up @@ -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 );
Expand Down
70 changes: 47 additions & 23 deletions src/drivers/net/intel.h
Expand Up @@ -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
Expand Down Expand Up @@ -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 );
};

/**
Expand All @@ -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 */
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions src/drivers/net/intelx.c
Expand Up @@ -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 );
Expand Down

0 comments on commit 9e2121b

Please sign in to comment.