[intelxl] Update driver to use DMA API

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/171/head
Michael Brown 2020-11-17 01:26:21 +00:00
parent 76a7bfe939
commit 03314e8da9
3 changed files with 215 additions and 121 deletions

View File

@ -34,7 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/if_ether.h> #include <ipxe/if_ether.h>
#include <ipxe/vlan.h> #include <ipxe/vlan.h>
#include <ipxe/iobuf.h> #include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/pci.h> #include <ipxe/pci.h>
#include <ipxe/version.h> #include <ipxe/version.h>
#include "intelxl.h" #include "intelxl.h"
@ -136,20 +135,35 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl,
struct pci_device *pci ) { struct pci_device *pci ) {
int rc; int rc;
/* Map dummy target location */
if ( ( rc = dma_map ( intelxl->dma, virt_to_phys ( &intelxl->msix.msg ),
sizeof ( intelxl->msix.msg ), DMA_RX,
&intelxl->msix.map ) ) != 0 ) {
DBGC ( intelxl, "INTELXL %p could not map MSI-X target: %s\n",
intelxl, strerror ( rc ) );
goto err_map;
}
/* Enable MSI-X capability */ /* Enable MSI-X capability */
if ( ( rc = pci_msix_enable ( pci, &intelxl->msix ) ) != 0 ) { if ( ( rc = pci_msix_enable ( pci, &intelxl->msix.cap ) ) != 0 ) {
DBGC ( intelxl, "INTELXL %p could not enable MSI-X: %s\n", DBGC ( intelxl, "INTELXL %p could not enable MSI-X: %s\n",
intelxl, strerror ( rc ) ); intelxl, strerror ( rc ) );
return rc; goto err_enable;
} }
/* Configure interrupt zero to write to dummy location */ /* Configure interrupt zero to write to dummy location */
pci_msix_map ( &intelxl->msix, 0, virt_to_bus ( &intelxl->msg ), 0 ); pci_msix_map ( &intelxl->msix.cap, 0, intelxl->msix.map.addr, 0 );
/* Enable dummy interrupt zero */ /* Enable dummy interrupt zero */
pci_msix_unmask ( &intelxl->msix, 0 ); pci_msix_unmask ( &intelxl->msix.cap, 0 );
return 0; return 0;
pci_msix_disable ( pci, &intelxl->msix.cap );
err_enable:
dma_unmap ( intelxl->dma, &intelxl->msix.map );
err_map:
return rc;
} }
/** /**
@ -162,10 +176,13 @@ void intelxl_msix_disable ( struct intelxl_nic *intelxl,
struct pci_device *pci ) { struct pci_device *pci ) {
/* Disable dummy interrupt zero */ /* Disable dummy interrupt zero */
pci_msix_mask ( &intelxl->msix, 0 ); pci_msix_mask ( &intelxl->msix.cap, 0 );
/* Disable MSI-X capability */ /* Disable MSI-X capability */
pci_msix_disable ( pci, &intelxl->msix ); pci_msix_disable ( pci, &intelxl->msix.cap );
/* Unmap dummy target location */
dma_unmap ( intelxl->dma, &intelxl->msix.map );
} }
/****************************************************************************** /******************************************************************************
@ -197,22 +214,38 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl,
size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
/* Allocate admin queue */ /* Allocate admin queue */
admin->buf = malloc_phys ( ( buf_len + len ), INTELXL_ALIGN ); admin->buf = dma_alloc ( intelxl->dma, ( buf_len + len ),
INTELXL_ALIGN, &admin->map );
if ( ! admin->buf ) if ( ! admin->buf )
return -ENOMEM; return -ENOMEM;
admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); admin->desc = ( ( ( void * ) admin->buf ) + buf_len );
DBGC ( intelxl, "INTELXL %p A%cQ is at [%08llx,%08llx) buf " DBGC ( intelxl, "INTELXL %p A%cQ is at [%08lx,%08lx) buf "
"[%08llx,%08llx)\n", intelxl, "[%08lx,%08lx)\n", intelxl,
( ( admin == &intelxl->command ) ? 'T' : 'R' ), ( ( admin == &intelxl->command ) ? 'T' : 'R' ),
( ( unsigned long long ) virt_to_bus ( admin->desc ) ), virt_to_phys ( admin->desc ),
( ( unsigned long long ) ( virt_to_bus ( admin->desc ) + len ) ), ( virt_to_phys ( admin->desc ) + len ),
( ( unsigned long long ) virt_to_bus ( admin->buf ) ), virt_to_phys ( admin->buf ),
( ( unsigned long long ) ( virt_to_bus ( admin->buf ) + ( virt_to_phys ( admin->buf ) + buf_len ) );
buf_len ) ) );
return 0; return 0;
} }
/**
* Get DMA address for admin descriptor or buffer entry
*
* @v admin Admin queue
* @v addr Virtual address
* @ret addr DMA address
*/
static physaddr_t intelxl_admin_address ( struct intelxl_admin *admin,
void *addr ) {
size_t offset;
/* Calculate offset within mapped area */
offset = ( addr - ( ( void * ) admin->buf ) );
return ( admin->map.addr + offset );
}
/** /**
* Enable admin queue * Enable admin queue
* *
@ -237,7 +270,7 @@ static void intelxl_enable_admin ( struct intelxl_nic *intelxl,
admin->index = 0; admin->index = 0;
/* Program queue address */ /* Program queue address */
address = virt_to_bus ( admin->desc ); address = intelxl_admin_address ( admin, admin->desc );
writel ( ( address & 0xffffffffUL ), admin_regs + regs->bal ); writel ( ( address & 0xffffffffUL ), admin_regs + regs->bal );
if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
writel ( ( ( ( uint64_t ) address ) >> 32 ), writel ( ( ( ( uint64_t ) address ) >> 32 ),
@ -273,13 +306,13 @@ static void intelxl_disable_admin ( struct intelxl_nic *intelxl,
* @v intelxl Intel device * @v intelxl Intel device
* @v admin Admin queue * @v admin Admin queue
*/ */
static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, static void intelxl_free_admin ( struct intelxl_nic *intelxl,
struct intelxl_admin *admin ) { struct intelxl_admin *admin ) {
size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC );
size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
/* Free queue */ /* Free queue */
free_phys ( admin->buf, ( buf_len + len ) ); dma_free ( intelxl->dma, admin->buf, ( buf_len + len ), &admin->map );
} }
/** /**
@ -332,7 +365,7 @@ static void intelxl_admin_event_init ( struct intelxl_nic *intelxl,
/* Initialise descriptor */ /* Initialise descriptor */
evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ]; evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ];
buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ]; buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ];
address = virt_to_bus ( buf ); address = intelxl_admin_address ( admin, buf );
evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
evt->len = cpu_to_le16 ( sizeof ( *buf ) ); evt->len = cpu_to_le16 ( sizeof ( *buf ) );
evt->params.buffer.high = cpu_to_le32 ( address >> 32 ); evt->params.buffer.high = cpu_to_le32 ( address >> 32 );
@ -377,7 +410,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) {
/* Populate data buffer address if applicable */ /* Populate data buffer address if applicable */
if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) { if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
address = virt_to_bus ( buf ); address = intelxl_admin_address ( admin, buf );
cmd->params.buffer.high = cpu_to_le32 ( address >> 32 ); cmd->params.buffer.high = cpu_to_le32 ( address >> 32 );
cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL ); cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL );
} }
@ -924,16 +957,15 @@ void intelxl_close_admin ( struct intelxl_nic *intelxl ) {
*/ */
int intelxl_alloc_ring ( struct intelxl_nic *intelxl, int intelxl_alloc_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring ) { struct intelxl_ring *ring ) {
physaddr_t address;
int rc; int rc;
/* Allocate descriptor ring */ /* Allocate descriptor ring */
ring->desc.raw = malloc_phys ( ring->len, INTELXL_ALIGN ); ring->desc.raw = dma_alloc ( intelxl->dma, ring->len, INTELXL_ALIGN,
&ring->map );
if ( ! ring->desc.raw ) { if ( ! ring->desc.raw ) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_alloc; goto err_alloc;
} }
address = virt_to_bus ( ring->desc.raw );
/* Initialise descriptor ring */ /* Initialise descriptor ring */
memset ( ring->desc.raw, 0, ring->len ); memset ( ring->desc.raw, 0, ring->len );
@ -945,14 +977,14 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl,
ring->prod = 0; ring->prod = 0;
ring->cons = 0; ring->cons = 0;
DBGC ( intelxl, "INTELXL %p ring %06x is at [%08llx,%08llx)\n", DBGC ( intelxl, "INTELXL %p ring %06x is at [%08lx,%08lx)\n",
intelxl, ( ring->reg + ring->tail ), intelxl, ( ring->reg + ring->tail ),
( ( unsigned long long ) address ), virt_to_phys ( ring->desc.raw ),
( ( unsigned long long ) address + ring->len ) ); ( virt_to_phys ( ring->desc.raw ) + ring->len ) );
return 0; return 0;
free_phys ( ring->desc.raw, ring->len ); dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map );
err_alloc: err_alloc:
return rc; return rc;
} }
@ -963,11 +995,11 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl,
* @v intelxl Intel device * @v intelxl Intel device
* @v ring Descriptor ring * @v ring Descriptor ring
*/ */
void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, void intelxl_free_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring ) { struct intelxl_ring *ring ) {
/* Free descriptor ring */ /* Free descriptor ring */
free_phys ( ring->desc.raw, ring->len ); dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map );
ring->desc.raw = NULL; ring->desc.raw = NULL;
} }
@ -1235,7 +1267,6 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl,
*/ */
static int intelxl_create_ring ( struct intelxl_nic *intelxl, static int intelxl_create_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring ) { struct intelxl_ring *ring ) {
physaddr_t address;
int rc; int rc;
/* Allocate descriptor ring */ /* Allocate descriptor ring */
@ -1243,8 +1274,7 @@ static int intelxl_create_ring ( struct intelxl_nic *intelxl,
goto err_alloc; goto err_alloc;
/* Program queue context */ /* Program queue context */
address = virt_to_bus ( ring->desc.raw ); if ( ( rc = ring->context ( intelxl, ring->map.addr ) ) != 0 )
if ( ( rc = ring->context ( intelxl, address ) ) != 0 )
goto err_context; goto err_context;
/* Enable ring */ /* Enable ring */
@ -1289,61 +1319,75 @@ static void intelxl_destroy_ring ( struct intelxl_nic *intelxl,
static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) {
struct intelxl_rx_data_descriptor *rx; struct intelxl_rx_data_descriptor *rx;
struct io_buffer *iobuf; struct io_buffer *iobuf;
struct dma_mapping *map;
unsigned int rx_idx; unsigned int rx_idx;
unsigned int rx_tail; unsigned int rx_tail;
physaddr_t address;
unsigned int refilled = 0; unsigned int refilled = 0;
/* Refill ring */ /* Refill ring */
while ( ( intelxl->rx.prod - intelxl->rx.cons ) < INTELXL_RX_FILL ) { while ( ( intelxl->rx.ring.prod -
intelxl->rx.ring.cons ) < INTELXL_RX_FILL ) {
/* Get next receive descriptor */
rx_idx = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC );
rx = &intelxl->rx.ring.desc.rx[rx_idx].data;
map = &intelxl->rx.map[rx_idx];
assert ( intelxl->rx.iobuf[rx_idx] == NULL );
/* Allocate I/O buffer */ /* Allocate I/O buffer */
iobuf = alloc_iob ( intelxl->mfs ); iobuf = dma_alloc_rx_iob ( intelxl->dma, intelxl->mfs, map );
if ( ! iobuf ) { if ( ! iobuf ) {
/* Wait for next refill */ /* Wait for next refill */
break; break;
} }
intelxl->rx.iobuf[rx_idx] = iobuf;
/* Get next receive descriptor */ /* Update producer index */
rx_idx = ( intelxl->rx.prod++ % INTELXL_RX_NUM_DESC ); intelxl->rx.ring.prod++;
rx = &intelxl->rx.desc.rx[rx_idx].data;
/* Populate receive descriptor */ /* Populate receive descriptor */
address = virt_to_bus ( iobuf->data ); rx->address = cpu_to_le64 ( map->addr );
rx->address = cpu_to_le64 ( address );
rx->flags = 0; rx->flags = 0;
/* Record I/O buffer */ DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n",
assert ( intelxl->rx_iobuf[rx_idx] == NULL ); intelxl, rx_idx, virt_to_phys ( iobuf->data ),
intelxl->rx_iobuf[rx_idx] = iobuf; ( virt_to_phys ( iobuf->data ) + intelxl->mfs ) );
DBGC2 ( intelxl, "INTELXL %p RX %d is [%llx,%llx)\n", intelxl,
rx_idx, ( ( unsigned long long ) address ),
( ( unsigned long long ) address + intelxl->mfs ) );
refilled++; refilled++;
} }
/* Push descriptors to card, if applicable */ /* Push descriptors to card, if applicable */
if ( refilled ) { if ( refilled ) {
wmb(); wmb();
rx_tail = ( intelxl->rx.prod % INTELXL_RX_NUM_DESC ); rx_tail = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC );
writel ( rx_tail, ( intelxl->regs + intelxl->rx.tail ) ); writel ( rx_tail, ( intelxl->regs + intelxl->rx.ring.tail ) );
} }
} }
/** /**
* Discard unused receive I/O buffers * Flush unused I/O buffers
* *
* @v intelxl Intel device * @v intelxl Intel device
*
* Discard any unused receive I/O buffers and unmap any incomplete
* transmit I/O buffers.
*/ */
void intelxl_empty_rx ( struct intelxl_nic *intelxl ) { void intelxl_flush ( struct intelxl_nic *intelxl ) {
unsigned int i; unsigned int i;
unsigned int tx_idx;
/* Discard any unused receive buffers */ /* Discard any unused receive buffers */
for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) {
if ( intelxl->rx_iobuf[i] ) if ( intelxl->rx.iobuf[i] ) {
free_iob ( intelxl->rx_iobuf[i] ); dma_unmap ( intelxl->dma, &intelxl->rx.map[i] );
intelxl->rx_iobuf[i] = NULL; free_iob ( intelxl->rx.iobuf[i] );
}
intelxl->rx.iobuf[i] = NULL;
}
/* Unmap incomplete transmit buffers */
for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) {
tx_idx = ( i % INTELXL_TX_NUM_DESC );
dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] );
} }
} }
@ -1384,7 +1428,7 @@ static int intelxl_open ( struct net_device *netdev ) {
/* Associate transmit queue to PF */ /* Associate transmit queue to PF */
writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF | writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF |
INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ), INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ),
( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_CTL ) ); ( intelxl->regs + intelxl->tx.ring.reg + INTELXL_QXX_CTL ) );
/* Clear transmit pre queue disable */ /* Clear transmit pre queue disable */
queue = ( intelxl->base + intelxl->queue ); queue = ( intelxl->base + intelxl->queue );
@ -1396,11 +1440,11 @@ static int intelxl_open ( struct net_device *netdev ) {
writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) ); writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) );
/* Create receive descriptor ring */ /* Create receive descriptor ring */
if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 ) if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx.ring ) ) != 0 )
goto err_create_rx; goto err_create_rx;
/* Create transmit descriptor ring */ /* Create transmit descriptor ring */
if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx ) ) != 0 ) if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx.ring ) ) != 0 )
goto err_create_tx; goto err_create_tx;
/* Fill receive ring */ /* Fill receive ring */
@ -1418,9 +1462,9 @@ static int intelxl_open ( struct net_device *netdev ) {
INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ), INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ),
( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) ); ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) );
udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US );
intelxl_destroy_ring ( intelxl, &intelxl->tx ); intelxl_destroy_ring ( intelxl, &intelxl->tx.ring );
err_create_tx: err_create_tx:
intelxl_destroy_ring ( intelxl, &intelxl->rx ); intelxl_destroy_ring ( intelxl, &intelxl->rx.ring );
err_create_rx: err_create_rx:
return rc; return rc;
} }
@ -1448,13 +1492,13 @@ static void intelxl_close ( struct net_device *netdev ) {
udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US );
/* Destroy transmit descriptor ring */ /* Destroy transmit descriptor ring */
intelxl_destroy_ring ( intelxl, &intelxl->tx ); intelxl_destroy_ring ( intelxl, &intelxl->tx.ring );
/* Destroy receive descriptor ring */ /* Destroy receive descriptor ring */
intelxl_destroy_ring ( intelxl, &intelxl->rx ); intelxl_destroy_ring ( intelxl, &intelxl->rx.ring );
/* Discard any unused receive buffers */ /* Flush unused buffers */
intelxl_empty_rx ( intelxl ); intelxl_flush ( intelxl );
} }
/** /**
@ -1467,36 +1511,45 @@ static void intelxl_close ( struct net_device *netdev ) {
int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
struct intelxl_nic *intelxl = netdev->priv; struct intelxl_nic *intelxl = netdev->priv;
struct intelxl_tx_data_descriptor *tx; struct intelxl_tx_data_descriptor *tx;
struct dma_mapping *map;
unsigned int tx_idx; unsigned int tx_idx;
unsigned int tx_tail; unsigned int tx_tail;
physaddr_t address;
size_t len; size_t len;
int rc;
/* Get next transmit descriptor */ /* Get next transmit descriptor */
if ( ( intelxl->tx.prod - intelxl->tx.cons ) >= INTELXL_TX_FILL ) { if ( ( intelxl->tx.ring.prod -
intelxl->tx.ring.cons ) >= INTELXL_TX_FILL ) {
DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n", DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n",
intelxl ); intelxl );
return -ENOBUFS; return -ENOBUFS;
} }
tx_idx = ( intelxl->tx.prod++ % INTELXL_TX_NUM_DESC ); tx_idx = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC );
tx_tail = ( intelxl->tx.prod % INTELXL_TX_NUM_DESC ); tx = &intelxl->tx.ring.desc.tx[tx_idx].data;
tx = &intelxl->tx.desc.tx[tx_idx].data; map = &intelxl->tx.map[tx_idx];
/* Map I/O buffer */
if ( ( rc = dma_map_tx_iob ( intelxl->dma, iobuf, map ) ) != 0 )
return rc;
/* Update producer index */
intelxl->tx.ring.prod++;
/* Populate transmit descriptor */ /* Populate transmit descriptor */
address = virt_to_bus ( iobuf->data );
len = iob_len ( iobuf ); len = iob_len ( iobuf );
tx->address = cpu_to_le64 ( address ); tx->address = cpu_to_le64 ( map->addr );
tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) );
tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP |
INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI );
wmb(); wmb();
/* Notify card that there are packets ready to transmit */ /* Notify card that there are packets ready to transmit */
writel ( tx_tail, ( intelxl->regs + intelxl->tx.tail ) ); tx_tail = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC );
writel ( tx_tail, ( intelxl->regs + intelxl->tx.ring.tail ) );
DBGC2 ( intelxl, "INTELXL %p TX %d is [%llx,%llx)\n", intelxl, tx_idx, DBGC2 ( intelxl, "INTELXL %p TX %d is [%08lx,%08lx)\n",
( ( unsigned long long ) address ), intelxl, tx_idx, virt_to_phys ( iobuf->data ),
( ( unsigned long long ) address + len ) ); ( virt_to_phys ( iobuf->data ) + len ) );
return 0; return 0;
} }
@ -1511,11 +1564,11 @@ static void intelxl_poll_tx ( struct net_device *netdev ) {
unsigned int tx_idx; unsigned int tx_idx;
/* Check for completed packets */ /* Check for completed packets */
while ( intelxl->tx.cons != intelxl->tx.prod ) { while ( intelxl->tx.ring.cons != intelxl->tx.ring.prod ) {
/* Get next transmit descriptor */ /* Get next transmit descriptor */
tx_idx = ( intelxl->tx.cons % INTELXL_TX_NUM_DESC ); tx_idx = ( intelxl->tx.ring.cons % INTELXL_TX_NUM_DESC );
tx_wb = &intelxl->tx.desc.tx[tx_idx].wb; tx_wb = &intelxl->tx.ring.desc.tx[tx_idx].wb;
/* Stop if descriptor is still in use */ /* Stop if descriptor is still in use */
if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) ) if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) )
@ -1523,9 +1576,12 @@ static void intelxl_poll_tx ( struct net_device *netdev ) {
DBGC2 ( intelxl, "INTELXL %p TX %d complete\n", DBGC2 ( intelxl, "INTELXL %p TX %d complete\n",
intelxl, tx_idx ); intelxl, tx_idx );
/* Unmap I/O buffer */
dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] );
/* Complete TX descriptor */ /* Complete TX descriptor */
netdev_tx_complete_next ( netdev ); netdev_tx_complete_next ( netdev );
intelxl->tx.cons++; intelxl->tx.ring.cons++;
} }
} }
@ -1543,19 +1599,22 @@ static void intelxl_poll_rx ( struct net_device *netdev ) {
size_t len; size_t len;
/* Check for received packets */ /* Check for received packets */
while ( intelxl->rx.cons != intelxl->rx.prod ) { while ( intelxl->rx.ring.cons != intelxl->rx.ring.prod ) {
/* Get next receive descriptor */ /* Get next receive descriptor */
rx_idx = ( intelxl->rx.cons % INTELXL_RX_NUM_DESC ); rx_idx = ( intelxl->rx.ring.cons % INTELXL_RX_NUM_DESC );
rx_wb = &intelxl->rx.desc.rx[rx_idx].wb; rx_wb = &intelxl->rx.ring.desc.rx[rx_idx].wb;
/* Stop if descriptor is still in use */ /* Stop if descriptor is still in use */
if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) ) if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) )
return; return;
/* Unmap I/O buffer */
dma_unmap ( intelxl->dma, &intelxl->rx.map[rx_idx] );
/* Populate I/O buffer */ /* Populate I/O buffer */
iobuf = intelxl->rx_iobuf[rx_idx]; iobuf = intelxl->rx.iobuf[rx_idx];
intelxl->rx_iobuf[rx_idx] = NULL; intelxl->rx.iobuf[rx_idx] = NULL;
len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) ); len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) );
iob_put ( iobuf, len ); iob_put ( iobuf, len );
@ -1577,7 +1636,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) {
"%zd)\n", intelxl, rx_idx, len ); "%zd)\n", intelxl, rx_idx, len );
vlan_netdev_rx ( netdev, tag, iobuf ); vlan_netdev_rx ( netdev, tag, iobuf );
} }
intelxl->rx.cons++; intelxl->rx.ring.cons++;
} }
} }
@ -1659,16 +1718,17 @@ static int intelxl_probe ( struct pci_device *pci ) {
pci_set_drvdata ( pci, netdev ); pci_set_drvdata ( pci, netdev );
netdev->dev = &pci->dev; netdev->dev = &pci->dev;
memset ( intelxl, 0, sizeof ( *intelxl ) ); memset ( intelxl, 0, sizeof ( *intelxl ) );
intelxl->dma = &pci->dma;
intelxl->intr = INTELXL_PFINT_DYN_CTL0; intelxl->intr = INTELXL_PFINT_DYN_CTL0;
intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD, intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD,
&intelxl_admin_offsets ); &intelxl_admin_offsets );
intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT, intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT,
&intelxl_admin_offsets ); &intelxl_admin_offsets );
intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, intelxl_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC,
sizeof ( intelxl->tx.desc.tx[0] ), sizeof ( intelxl->tx.ring.desc.tx[0] ),
intelxl_context_tx ); intelxl_context_tx );
intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, intelxl_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC,
sizeof ( intelxl->rx.desc.rx[0] ), sizeof ( intelxl->rx.ring.desc.rx[0] ),
intelxl_context_rx ); intelxl_context_rx );
/* Fix up PCI device */ /* Fix up PCI device */
@ -1725,10 +1785,10 @@ static int intelxl_probe ( struct pci_device *pci ) {
goto err_admin_promisc; goto err_admin_promisc;
/* Configure queue register addresses */ /* Configure queue register addresses */
intelxl->tx.reg = INTELXL_QTX ( intelxl->queue ); intelxl->tx.ring.reg = INTELXL_QTX ( intelxl->queue );
intelxl->tx.tail = ( intelxl->tx.reg + INTELXL_QXX_TAIL ); intelxl->tx.ring.tail = ( intelxl->tx.ring.reg + INTELXL_QXX_TAIL );
intelxl->rx.reg = INTELXL_QRX ( intelxl->queue ); intelxl->rx.ring.reg = INTELXL_QRX ( intelxl->queue );
intelxl->rx.tail = ( intelxl->rx.reg + INTELXL_QXX_TAIL ); intelxl->rx.ring.tail = ( intelxl->rx.ring.reg + INTELXL_QXX_TAIL );
/* Configure interrupt causes */ /* Configure interrupt causes */
writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE | writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE |

View File

@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h> #include <stdint.h>
#include <ipxe/if_ether.h> #include <ipxe/if_ether.h>
#include <ipxe/pcimsix.h> #include <ipxe/pcimsix.h>
#include <ipxe/dma.h>
struct intelxl_nic; struct intelxl_nic;
@ -562,6 +563,8 @@ struct intelxl_admin {
struct intelxl_admin_descriptor *desc; struct intelxl_admin_descriptor *desc;
/** Data buffers */ /** Data buffers */
union intelxl_admin_buffer *buf; union intelxl_admin_buffer *buf;
/** DMA mapping */
struct dma_mapping map;
/** Queue index */ /** Queue index */
unsigned int index; unsigned int index;
@ -866,6 +869,8 @@ struct intelxl_ring {
/** Raw data */ /** Raw data */
void *raw; void *raw;
} desc; } desc;
/** Descriptor ring DMA mapping */
struct dma_mapping map;
/** Producer index */ /** Producer index */
unsigned int prod; unsigned int prod;
/** Consumer index */ /** Consumer index */
@ -1025,10 +1030,40 @@ union intelxl_receive_address {
uint8_t raw[ETH_ALEN]; uint8_t raw[ETH_ALEN];
}; };
/** Transmit ring */
struct intelxl_tx_ring {
/** Descriptor ring */
struct intelxl_ring ring;
/** DMA mappings */
struct dma_mapping map[INTELXL_TX_NUM_DESC];
};
/** Receive ring */
struct intelxl_rx_ring {
/** Descriptor ring */
struct intelxl_ring ring;
/** I/O buffers */
struct io_buffer *iobuf[INTELXL_RX_NUM_DESC];
/** DMA mappings */
struct dma_mapping map[INTELXL_RX_NUM_DESC];
};
/** MSI-X interrupt */
struct intelxl_msix {
/** PCI capability */
struct pci_msix cap;
/** MSI-X dummy interrupt target */
uint32_t msg;
/** DMA mapping for dummy interrupt target */
struct dma_mapping map;
};
/** An Intel 40Gigabit network card */ /** An Intel 40Gigabit network card */
struct intelxl_nic { struct intelxl_nic {
/** Registers */ /** Registers */
void *regs; void *regs;
/** DMA device */
struct dma_device *dma;
/** Maximum frame size */ /** Maximum frame size */
size_t mfs; size_t mfs;
@ -1046,12 +1081,10 @@ struct intelxl_nic {
unsigned int qset; unsigned int qset;
/** Interrupt control register */ /** Interrupt control register */
unsigned int intr; unsigned int intr;
/** MSI-X capability */
struct pci_msix msix;
/** MSI-X dummy interrupt target */
uint32_t msg;
/** PCI Express capability offset */ /** PCI Express capability offset */
unsigned int exp; unsigned int exp;
/** MSI-X interrupt */
struct intelxl_msix msix;
/** Admin command queue */ /** Admin command queue */
struct intelxl_admin command; struct intelxl_admin command;
@ -1065,12 +1098,10 @@ struct intelxl_nic {
/** Current VF event data buffer */ /** Current VF event data buffer */
union intelxl_admin_buffer vbuf; union intelxl_admin_buffer vbuf;
/** Transmit descriptor ring */ /** Transmit ring */
struct intelxl_ring tx; struct intelxl_tx_ring tx;
/** Receive descriptor ring */ /** Receive ring */
struct intelxl_ring rx; struct intelxl_rx_ring rx;
/** Receive I/O buffers */
struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC];
}; };
extern int intelxl_msix_enable ( struct intelxl_nic *intelxl, extern int intelxl_msix_enable ( struct intelxl_nic *intelxl,
@ -1090,7 +1121,7 @@ extern int intelxl_alloc_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring ); struct intelxl_ring *ring );
extern void intelxl_free_ring ( struct intelxl_nic *intelxl, extern void intelxl_free_ring ( struct intelxl_nic *intelxl,
struct intelxl_ring *ring ); struct intelxl_ring *ring );
extern void intelxl_empty_rx ( struct intelxl_nic *intelxl ); extern void intelxl_flush ( struct intelxl_nic *intelxl );
extern int intelxl_transmit ( struct net_device *netdev, extern int intelxl_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ); struct io_buffer *iobuf );
extern void intelxl_poll ( struct net_device *netdev ); extern void intelxl_poll ( struct net_device *netdev );

