+int
+atl_stop_queues(struct rte_eth_dev *dev)
+{
+ int i;
+
+ PMD_INIT_FUNC_TRACE();
+
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
+ if (atl_rx_queue_stop(dev, i) != 0) {
+ PMD_DRV_LOG(ERR,
+ "Port %d: Stop Rx queue %d failed",
+ dev->data->port_id, i);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static uint64_t
+atl_desc_to_offload_flags(struct atl_rx_queue *rxq,
+ struct hw_atl_rxd_wb_s *rxd_wb)
+{
+ uint64_t mbuf_flags = 0;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* IPv4 ? */
+ if (rxq->l3_csum_enabled && ((rxd_wb->pkt_type & 0x3) == 0)) {
+ /* IPv4 csum error ? */
+ if (rxd_wb->rx_stat & BIT(1))
+ mbuf_flags |= PKT_RX_IP_CKSUM_BAD;
+ else
+ mbuf_flags |= PKT_RX_IP_CKSUM_GOOD;
+ } else {
+ mbuf_flags |= PKT_RX_IP_CKSUM_UNKNOWN;
+ }
+
+ /* CSUM calculated ? */
+ if (rxq->l4_csum_enabled && (rxd_wb->rx_stat & BIT(3))) {
+ if (rxd_wb->rx_stat & BIT(2))
+ mbuf_flags |= PKT_RX_L4_CKSUM_BAD;
+ else
+ mbuf_flags |= PKT_RX_L4_CKSUM_GOOD;
+ } else {
+ mbuf_flags |= PKT_RX_L4_CKSUM_UNKNOWN;
+ }
+
+ return mbuf_flags;
+}
+
+static uint32_t
+atl_desc_to_pkt_type(struct hw_atl_rxd_wb_s *rxd_wb)
+{
+ uint32_t type = RTE_PTYPE_UNKNOWN;
+ uint16_t l2_l3_type = rxd_wb->pkt_type & 0x3;
+ uint16_t l4_type = (rxd_wb->pkt_type & 0x1C) >> 2;
+
+ switch (l2_l3_type) {
+ case 0:
+ type = RTE_PTYPE_L3_IPV4;
+ break;
+ case 1:
+ type = RTE_PTYPE_L3_IPV6;
+ break;
+ case 2:
+ type = RTE_PTYPE_L2_ETHER;
+ break;
+ case 3:
+ type = RTE_PTYPE_L2_ETHER_ARP;
+ break;
+ }
+
+ switch (l4_type) {
+ case 0:
+ type |= RTE_PTYPE_L4_TCP;
+ break;
+ case 1:
+ type |= RTE_PTYPE_L4_UDP;
+ break;
+ case 2:
+ type |= RTE_PTYPE_L4_SCTP;
+ break;
+ case 3:
+ type |= RTE_PTYPE_L4_ICMP;
+ break;
+ }
+
+ if (rxd_wb->pkt_type & BIT(5))
+ type |= RTE_PTYPE_L2_ETHER_VLAN;
+
+ return type;
+}
+
+uint16_t
+atl_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+ struct atl_rx_queue *rxq = (struct atl_rx_queue *)rx_queue;
+ struct rte_eth_dev *dev = &rte_eth_devices[rxq->port_id];
+ struct atl_adapter *adapter =
+ ATL_DEV_TO_ADAPTER(&rte_eth_devices[rxq->port_id]);
+ struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(adapter);
+ struct atl_rx_entry *sw_ring = rxq->sw_ring;
+
+ struct rte_mbuf *new_mbuf;
+ struct rte_mbuf *rx_mbuf, *rx_mbuf_prev, *rx_mbuf_first;
+ struct atl_rx_entry *rx_entry;
+ uint16_t nb_rx = 0;
+ uint16_t nb_hold = 0;
+ struct hw_atl_rxd_wb_s rxd_wb;
+ struct hw_atl_rxd_s *rxd = NULL;
+ uint16_t tail = rxq->rx_tail;
+ uint64_t dma_addr;
+ uint16_t pkt_len = 0;
+
+ while (nb_rx < nb_pkts) {
+ uint16_t eop_tail = tail;
+
+ rxd = (struct hw_atl_rxd_s *)&rxq->hw_ring[tail];
+ rxd_wb = *(struct hw_atl_rxd_wb_s *)rxd;
+
+ if (!rxd_wb.dd) { /* RxD is not done */
+ break;
+ }
+
+ PMD_RX_LOG(ERR, "port_id=%u queue_id=%u tail=%u "
+ "eop=0x%x pkt_len=%u hash=0x%x hash_type=0x%x",
+ (unsigned int)rxq->port_id,
+ (unsigned int)rxq->queue_id,
+ (unsigned int)tail, (unsigned int)rxd_wb.eop,
+ (unsigned int)rte_le_to_cpu_16(rxd_wb.pkt_len),
+ rxd_wb.rss_hash, rxd_wb.rss_type);
+
+ /* RxD is not done */
+ if (!rxd_wb.eop) {
+ while (true) {
+ struct hw_atl_rxd_wb_s *eop_rxwbd;
+
+ eop_tail = (eop_tail + 1) % rxq->nb_rx_desc;
+ eop_rxwbd = (struct hw_atl_rxd_wb_s *)
+ &rxq->hw_ring[eop_tail];
+ if (!eop_rxwbd->dd) {
+ /* no EOP received yet */
+ eop_tail = tail;
+ break;
+ }
+ if (eop_rxwbd->dd && eop_rxwbd->eop)
+ break;
+ }
+ /* No EOP in ring */
+ if (eop_tail == tail)
+ break;
+ }
+ rx_mbuf_prev = NULL;
+ rx_mbuf_first = NULL;
+
+ /* Run through packet segments */
+ while (true) {
+ new_mbuf = rte_mbuf_raw_alloc(rxq->mb_pool);
+ if (new_mbuf == NULL) {
+ PMD_RX_LOG(ERR,
+ "RX mbuf alloc failed port_id=%u "
+ "queue_id=%u", (unsigned int)rxq->port_id,
+ (unsigned int)rxq->queue_id);
+ dev->data->rx_mbuf_alloc_failed++;
+ goto err_stop;
+ }
+
+ nb_hold++;
+ rx_entry = &sw_ring[tail];
+
+ rx_mbuf = rx_entry->mbuf;
+ rx_entry->mbuf = new_mbuf;
+ dma_addr = rte_cpu_to_le_64(
+ rte_mbuf_data_iova_default(new_mbuf));
+
+ /* setup RX descriptor */
+ rxd->hdr_addr = 0;
+ rxd->buf_addr = dma_addr;
+
+ /*
+ * Initialize the returned mbuf.
+ * 1) setup generic mbuf fields:
+ * - number of segments,
+ * - next segment,
+ * - packet length,
+ * - RX port identifier.
+ * 2) integrate hardware offload data, if any:
+ * < - RSS flag & hash,
+ * - IP checksum flag,
+ * - VLAN TCI, if any,
+ * - error flags.
+ */
+ pkt_len = (uint16_t)rte_le_to_cpu_16(rxd_wb.pkt_len);
+ rx_mbuf->data_off = RTE_PKTMBUF_HEADROOM;
+ rte_prefetch1((char *)rx_mbuf->buf_addr +
+ rx_mbuf->data_off);
+ rx_mbuf->nb_segs = 0;
+ rx_mbuf->next = NULL;
+ rx_mbuf->pkt_len = pkt_len;
+ rx_mbuf->data_len = pkt_len;
+ if (rxd_wb.eop) {
+ u16 remainder_len = pkt_len % rxq->buff_size;
+ if (!remainder_len)
+ remainder_len = rxq->buff_size;
+ rx_mbuf->data_len = remainder_len;
+ } else {
+ rx_mbuf->data_len = pkt_len > rxq->buff_size ?
+ rxq->buff_size : pkt_len;
+ }
+ rx_mbuf->port = rxq->port_id;
+
+ rx_mbuf->hash.rss = rxd_wb.rss_hash;
+
+ rx_mbuf->vlan_tci = rxd_wb.vlan;
+
+ rx_mbuf->ol_flags =
+ atl_desc_to_offload_flags(rxq, &rxd_wb);
+ rx_mbuf->packet_type = atl_desc_to_pkt_type(&rxd_wb);
+
+ if (!rx_mbuf_first)
+ rx_mbuf_first = rx_mbuf;
+ rx_mbuf_first->nb_segs++;
+
+ if (rx_mbuf_prev)
+ rx_mbuf_prev->next = rx_mbuf;
+ rx_mbuf_prev = rx_mbuf;
+
+ tail = (tail + 1) % rxq->nb_rx_desc;
+ /* Prefetch next mbufs */
+ rte_prefetch0(sw_ring[tail].mbuf);
+ if ((tail & 0x3) == 0) {
+ rte_prefetch0(&sw_ring[tail]);
+ rte_prefetch0(&sw_ring[tail]);
+ }
+
+ /* filled mbuf_first */
+ if (rxd_wb.eop)
+ break;
+ rxd = (struct hw_atl_rxd_s *)&rxq->hw_ring[tail];
+ rxd_wb = *(struct hw_atl_rxd_wb_s *)rxd;
+ };
+
+ /*
+ * Store the mbuf address into the next entry of the array
+ * of returned packets.
+ */
+ rx_pkts[nb_rx++] = rx_mbuf_first;
+
+ PMD_RX_LOG(ERR, "add mbuf segs=%d pkt_len=%d",
+ rx_mbuf_first->nb_segs,
+ rx_mbuf_first->pkt_len);
+ }
+
+err_stop:
+
+ rxq->rx_tail = tail;
+
+ /*
+ * If the number of free RX descriptors is greater than the RX free
+ * threshold of the queue, advance the Receive Descriptor Tail (RDT)
+ * register.
+ * Update the RDT with the value of the last processed RX descriptor
+ * minus 1, to guarantee that the RDT register is never equal to the
+ * RDH register, which creates a "full" ring situtation from the
+ * hardware point of view...
+ */
+ nb_hold = (uint16_t)(nb_hold + rxq->nb_rx_hold);
+ if (nb_hold > rxq->rx_free_thresh) {
+ PMD_RX_LOG(ERR, "port_id=%u queue_id=%u rx_tail=%u "
+ "nb_hold=%u nb_rx=%u",
+ (unsigned int)rxq->port_id, (unsigned int)rxq->queue_id,
+ (unsigned int)tail, (unsigned int)nb_hold,
+ (unsigned int)nb_rx);
+ tail = (uint16_t)((tail == 0) ?
+ (rxq->nb_rx_desc - 1) : (tail - 1));
+
+ hw_atl_reg_rx_dma_desc_tail_ptr_set(hw, tail, rxq->queue_id);
+
+ nb_hold = 0;
+ }
+
+ rxq->nb_rx_hold = nb_hold;
+
+ return nb_rx;
+}
+
+