1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2008-2017 Cisco Systems, Inc. All rights reserved. 3 * Copyright 2007 Nuova Systems, Inc. All rights reserved. 4 */ 5 6 #ifndef _VNIC_CQ_H_ 7 #define _VNIC_CQ_H_ 8 9 #include "cq_desc.h" 10 #include "vnic_dev.h" 11 12 /* Completion queue control */ 13 struct vnic_cq_ctrl { 14 u64 ring_base; /* 0x00 */ 15 #define CQ_RING_BASE 0x00 16 u32 ring_size; /* 0x08 */ 17 #define CQ_RING_SIZE 0x08 18 u32 pad0; 19 u32 flow_control_enable; /* 0x10 */ 20 #define CQ_FLOW_CONTROL_ENABLE 0x10 21 u32 pad1; 22 u32 color_enable; /* 0x18 */ 23 #define CQ_COLOR_ENABLE 0x18 24 u32 pad2; 25 u32 cq_head; /* 0x20 */ 26 #define CQ_HEAD 0x20 27 u32 pad3; 28 u32 cq_tail; /* 0x28 */ 29 #define CQ_TAIL 0x28 30 u32 pad4; 31 u32 cq_tail_color; /* 0x30 */ 32 #define CQ_TAIL_COLOR 0x30 33 u32 pad5; 34 u32 interrupt_enable; /* 0x38 */ 35 #define CQ_INTR_ENABLE 0x38 36 u32 pad6; 37 u32 cq_entry_enable; /* 0x40 */ 38 #define CQ_ENTRY_ENABLE 0x40 39 u32 pad7; 40 u32 cq_message_enable; /* 0x48 */ 41 #define CQ_MESSAGE_ENABLE 0x48 42 u32 pad8; 43 u32 interrupt_offset; /* 0x50 */ 44 #define CQ_INTR_OFFSET 0x50 45 u32 pad9; 46 u64 cq_message_addr; /* 0x58 */ 47 #define CQ_MESSAGE_ADDR 0x58 48 u32 pad10; 49 }; 50 51 #ifdef ENIC_AIC 52 struct vnic_rx_bytes_counter { 53 unsigned int small_pkt_bytes_cnt; 54 unsigned int large_pkt_bytes_cnt; 55 }; 56 #endif 57 58 struct vnic_cq { 59 unsigned int index; 60 struct vnic_dev *vdev; 61 struct vnic_res *ctrl; 62 struct vnic_dev_ring ring; 63 unsigned int to_clean; 64 unsigned int last_color; 65 unsigned int interrupt_offset; 66 unsigned int cur_rx_coal_timeval; 67 unsigned int tobe_rx_coal_timeval; 68 #ifdef ENIC_AIC 69 struct vnic_rx_bytes_counter pkt_size_counter; 70 unsigned int cur_rx_coal_timeval; 71 unsigned int tobe_rx_coal_timeval; 72 ktime_t prev_ts; 73 #endif 74 int ntxqsets; 75 int nrxqsets; 76 int ntxqsets_start; 77 int nrxqsets_start; 78 }; 79 80 void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, 81 unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, 82 unsigned int cq_tail_color, unsigned int interrupt_enable, 83 unsigned int cq_entry_enable, unsigned int message_enable, 84 unsigned int interrupt_offset, u64 message_addr); 85 void vnic_cq_clean(struct vnic_cq *cq); 86 87 static inline unsigned int vnic_cq_service(struct vnic_cq *cq, 88 unsigned int work_to_do, 89 int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc, 90 u8 type, u16 q_number, u16 completed_index, void *opaque), 91 void *opaque) 92 { 93 struct cq_desc *cq_desc; 94 unsigned int work_done = 0; 95 u16 q_number, completed_index; 96 u8 type, color; 97 98 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 99 cq->ring.desc_size * cq->to_clean); 100 cq_desc_dec(cq_desc, &type, &color, 101 &q_number, &completed_index); 102 103 while (color != cq->last_color) { 104 if ((*q_service)(cq->vdev, cq_desc, type, 105 q_number, completed_index, opaque)) 106 break; 107 108 cq->to_clean++; 109 if (cq->to_clean == cq->ring.desc_count) { 110 cq->to_clean = 0; 111 cq->last_color = cq->last_color ? 0 : 1; 112 } 113 114 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 115 cq->ring.desc_size * cq->to_clean); 116 cq_desc_dec(cq_desc, &type, &color, 117 &q_number, &completed_index); 118 119 work_done++; 120 if (work_done >= work_to_do) 121 break; 122 } 123 124 return work_done; 125 } 126 127 static inline unsigned int vnic_cq_work(struct vnic_cq *cq, 128 unsigned int work_to_do) 129 { 130 struct cq_desc *cq_desc; 131 unsigned int work_avail = 0; 132 u16 q_number, completed_index; 133 u8 type, color; 134 u32 to_clean, last_color; 135 136 to_clean = cq->to_clean; 137 last_color = cq->last_color; 138 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 139 cq->ring.desc_size * to_clean); 140 cq_desc_dec(cq_desc, &type, &color, 141 &q_number, &completed_index); 142 143 while (color != last_color) { 144 to_clean++; 145 if (to_clean == cq->ring.desc_count) { 146 to_clean = 0; 147 last_color = last_color ? 0 : 1; 148 } 149 150 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 151 cq->ring.desc_size * to_clean); 152 cq_desc_dec(cq_desc, &type, &color, 153 &q_number, &completed_index); 154 155 work_avail++; 156 if (work_avail >= work_to_do) 157 break; 158 } 159 160 return work_avail; 161 } 162 163 #endif /* _VNIC_CQ_H_ */ 164