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 }; 75 76 void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, 77 unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, 78 unsigned int cq_tail_color, unsigned int interrupt_enable, 79 unsigned int cq_entry_enable, unsigned int message_enable, 80 unsigned int interrupt_offset, u64 message_addr); 81 void vnic_cq_clean(struct vnic_cq *cq); 82 83 static inline unsigned int vnic_cq_service(struct vnic_cq *cq, 84 unsigned int work_to_do, 85 int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc, 86 u8 type, u16 q_number, u16 completed_index, void *opaque), 87 void *opaque) 88 { 89 struct cq_desc *cq_desc; 90 unsigned int work_done = 0; 91 u16 q_number, completed_index; 92 u8 type, color; 93 94 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 95 cq->ring.desc_size * cq->to_clean); 96 cq_desc_dec(cq_desc, &type, &color, 97 &q_number, &completed_index); 98 99 while (color != cq->last_color) { 100 if ((*q_service)(cq->vdev, cq_desc, type, 101 q_number, completed_index, opaque)) 102 break; 103 104 cq->to_clean++; 105 if (cq->to_clean == cq->ring.desc_count) { 106 cq->to_clean = 0; 107 cq->last_color = cq->last_color ? 0 : 1; 108 } 109 110 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 111 cq->ring.desc_size * cq->to_clean); 112 cq_desc_dec(cq_desc, &type, &color, 113 &q_number, &completed_index); 114 115 work_done++; 116 if (work_done >= work_to_do) 117 break; 118 } 119 120 return work_done; 121 } 122 123 static inline unsigned int vnic_cq_work(struct vnic_cq *cq, 124 unsigned int work_to_do) 125 { 126 struct cq_desc *cq_desc; 127 unsigned int work_avail = 0; 128 u16 q_number, completed_index; 129 u8 type, color; 130 u32 to_clean, last_color; 131 132 to_clean = cq->to_clean; 133 last_color = cq->last_color; 134 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 135 cq->ring.desc_size * to_clean); 136 cq_desc_dec(cq_desc, &type, &color, 137 &q_number, &completed_index); 138 139 while (color != last_color) { 140 to_clean++; 141 if (to_clean == cq->ring.desc_count) { 142 to_clean = 0; 143 last_color = last_color ? 0 : 1; 144 } 145 146 cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + 147 cq->ring.desc_size * to_clean); 148 cq_desc_dec(cq_desc, &type, &color, 149 &q_number, &completed_index); 150 151 work_avail++; 152 if (work_avail >= work_to_do) 153 break; 154 } 155 156 return work_avail; 157 } 158 159 #endif /* _VNIC_CQ_H_ */ 160