Use a binary search algorithm to find the first empty DD bit. The ring-empty and ring-full cases are managed separately as they are more likely to happen.
PR=52423 Signed-off-by: Olivier Matz <olivier.matz at 6wind.com> Acked-by: Ivan Boule <ivan.boule at 6wind.com> --- drivers/net/e1000/igb_rxtx.c | 55 +++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/drivers/net/e1000/igb_rxtx.c b/drivers/net/e1000/igb_rxtx.c index e9aa356..6b0111f 100644 --- a/drivers/net/e1000/igb_rxtx.c +++ b/drivers/net/e1000/igb_rxtx.c @@ -1507,24 +1507,51 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev, uint32_t eth_igb_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id) { -#define IGB_RXQ_SCAN_INTERVAL 4 - volatile union e1000_adv_rx_desc *rxdp; + volatile uint32_t *status; struct igb_rx_queue *rxq; - uint32_t desc = 0; + uint32_t offset, interval, resolution; + int32_t idx; rxq = dev->data->rx_queues[rx_queue_id]; - rxdp = &(rxq->rx_ring[rxq->rx_tail]); - - while ((desc < rxq->nb_rx_desc) && - (rxdp->wb.upper.status_error & E1000_RXD_STAT_DD)) { - desc += IGB_RXQ_SCAN_INTERVAL; - rxdp += IGB_RXQ_SCAN_INTERVAL; - if (rxq->rx_tail + desc >= rxq->nb_rx_desc) - rxdp = &(rxq->rx_ring[rxq->rx_tail + - desc - rxq->nb_rx_desc]); - } - return desc; + /* check if ring empty */ + idx = rxq->rx_tail; + status = &rxq->rx_ring[idx].wb.upper.status_error; + if (!(*status & rte_cpu_to_le_32(E1000_RXD_STAT_DD))) + return 0; + + /* decrease the precision if ring is large */ + if (rxq->nb_rx_desc <= 256) + resolution = 4; + else + resolution = 16; + + /* check if ring full */ + idx = rxq->rx_tail - rxq->nb_rx_hold - resolution; + if (idx < 0) + idx += rxq->nb_rx_desc; + status = &rxq->rx_ring[idx].wb.upper.status_error; + if (*status & rte_cpu_to_le_32(E1000_RXD_STAT_DD)) + return rxq->nb_rx_desc; + + /* use a binary search */ + interval = (rxq->nb_rx_desc - rxq->nb_rx_hold) >> 1; + offset = interval; + + do { + idx = rxq->rx_tail + offset; + if (idx >= rxq->nb_rx_desc) + idx -= rxq->nb_rx_desc; + + interval >>= 1; + status = &rxq->rx_ring[idx].wb.upper.status_error; + if (*status & rte_cpu_to_le_32(E1000_RXD_STAT_DD)) + offset += interval; + else + offset -= interval; + } while (interval >= resolution); + + return offset; } int -- 2.8.1