1*039ce329SXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later 2*039ce329SXuan Zhuo /* 3*039ce329SXuan Zhuo * Driver for Alibaba Elastic Ethernet Adapter. 4*039ce329SXuan Zhuo * 5*039ce329SXuan Zhuo * Copyright (C) 2025 Alibaba Inc. 6*039ce329SXuan Zhuo */ 7*039ce329SXuan Zhuo 8*039ce329SXuan Zhuo #include "eea_pci.h" 9*039ce329SXuan Zhuo #include "eea_ring.h" 10*039ce329SXuan Zhuo 11*039ce329SXuan Zhuo void eea_ering_irq_active(struct eea_ring *ering, struct eea_ring *tx_ering) 12*039ce329SXuan Zhuo { 13*039ce329SXuan Zhuo u64 value = 0, rx_idx, tx_idx; 14*039ce329SXuan Zhuo 15*039ce329SXuan Zhuo tx_idx = (u64)tx_ering->cq.hw_idx; 16*039ce329SXuan Zhuo rx_idx = (u64)ering->cq.hw_idx; 17*039ce329SXuan Zhuo 18*039ce329SXuan Zhuo value |= EEA_IRQ_UNMASK << EEA_DB_FLAGS_OFF; 19*039ce329SXuan Zhuo value |= tx_idx << EEA_DB_TX_CQ_HEAD_OFF; 20*039ce329SXuan Zhuo value |= rx_idx << EEA_DB_RX_CQ_HEAD_OFF; 21*039ce329SXuan Zhuo 22*039ce329SXuan Zhuo writeq(value, ering->db); 23*039ce329SXuan Zhuo } 24*039ce329SXuan Zhuo 25*039ce329SXuan Zhuo void *eea_ering_cq_get_desc(const struct eea_ring *ering) 26*039ce329SXuan Zhuo { 27*039ce329SXuan Zhuo u8 phase; 28*039ce329SXuan Zhuo u8 *desc; 29*039ce329SXuan Zhuo 30*039ce329SXuan Zhuo desc = ering->cq.desc + (ering->cq.head << ering->cq.desc_size_shift); 31*039ce329SXuan Zhuo 32*039ce329SXuan Zhuo phase = READ_ONCE(*(u8 *)(desc + ering->cq.desc_size - 1)); 33*039ce329SXuan Zhuo 34*039ce329SXuan Zhuo if ((phase & EEA_RING_DESC_F_CQ_PHASE) == ering->cq.phase) { 35*039ce329SXuan Zhuo dma_rmb(); 36*039ce329SXuan Zhuo return desc; 37*039ce329SXuan Zhuo } 38*039ce329SXuan Zhuo 39*039ce329SXuan Zhuo return NULL; 40*039ce329SXuan Zhuo } 41*039ce329SXuan Zhuo 42*039ce329SXuan Zhuo /* sq api */ 43*039ce329SXuan Zhuo void *eea_ering_sq_alloc_desc(struct eea_ring *ering, u16 id, bool is_last, 44*039ce329SXuan Zhuo u16 flags) 45*039ce329SXuan Zhuo { 46*039ce329SXuan Zhuo struct eea_ring_sq *sq = &ering->sq; 47*039ce329SXuan Zhuo struct eea_common_desc *desc; 48*039ce329SXuan Zhuo 49*039ce329SXuan Zhuo if (!sq->shadow_num) { 50*039ce329SXuan Zhuo sq->shadow_idx = sq->head; 51*039ce329SXuan Zhuo sq->shadow_id = cpu_to_le16(id); 52*039ce329SXuan Zhuo } 53*039ce329SXuan Zhuo 54*039ce329SXuan Zhuo if (!is_last) 55*039ce329SXuan Zhuo flags |= EEA_RING_DESC_F_MORE; 56*039ce329SXuan Zhuo 57*039ce329SXuan Zhuo desc = sq->desc + (sq->shadow_idx << sq->desc_size_shift); 58*039ce329SXuan Zhuo 59*039ce329SXuan Zhuo desc->flags = cpu_to_le16(flags); 60*039ce329SXuan Zhuo desc->id = sq->shadow_id; 61*039ce329SXuan Zhuo 62*039ce329SXuan Zhuo if (unlikely(++sq->shadow_idx >= ering->num)) 63*039ce329SXuan Zhuo sq->shadow_idx = 0; 64*039ce329SXuan Zhuo 65*039ce329SXuan Zhuo ++sq->shadow_num; 66*039ce329SXuan Zhuo 67*039ce329SXuan Zhuo return desc; 68*039ce329SXuan Zhuo } 69*039ce329SXuan Zhuo 70*039ce329SXuan Zhuo /* This is an allocation API for admin Q. For each call to admin Q, only one 71*039ce329SXuan Zhuo * desc will be allocated. 72*039ce329SXuan Zhuo */ 73*039ce329SXuan Zhuo void *eea_ering_aq_alloc_desc(struct eea_ring *ering) 74*039ce329SXuan Zhuo { 75*039ce329SXuan Zhuo struct eea_ring_sq *sq = &ering->sq; 76*039ce329SXuan Zhuo struct eea_common_desc *desc; 77*039ce329SXuan Zhuo 78*039ce329SXuan Zhuo if (!sq->shadow_num) 79*039ce329SXuan Zhuo sq->shadow_idx = sq->head; 80*039ce329SXuan Zhuo 81*039ce329SXuan Zhuo desc = sq->desc + (sq->shadow_idx << sq->desc_size_shift); 82*039ce329SXuan Zhuo 83*039ce329SXuan Zhuo if (unlikely(++sq->shadow_idx >= ering->num)) 84*039ce329SXuan Zhuo sq->shadow_idx = 0; 85*039ce329SXuan Zhuo 86*039ce329SXuan Zhuo ++sq->shadow_num; 87*039ce329SXuan Zhuo 88*039ce329SXuan Zhuo return desc; 89*039ce329SXuan Zhuo } 90*039ce329SXuan Zhuo 91*039ce329SXuan Zhuo void eea_ering_sq_commit_desc(struct eea_ring *ering) 92*039ce329SXuan Zhuo { 93*039ce329SXuan Zhuo struct eea_ring_sq *sq = &ering->sq; 94*039ce329SXuan Zhuo int num; 95*039ce329SXuan Zhuo 96*039ce329SXuan Zhuo num = sq->shadow_num; 97*039ce329SXuan Zhuo 98*039ce329SXuan Zhuo ering->num_free -= num; 99*039ce329SXuan Zhuo 100*039ce329SXuan Zhuo sq->head = sq->shadow_idx; 101*039ce329SXuan Zhuo sq->hw_idx += num; 102*039ce329SXuan Zhuo sq->shadow_num = 0; 103*039ce329SXuan Zhuo } 104*039ce329SXuan Zhuo 105*039ce329SXuan Zhuo void eea_ering_sq_cancel(struct eea_ring *ering) 106*039ce329SXuan Zhuo { 107*039ce329SXuan Zhuo ering->sq.shadow_num = 0; 108*039ce329SXuan Zhuo } 109*039ce329SXuan Zhuo 110*039ce329SXuan Zhuo /* cq api */ 111*039ce329SXuan Zhuo void eea_ering_cq_ack_desc(struct eea_ring *ering, u32 num) 112*039ce329SXuan Zhuo { 113*039ce329SXuan Zhuo struct eea_ring_cq *cq = &ering->cq; 114*039ce329SXuan Zhuo 115*039ce329SXuan Zhuo cq->head += num; 116*039ce329SXuan Zhuo cq->hw_idx += num; 117*039ce329SXuan Zhuo 118*039ce329SXuan Zhuo if (unlikely(cq->head >= ering->num)) { 119*039ce329SXuan Zhuo cq->head -= ering->num; 120*039ce329SXuan Zhuo cq->phase ^= EEA_RING_DESC_F_CQ_PHASE; 121*039ce329SXuan Zhuo } 122*039ce329SXuan Zhuo 123*039ce329SXuan Zhuo ering->num_free += num; 124*039ce329SXuan Zhuo } 125*039ce329SXuan Zhuo 126*039ce329SXuan Zhuo /* notify */ 127*039ce329SXuan Zhuo void eea_ering_kick(struct eea_ring *ering) 128*039ce329SXuan Zhuo { 129*039ce329SXuan Zhuo u64 value = 0, idx; 130*039ce329SXuan Zhuo 131*039ce329SXuan Zhuo idx = (u64)ering->sq.hw_idx; 132*039ce329SXuan Zhuo 133*039ce329SXuan Zhuo value |= EEA_IDX_PRESENT << EEA_DB_FLAGS_OFF; 134*039ce329SXuan Zhuo value |= idx << EEA_DB_IDX_OFF; 135*039ce329SXuan Zhuo 136*039ce329SXuan Zhuo writeq(value, ering->db); 137*039ce329SXuan Zhuo } 138*039ce329SXuan Zhuo 139*039ce329SXuan Zhuo /* ering alloc/free */ 140*039ce329SXuan Zhuo static void ering_free_queue(struct eea_device *edev, size_t size, 141*039ce329SXuan Zhuo void *queue, dma_addr_t dma_handle) 142*039ce329SXuan Zhuo { 143*039ce329SXuan Zhuo dma_free_coherent(edev->dma_dev, size, queue, dma_handle); 144*039ce329SXuan Zhuo } 145*039ce329SXuan Zhuo 146*039ce329SXuan Zhuo static void *ering_alloc_queue(struct eea_device *edev, size_t size, 147*039ce329SXuan Zhuo dma_addr_t *dma_handle) 148*039ce329SXuan Zhuo { 149*039ce329SXuan Zhuo gfp_t flags = GFP_KERNEL | __GFP_NOWARN; 150*039ce329SXuan Zhuo 151*039ce329SXuan Zhuo return dma_alloc_coherent(edev->dma_dev, size, dma_handle, flags); 152*039ce329SXuan Zhuo } 153*039ce329SXuan Zhuo 154*039ce329SXuan Zhuo static int ering_alloc_queues(struct eea_ring *ering, struct eea_device *edev, 155*039ce329SXuan Zhuo size_t num, u8 sq_desc_size, u8 cq_desc_size) 156*039ce329SXuan Zhuo { 157*039ce329SXuan Zhuo dma_addr_t addr; 158*039ce329SXuan Zhuo size_t size; 159*039ce329SXuan Zhuo void *ring; 160*039ce329SXuan Zhuo 161*039ce329SXuan Zhuo size = num * sq_desc_size; 162*039ce329SXuan Zhuo 163*039ce329SXuan Zhuo ring = ering_alloc_queue(edev, size, &addr); 164*039ce329SXuan Zhuo if (!ring) 165*039ce329SXuan Zhuo return -ENOMEM; 166*039ce329SXuan Zhuo 167*039ce329SXuan Zhuo ering->sq.desc = ring; 168*039ce329SXuan Zhuo ering->sq.dma_addr = addr; 169*039ce329SXuan Zhuo ering->sq.dma_size = size; 170*039ce329SXuan Zhuo ering->sq.desc_size = sq_desc_size; 171*039ce329SXuan Zhuo ering->sq.desc_size_shift = fls(sq_desc_size) - 1; 172*039ce329SXuan Zhuo 173*039ce329SXuan Zhuo size = num * cq_desc_size; 174*039ce329SXuan Zhuo 175*039ce329SXuan Zhuo ring = ering_alloc_queue(edev, size, &addr); 176*039ce329SXuan Zhuo if (!ring) 177*039ce329SXuan Zhuo goto err_free_sq; 178*039ce329SXuan Zhuo 179*039ce329SXuan Zhuo ering->cq.desc = ring; 180*039ce329SXuan Zhuo ering->cq.dma_addr = addr; 181*039ce329SXuan Zhuo ering->cq.dma_size = size; 182*039ce329SXuan Zhuo ering->cq.desc_size = cq_desc_size; 183*039ce329SXuan Zhuo ering->cq.desc_size_shift = fls(cq_desc_size) - 1; 184*039ce329SXuan Zhuo 185*039ce329SXuan Zhuo ering->num = num; 186*039ce329SXuan Zhuo 187*039ce329SXuan Zhuo return 0; 188*039ce329SXuan Zhuo 189*039ce329SXuan Zhuo err_free_sq: 190*039ce329SXuan Zhuo ering_free_queue(ering->edev, ering->sq.dma_size, 191*039ce329SXuan Zhuo ering->sq.desc, ering->sq.dma_addr); 192*039ce329SXuan Zhuo return -ENOMEM; 193*039ce329SXuan Zhuo } 194*039ce329SXuan Zhuo 195*039ce329SXuan Zhuo static void ering_init(struct eea_ring *ering) 196*039ce329SXuan Zhuo { 197*039ce329SXuan Zhuo ering->cq.phase = EEA_RING_DESC_F_CQ_PHASE; 198*039ce329SXuan Zhuo ering->num_free = ering->num; 199*039ce329SXuan Zhuo } 200*039ce329SXuan Zhuo 201*039ce329SXuan Zhuo struct eea_ring *eea_ering_alloc(u32 index, u32 num, struct eea_device *edev, 202*039ce329SXuan Zhuo u8 sq_desc_size, u8 cq_desc_size, 203*039ce329SXuan Zhuo const char *name) 204*039ce329SXuan Zhuo { 205*039ce329SXuan Zhuo struct eea_ring *ering; 206*039ce329SXuan Zhuo 207*039ce329SXuan Zhuo if (num > EEA_NET_IO_HW_RING_DEPTH_MAX || 208*039ce329SXuan Zhuo num < EEA_NET_IO_RING_DEPTH_MIN) 209*039ce329SXuan Zhuo return NULL; 210*039ce329SXuan Zhuo 211*039ce329SXuan Zhuo if (!is_power_of_2(num)) 212*039ce329SXuan Zhuo return NULL; 213*039ce329SXuan Zhuo 214*039ce329SXuan Zhuo if (!sq_desc_size || !is_power_of_2(sq_desc_size)) 215*039ce329SXuan Zhuo return NULL; 216*039ce329SXuan Zhuo 217*039ce329SXuan Zhuo if (!cq_desc_size || !is_power_of_2(cq_desc_size)) 218*039ce329SXuan Zhuo return NULL; 219*039ce329SXuan Zhuo 220*039ce329SXuan Zhuo ering = kzalloc(sizeof(*ering), GFP_KERNEL); 221*039ce329SXuan Zhuo if (!ering) 222*039ce329SXuan Zhuo return NULL; 223*039ce329SXuan Zhuo 224*039ce329SXuan Zhuo ering->edev = edev; 225*039ce329SXuan Zhuo ering->name = name; 226*039ce329SXuan Zhuo ering->index = index; 227*039ce329SXuan Zhuo 228*039ce329SXuan Zhuo if (ering_alloc_queues(ering, edev, num, sq_desc_size, cq_desc_size)) 229*039ce329SXuan Zhuo goto err_free; 230*039ce329SXuan Zhuo 231*039ce329SXuan Zhuo ering_init(ering); 232*039ce329SXuan Zhuo 233*039ce329SXuan Zhuo return ering; 234*039ce329SXuan Zhuo 235*039ce329SXuan Zhuo err_free: 236*039ce329SXuan Zhuo kfree(ering); 237*039ce329SXuan Zhuo return NULL; 238*039ce329SXuan Zhuo } 239*039ce329SXuan Zhuo 240*039ce329SXuan Zhuo void eea_ering_free(struct eea_ring *ering) 241*039ce329SXuan Zhuo { 242*039ce329SXuan Zhuo ering_free_queue(ering->edev, ering->cq.dma_size, 243*039ce329SXuan Zhuo ering->cq.desc, ering->cq.dma_addr); 244*039ce329SXuan Zhuo 245*039ce329SXuan Zhuo ering_free_queue(ering->edev, ering->sq.dma_size, 246*039ce329SXuan Zhuo ering->sq.desc, ering->sq.dma_addr); 247*039ce329SXuan Zhuo 248*039ce329SXuan Zhuo kfree(ering); 249*039ce329SXuan Zhuo } 250