diff options
Diffstat (limited to 'src/drivers/net/ena.c')
-rw-r--r-- | src/drivers/net/ena.c | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 9f52a658e..46351dd7d 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -359,6 +359,7 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq, struct ena_cq *cq ) { union ena_aq_req *req; union ena_acq_rsp *rsp; + unsigned int i; int rc; /* Allocate submission queue entries */ @@ -396,6 +397,10 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq, if ( sq->fill > cq->actual ) sq->fill = cq->actual; + /* Initialise buffer ID ring */ + for ( i = 0 ; i < sq->count ; i++ ) + sq->ids[i] = i; + DBGC ( ena, "ENA %p %s SQ%d at [%08lx,%08lx) fill %d db +%04x CQ%d\n", ena, ena_direction ( sq->direction ), sq->id, virt_to_phys ( sq->sqe.raw ), @@ -657,10 +662,11 @@ static void ena_refill_rx ( struct net_device *netdev ) { struct ena_nic *ena = netdev->priv; struct io_buffer *iobuf; struct ena_rx_sqe *sqe; - unsigned int index; physaddr_t address; size_t len = netdev->max_pkt_len; unsigned int refilled = 0; + unsigned int index; + unsigned int id; /* Refill queue */ while ( ( ena->rx.sq.prod - ena->rx.cq.cons ) < ena->rx.sq.fill ) { @@ -672,14 +678,15 @@ static void ena_refill_rx ( struct net_device *netdev ) { break; } - /* Get next submission queue entry */ + /* Get next submission queue entry and buffer ID */ index = ( ena->rx.sq.prod % ENA_RX_COUNT ); sqe = &ena->rx.sq.sqe.rx[index]; + id = ena->rx_ids[index]; /* Construct submission queue entry */ address = virt_to_bus ( iobuf->data ); sqe->len = cpu_to_le16 ( len ); - sqe->id = cpu_to_le16 ( ena->rx.sq.prod ); + sqe->id = cpu_to_le16 ( id ); sqe->address = cpu_to_le64 ( address ); wmb(); sqe->flags = ( ENA_SQE_FIRST | ENA_SQE_LAST | ENA_SQE_CPL | @@ -691,10 +698,10 @@ static void ena_refill_rx ( struct net_device *netdev ) { ena->rx.sq.phase ^= ENA_SQE_PHASE; /* Record I/O buffer */ - assert ( ena->rx_iobuf[index] == NULL ); - ena->rx_iobuf[index] = iobuf; + assert ( ena->rx_iobuf[id] == NULL ); + ena->rx_iobuf[id] = iobuf; - DBGC2 ( ena, "ENA %p RX %d at [%08llx,%08llx)\n", ena, sqe->id, + DBGC2 ( ena, "ENA %p RX %d at [%08llx,%08llx)\n", ena, id, ( ( unsigned long long ) address ), ( ( unsigned long long ) address + len ) ); refilled++; @@ -783,8 +790,9 @@ static void ena_close ( struct net_device *netdev ) { static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct ena_nic *ena = netdev->priv; struct ena_tx_sqe *sqe; - unsigned int index; physaddr_t address; + unsigned int index; + unsigned int id; size_t len; /* Get next submission queue entry */ @@ -794,12 +802,13 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { } index = ( ena->tx.sq.prod % ENA_TX_COUNT ); sqe = &ena->tx.sq.sqe.tx[index]; + id = ena->tx_ids[index]; /* Construct submission queue entry */ address = virt_to_bus ( iobuf->data ); len = iob_len ( iobuf ); sqe->len = cpu_to_le16 ( len ); - sqe->id = ena->tx.sq.prod; + sqe->id = cpu_to_le16 ( id ); sqe->address = cpu_to_le64 ( address ); wmb(); sqe->flags = ( ENA_SQE_FIRST | ENA_SQE_LAST | ENA_SQE_CPL | @@ -811,10 +820,14 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { if ( ( ena->tx.sq.prod % ENA_TX_COUNT ) == 0 ) ena->tx.sq.phase ^= ENA_SQE_PHASE; + /* Record I/O buffer */ + assert ( ena->tx_iobuf[id] == NULL ); + ena->tx_iobuf[id] = iobuf; + /* Ring doorbell */ writel ( ena->tx.sq.prod, ( ena->regs + ena->tx.sq.doorbell ) ); - DBGC2 ( ena, "ENA %p TX %d at [%08llx,%08llx)\n", ena, sqe->id, + DBGC2 ( ena, "ENA %p TX %d at [%08llx,%08llx)\n", ena, id, ( ( unsigned long long ) address ), ( ( unsigned long long ) address + len ) ); return 0; @@ -828,7 +841,9 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { static void ena_poll_tx ( struct net_device *netdev ) { struct ena_nic *ena = netdev->priv; struct ena_tx_cqe *cqe; + struct io_buffer *iobuf; unsigned int index; + unsigned int id; /* Check for completed packets */ while ( ena->tx.cq.cons != ena->tx.sq.prod ) { @@ -840,16 +855,24 @@ static void ena_poll_tx ( struct net_device *netdev ) { /* Stop if completion queue entry is empty */ if ( ( cqe->flags ^ ena->tx.cq.phase ) & ENA_CQE_PHASE ) return; - DBGC2 ( ena, "ENA %p TX %d complete\n", ena, - ( le16_to_cpu ( cqe->id ) >> 2 /* Don't ask */ ) ); /* Increment consumer counter */ ena->tx.cq.cons++; if ( ! ( ena->tx.cq.cons & ena->tx.cq.mask ) ) ena->tx.cq.phase ^= ENA_CQE_PHASE; + /* Identify and free buffer ID */ + id = ENA_TX_CQE_ID ( le16_to_cpu ( cqe->id ) ); + ena->tx_ids[index] = id; + + /* Identify I/O buffer */ + iobuf = ena->tx_iobuf[id]; + assert ( iobuf != NULL ); + ena->tx_iobuf[id] = NULL; + /* Complete transmit */ - netdev_tx_complete_next ( netdev ); + DBGC2 ( ena, "ENA %p TX %d complete\n", ena, id ); + netdev_tx_complete ( netdev, iobuf ); } } @@ -863,13 +886,14 @@ static void ena_poll_rx ( struct net_device *netdev ) { struct ena_rx_cqe *cqe; struct io_buffer *iobuf; unsigned int index; + unsigned int id; size_t len; /* Check for received packets */ while ( ena->rx.cq.cons != ena->rx.sq.prod ) { /* Get next completion queue entry */ - index = ( ena->rx.cq.cons % ENA_RX_COUNT ); + index = ( ena->rx.cq.cons & ena->rx.cq.mask ); cqe = &ena->rx.cq.cqe.rx[index]; /* Stop if completion queue entry is empty */ @@ -881,15 +905,20 @@ static void ena_poll_rx ( struct net_device *netdev ) { if ( ! ( ena->rx.cq.cons & ena->rx.cq.mask ) ) ena->rx.cq.phase ^= ENA_CQE_PHASE; + /* Identify and free buffer ID */ + id = le16_to_cpu ( cqe->id ); + ena->rx_ids[index] = id; + /* Populate I/O buffer */ - iobuf = ena->rx_iobuf[index]; - ena->rx_iobuf[index] = NULL; + iobuf = ena->rx_iobuf[id]; + assert ( iobuf != NULL ); + ena->rx_iobuf[id] = NULL; len = le16_to_cpu ( cqe->len ); iob_put ( iobuf, len ); /* Hand off to network stack */ DBGC2 ( ena, "ENA %p RX %d complete (length %zd)\n", - ena, le16_to_cpu ( cqe->id ), len ); + ena, id, len ); netdev_rx ( netdev, iobuf ); } } @@ -952,11 +981,11 @@ static int ena_probe ( struct pci_device *pci ) { ena_cq_init ( &ena->tx.cq, ENA_TX_COUNT, sizeof ( ena->tx.cq.cqe.tx[0] ) ); ena_sq_init ( &ena->tx.sq, ENA_SQ_TX, ENA_TX_COUNT, - sizeof ( ena->tx.sq.sqe.tx[0] ) ); + sizeof ( ena->tx.sq.sqe.tx[0] ), ena->tx_ids ); ena_cq_init ( &ena->rx.cq, ENA_RX_COUNT, sizeof ( ena->rx.cq.cqe.rx[0] ) ); ena_sq_init ( &ena->rx.sq, ENA_SQ_RX, ENA_RX_COUNT, - sizeof ( ena->rx.sq.sqe.rx[0] ) ); + sizeof ( ena->rx.sq.sqe.rx[0] ), ena->rx_ids ); /* Fix up PCI device */ adjust_pci_device ( pci ); |