View File

@ -298,9 +298,9 @@ void intelxlvf_admin_event ( struct net_device *netdev,
if ( intelxl->vret != 0 ) { if ( intelxl->vret != 0 ) {
DBGC ( intelxl, "INTELXL %p admin VF command %#x " DBGC ( intelxl, "INTELXL %p admin VF command %#x "
"error %d\n", intelxl, vopcode, intelxl->vret ); "error %d\n", intelxl, vopcode, intelxl->vret );
DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt, DBGC_HDA ( intelxl, virt_to_phys ( evt ), evt,
sizeof ( *evt ) ); sizeof ( *evt ) );
DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf, DBGC_HDA ( intelxl, virt_to_phys ( buf ), buf,
le16_to_cpu ( evt->len ) ); le16_to_cpu ( evt->len ) );
} }
return; return;
@ -314,8 +314,10 @@ void intelxlvf_admin_event ( struct net_device *netdev,
default: default:
DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n", DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n",
intelxl, vopcode ); intelxl, vopcode );
DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) ); DBGC_HDA ( intelxl, virt_to_phys ( evt ), evt,
DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) ); sizeof ( *evt ) );
DBGC_HDA ( intelxl, virt_to_phys ( buf ), buf,
le16_to_cpu ( evt->len ) );
break; break;
} }
} }
@ -378,12 +380,12 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) {
buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.count = cpu_to_le16 ( 1 );
buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi );
buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC );
buf->cfg.tx.base = cpu_to_le64 ( virt_to_bus ( intelxl->tx.desc.raw ) ); buf->cfg.tx.base = cpu_to_le64 ( intelxl->tx.ring.map.addr );
buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi );
buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC );
buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs );
buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs );
buf->cfg.rx.base = cpu_to_le64 ( virt_to_bus ( intelxl->rx.desc.raw ) ); buf->cfg.rx.base = cpu_to_le64 ( intelxl->rx.ring.map.addr );
/* Issue command */ /* Issue command */
if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
@ -497,11 +499,11 @@ static int intelxlvf_open ( struct net_device *netdev ) {
INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) ); INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
/* Allocate transmit descriptor ring */ /* Allocate transmit descriptor ring */
if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 ) if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx.ring ) ) != 0 )
goto err_alloc_tx; goto err_alloc_tx;
/* Allocate receive descriptor ring */ /* Allocate receive descriptor ring */
if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 ) if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx.ring ) ) != 0 )
goto err_alloc_rx; goto err_alloc_rx;
/* Configure queues */ /* Configure queues */
@ -527,9 +529,9 @@ static int intelxlvf_open ( struct net_device *netdev ) {
err_enable: err_enable:
err_irq_map: err_irq_map:
err_configure: err_configure:
intelxl_free_ring ( intelxl, &intelxl->rx ); intelxl_free_ring ( intelxl, &intelxl->rx.ring );
err_alloc_rx: err_alloc_rx:
intelxl_free_ring ( intelxl, &intelxl->tx ); intelxl_free_ring ( intelxl, &intelxl->tx.ring );
err_alloc_tx: err_alloc_tx:
return rc; return rc;
} }
@ -550,13 +552,13 @@ static void intelxlvf_close ( struct net_device *netdev ) {
} }
/* Free receive descriptor ring */ /* Free receive descriptor ring */
intelxl_free_ring ( intelxl, &intelxl->rx ); intelxl_free_ring ( intelxl, &intelxl->rx.ring );
/* Free transmit descriptor ring */ /* Free transmit descriptor ring */
intelxl_free_ring ( intelxl, &intelxl->tx ); intelxl_free_ring ( intelxl, &intelxl->tx.ring );
/* Discard any unused receive buffers */ /* Flush unused buffers */
intelxl_empty_rx ( intelxl ); intelxl_flush ( intelxl );
} }
/** Network device operations */ /** Network device operations */
@ -596,16 +598,17 @@ static int intelxlvf_probe ( struct pci_device *pci ) {
pci_set_drvdata ( pci, netdev ); pci_set_drvdata ( pci, netdev );
netdev->dev = &pci->dev; netdev->dev = &pci->dev;
memset ( intelxl, 0, sizeof ( *intelxl ) ); memset ( intelxl, 0, sizeof ( *intelxl ) );
intelxl->dma = &pci->dma;
intelxl->intr = INTELXLVF_VFINT_DYN_CTL0; intelxl->intr = INTELXLVF_VFINT_DYN_CTL0;
intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN, intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN,
&intelxlvf_admin_command_offsets ); &intelxlvf_admin_command_offsets );
intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN, intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN,
&intelxlvf_admin_event_offsets ); &intelxlvf_admin_event_offsets );
intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, intelxlvf_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC,
sizeof ( intelxl->tx.desc.tx[0] ), sizeof ( intelxl->tx.ring.desc.tx[0] ),
INTELXLVF_QTX_TAIL ); INTELXLVF_QTX_TAIL );
intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, intelxlvf_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC,
sizeof ( intelxl->rx.desc.rx[0] ), sizeof ( intelxl->rx.ring.desc.rx[0] ),
INTELXLVF_QRX_TAIL ); INTELXLVF_QRX_TAIL );
/* Fix up PCI device */ /* Fix up PCI device */