1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Intel Corporation 3 */ 4 5 #include "ifcvf.h" 6 #include "ifcvf_osdep.h" 7 8 STATIC void * 9 get_cap_addr(struct ifcvf_hw *hw, struct ifcvf_pci_cap *cap) 10 { 11 u8 bar = cap->bar; 12 u32 length = cap->length; 13 u32 offset = cap->offset; 14 15 if (bar > IFCVF_PCI_MAX_RESOURCE - 1) { 16 DEBUGOUT("invalid bar: %u\n", bar); 17 return NULL; 18 } 19 20 if (offset + length < offset) { 21 DEBUGOUT("offset(%u) + length(%u) overflows\n", 22 offset, length); 23 return NULL; 24 } 25 26 if (offset + length > hw->mem_resource[cap->bar].len) { 27 DEBUGOUT("offset(%u) + length(%u) overflows bar length(%u)", 28 offset, length, (u32)hw->mem_resource[cap->bar].len); 29 return NULL; 30 } 31 32 return hw->mem_resource[bar].addr + offset; 33 } 34 35 int 36 ifcvf_init_hw(struct ifcvf_hw *hw, PCI_DEV *dev) 37 { 38 int ret; 39 u8 pos; 40 struct ifcvf_pci_cap cap; 41 42 ret = PCI_READ_CONFIG_BYTE(dev, &pos, PCI_CAPABILITY_LIST); 43 if (ret < 0) { 44 DEBUGOUT("failed to read pci capability list\n"); 45 return -1; 46 } 47 48 while (pos) { 49 ret = PCI_READ_CONFIG_RANGE(dev, (u32 *)&cap, 50 sizeof(cap), pos); 51 if (ret < 0) { 52 DEBUGOUT("failed to read cap at pos: %x", pos); 53 break; 54 } 55 56 if (cap.cap_vndr != PCI_CAP_ID_VNDR) 57 goto next; 58 59 DEBUGOUT("cfg type: %u, bar: %u, offset: %u, " 60 "len: %u\n", cap.cfg_type, cap.bar, 61 cap.offset, cap.length); 62 63 switch (cap.cfg_type) { 64 case IFCVF_PCI_CAP_COMMON_CFG: 65 hw->common_cfg = get_cap_addr(hw, &cap); 66 break; 67 case IFCVF_PCI_CAP_NOTIFY_CFG: 68 ret = PCI_READ_CONFIG_DWORD(dev, 69 &hw->notify_off_multiplier, 70 pos + sizeof(cap)); 71 if (ret < 0) { 72 DEBUGOUT("failed to read notify_off_multiplier\n"); 73 return -1; 74 } 75 hw->notify_base = get_cap_addr(hw, &cap); 76 hw->notify_region = cap.bar; 77 break; 78 case IFCVF_PCI_CAP_ISR_CFG: 79 hw->isr = get_cap_addr(hw, &cap); 80 break; 81 case IFCVF_PCI_CAP_DEVICE_CFG: 82 hw->dev_cfg = get_cap_addr(hw, &cap); 83 break; 84 } 85 next: 86 pos = cap.cap_next; 87 } 88 89 hw->lm_cfg = hw->mem_resource[4].addr; 90 91 if (hw->common_cfg == NULL || hw->notify_base == NULL || 92 hw->isr == NULL || hw->dev_cfg == NULL) { 93 DEBUGOUT("capability incomplete\n"); 94 return -1; 95 } 96 97 DEBUGOUT("capability mapping:\ncommon cfg: %p\n" 98 "notify base: %p\nisr cfg: %p\ndevice cfg: %p\n" 99 "multiplier: %u\n", 100 hw->common_cfg, hw->dev_cfg, 101 hw->isr, hw->notify_base, 102 hw->notify_off_multiplier); 103 104 return 0; 105 } 106 107 STATIC u8 108 ifcvf_get_status(struct ifcvf_hw *hw) 109 { 110 return IFCVF_READ_REG8(&hw->common_cfg->device_status); 111 } 112 113 STATIC void 114 ifcvf_set_status(struct ifcvf_hw *hw, u8 status) 115 { 116 IFCVF_WRITE_REG8(status, &hw->common_cfg->device_status); 117 } 118 119 STATIC void 120 ifcvf_reset(struct ifcvf_hw *hw) 121 { 122 ifcvf_set_status(hw, 0); 123 124 /* flush status write */ 125 while (ifcvf_get_status(hw)) 126 msec_delay(1); 127 } 128 129 STATIC void 130 ifcvf_add_status(struct ifcvf_hw *hw, u8 status) 131 { 132 if (status != 0) 133 status |= ifcvf_get_status(hw); 134 135 ifcvf_set_status(hw, status); 136 ifcvf_get_status(hw); 137 } 138 139 u64 140 ifcvf_get_features(struct ifcvf_hw *hw) 141 { 142 u32 features_lo, features_hi; 143 struct ifcvf_pci_common_cfg *cfg = hw->common_cfg; 144 145 IFCVF_WRITE_REG32(0, &cfg->device_feature_select); 146 features_lo = IFCVF_READ_REG32(&cfg->device_feature); 147 148 IFCVF_WRITE_REG32(1, &cfg->device_feature_select); 149 features_hi = IFCVF_READ_REG32(&cfg->device_feature); 150 151 return ((u64)features_hi << 32) | features_lo; 152 } 153 154 STATIC void 155 ifcvf_set_features(struct ifcvf_hw *hw, u64 features) 156 { 157 struct ifcvf_pci_common_cfg *cfg = hw->common_cfg; 158 159 IFCVF_WRITE_REG32(0, &cfg->guest_feature_select); 160 IFCVF_WRITE_REG32(features & ((1ULL << 32) - 1), &cfg->guest_feature); 161 162 IFCVF_WRITE_REG32(1, &cfg->guest_feature_select); 163 IFCVF_WRITE_REG32(features >> 32, &cfg->guest_feature); 164 } 165 166 STATIC int 167 ifcvf_config_features(struct ifcvf_hw *hw) 168 { 169 u64 host_features; 170 171 host_features = ifcvf_get_features(hw); 172 hw->req_features &= host_features; 173 174 ifcvf_set_features(hw, hw->req_features); 175 ifcvf_add_status(hw, IFCVF_CONFIG_STATUS_FEATURES_OK); 176 177 if (!(ifcvf_get_status(hw) & IFCVF_CONFIG_STATUS_FEATURES_OK)) { 178 DEBUGOUT("failed to set FEATURES_OK status\n"); 179 return -1; 180 } 181 182 return 0; 183 } 184 185 STATIC void 186 io_write64_twopart(u64 val, u32 *lo, u32 *hi) 187 { 188 IFCVF_WRITE_REG32(val & ((1ULL << 32) - 1), lo); 189 IFCVF_WRITE_REG32(val >> 32, hi); 190 } 191 192 STATIC int 193 ifcvf_hw_enable(struct ifcvf_hw *hw) 194 { 195 struct ifcvf_pci_common_cfg *cfg; 196 u8 *lm_cfg; 197 u32 i; 198 u16 notify_off; 199 200 cfg = hw->common_cfg; 201 lm_cfg = hw->lm_cfg; 202 203 IFCVF_WRITE_REG16(0, &cfg->msix_config); 204 if (IFCVF_READ_REG16(&cfg->msix_config) == IFCVF_MSI_NO_VECTOR) { 205 DEBUGOUT("msix vec alloc failed for device config\n"); 206 return -1; 207 } 208 209 for (i = 0; i < hw->nr_vring; i++) { 210 IFCVF_WRITE_REG16(i, &cfg->queue_select); 211 io_write64_twopart(hw->vring[i].desc, &cfg->queue_desc_lo, 212 &cfg->queue_desc_hi); 213 io_write64_twopart(hw->vring[i].avail, &cfg->queue_avail_lo, 214 &cfg->queue_avail_hi); 215 io_write64_twopart(hw->vring[i].used, &cfg->queue_used_lo, 216 &cfg->queue_used_hi); 217 IFCVF_WRITE_REG16(hw->vring[i].size, &cfg->queue_size); 218 219 *(u32 *)(lm_cfg + IFCVF_LM_RING_STATE_OFFSET + 220 (i / 2) * IFCVF_LM_CFG_SIZE + (i % 2) * 4) = 221 (u32)hw->vring[i].last_avail_idx | 222 ((u32)hw->vring[i].last_used_idx << 16); 223 224 IFCVF_WRITE_REG16(i + 1, &cfg->queue_msix_vector); 225 if (IFCVF_READ_REG16(&cfg->queue_msix_vector) == 226 IFCVF_MSI_NO_VECTOR) { 227 DEBUGOUT("queue %u, msix vec alloc failed\n", 228 i); 229 return -1; 230 } 231 232 notify_off = IFCVF_READ_REG16(&cfg->queue_notify_off); 233 hw->notify_addr[i] = (void *)((u8 *)hw->notify_base + 234 notify_off * hw->notify_off_multiplier); 235 IFCVF_WRITE_REG16(1, &cfg->queue_enable); 236 } 237 238 return 0; 239 } 240 241 STATIC void 242 ifcvf_hw_disable(struct ifcvf_hw *hw) 243 { 244 u32 i; 245 struct ifcvf_pci_common_cfg *cfg; 246 u32 ring_state; 247 248 cfg = hw->common_cfg; 249 250 IFCVF_WRITE_REG16(IFCVF_MSI_NO_VECTOR, &cfg->msix_config); 251 for (i = 0; i < hw->nr_vring; i++) { 252 IFCVF_WRITE_REG16(i, &cfg->queue_select); 253 IFCVF_WRITE_REG16(0, &cfg->queue_enable); 254 IFCVF_WRITE_REG16(IFCVF_MSI_NO_VECTOR, &cfg->queue_msix_vector); 255 ring_state = *(u32 *)(hw->lm_cfg + IFCVF_LM_RING_STATE_OFFSET + 256 (i / 2) * IFCVF_LM_CFG_SIZE + (i % 2) * 4); 257 hw->vring[i].last_avail_idx = (u16)(ring_state >> 16); 258 hw->vring[i].last_used_idx = (u16)(ring_state >> 16); 259 } 260 } 261 262 int 263 ifcvf_start_hw(struct ifcvf_hw *hw) 264 { 265 ifcvf_reset(hw); 266 ifcvf_add_status(hw, IFCVF_CONFIG_STATUS_ACK); 267 ifcvf_add_status(hw, IFCVF_CONFIG_STATUS_DRIVER); 268 269 if (ifcvf_config_features(hw) < 0) 270 return -1; 271 272 if (ifcvf_hw_enable(hw) < 0) 273 return -1; 274 275 ifcvf_add_status(hw, IFCVF_CONFIG_STATUS_DRIVER_OK); 276 return 0; 277 } 278 279 void 280 ifcvf_stop_hw(struct ifcvf_hw *hw) 281 { 282 ifcvf_hw_disable(hw); 283 ifcvf_reset(hw); 284 } 285 286 void 287 ifcvf_enable_logging(struct ifcvf_hw *hw, u64 log_base, u64 log_size) 288 { 289 u8 *lm_cfg; 290 291 lm_cfg = hw->lm_cfg; 292 293 *(u32 *)(lm_cfg + IFCVF_LM_BASE_ADDR_LOW) = 294 log_base & IFCVF_32_BIT_MASK; 295 296 *(u32 *)(lm_cfg + IFCVF_LM_BASE_ADDR_HIGH) = 297 (log_base >> 32) & IFCVF_32_BIT_MASK; 298 299 *(u32 *)(lm_cfg + IFCVF_LM_END_ADDR_LOW) = 300 (log_base + log_size) & IFCVF_32_BIT_MASK; 301 302 *(u32 *)(lm_cfg + IFCVF_LM_END_ADDR_HIGH) = 303 ((log_base + log_size) >> 32) & IFCVF_32_BIT_MASK; 304 305 *(u32 *)(lm_cfg + IFCVF_LM_LOGGING_CTRL) = IFCVF_LM_ENABLE_VF; 306 } 307 308 void 309 ifcvf_disable_logging(struct ifcvf_hw *hw) 310 { 311 u8 *lm_cfg; 312 313 lm_cfg = hw->lm_cfg; 314 *(u32 *)(lm_cfg + IFCVF_LM_LOGGING_CTRL) = IFCVF_LM_DISABLE; 315 } 316 317 void 318 ifcvf_notify_queue(struct ifcvf_hw *hw, u16 qid) 319 { 320 IFCVF_WRITE_REG16(qid, hw->notify_addr[qid]); 321 } 322 323 u8 324 ifcvf_get_notify_region(struct ifcvf_hw *hw) 325 { 326 return hw->notify_region; 327 } 328 329 u64 330 ifcvf_get_queue_notify_off(struct ifcvf_hw *hw, int qid) 331 { 332 return (u8 *)hw->notify_addr[qid] - 333 (u8 *)hw->mem_resource[hw->notify_region].addr; 334 } 335