18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel IFC VF NIC driver for virtio dataplane offloading 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Intel Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Zhu Lingshan <lingshan.zhu@intel.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "ifcvf_base.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic inline u8 ifc_ioread8(u8 __iomem *addr) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci return ioread8(addr); 168c2ecf20Sopenharmony_ci} 178c2ecf20Sopenharmony_cistatic inline u16 ifc_ioread16 (__le16 __iomem *addr) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci return ioread16(addr); 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic inline u32 ifc_ioread32(__le32 __iomem *addr) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci return ioread32(addr); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic inline void ifc_iowrite8(u8 value, u8 __iomem *addr) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci iowrite8(value, addr); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline void ifc_iowrite16(u16 value, __le16 __iomem *addr) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci iowrite16(value, addr); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline void ifc_iowrite32(u32 value, __le32 __iomem *addr) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci iowrite32(value, addr); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void ifc_iowrite64_twopart(u64 val, 438c2ecf20Sopenharmony_ci __le32 __iomem *lo, __le32 __iomem *hi) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci ifc_iowrite32((u32)val, lo); 468c2ecf20Sopenharmony_ci ifc_iowrite32(val >> 32, hi); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return container_of(hw, struct ifcvf_adapter, vf); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void __iomem *get_cap_addr(struct ifcvf_hw *hw, 558c2ecf20Sopenharmony_ci struct virtio_pci_cap *cap) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct ifcvf_adapter *ifcvf; 588c2ecf20Sopenharmony_ci struct pci_dev *pdev; 598c2ecf20Sopenharmony_ci u32 length, offset; 608c2ecf20Sopenharmony_ci u8 bar; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci length = le32_to_cpu(cap->length); 638c2ecf20Sopenharmony_ci offset = le32_to_cpu(cap->offset); 648c2ecf20Sopenharmony_ci bar = cap->bar; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ifcvf= vf_to_adapter(hw); 678c2ecf20Sopenharmony_ci pdev = ifcvf->pdev; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (bar >= IFCVF_PCI_MAX_RESOURCE) { 708c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, 718c2ecf20Sopenharmony_ci "Invalid bar number %u to get capabilities\n", bar); 728c2ecf20Sopenharmony_ci return NULL; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (offset + length > pci_resource_len(pdev, bar)) { 768c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, 778c2ecf20Sopenharmony_ci "offset(%u) + len(%u) overflows bar%u's capability\n", 788c2ecf20Sopenharmony_ci offset, length, bar); 798c2ecf20Sopenharmony_ci return NULL; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return hw->base[bar] + offset; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int ifcvf_read_config_range(struct pci_dev *dev, 868c2ecf20Sopenharmony_ci uint32_t *val, int size, int where) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci int ret, i; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci for (i = 0; i < size; i += 4) { 918c2ecf20Sopenharmony_ci ret = pci_read_config_dword(dev, where + i, val + i / 4); 928c2ecf20Sopenharmony_ci if (ret < 0) 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciint ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct virtio_pci_cap cap; 1028c2ecf20Sopenharmony_ci u16 notify_off; 1038c2ecf20Sopenharmony_ci int ret; 1048c2ecf20Sopenharmony_ci u8 pos; 1058c2ecf20Sopenharmony_ci u32 i; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos); 1088c2ecf20Sopenharmony_ci if (ret < 0) { 1098c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to read PCI capability list\n"); 1108c2ecf20Sopenharmony_ci return -EIO; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci while (pos) { 1148c2ecf20Sopenharmony_ci ret = ifcvf_read_config_range(pdev, (u32 *)&cap, 1158c2ecf20Sopenharmony_ci sizeof(cap), pos); 1168c2ecf20Sopenharmony_ci if (ret < 0) { 1178c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, 1188c2ecf20Sopenharmony_ci "Failed to get PCI capability at %x\n", pos); 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (cap.cap_vndr != PCI_CAP_ID_VNDR) 1238c2ecf20Sopenharmony_ci goto next; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci switch (cap.cfg_type) { 1268c2ecf20Sopenharmony_ci case VIRTIO_PCI_CAP_COMMON_CFG: 1278c2ecf20Sopenharmony_ci hw->common_cfg = get_cap_addr(hw, &cap); 1288c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, "hw->common_cfg = %p\n", 1298c2ecf20Sopenharmony_ci hw->common_cfg); 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case VIRTIO_PCI_CAP_NOTIFY_CFG: 1328c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, pos + sizeof(cap), 1338c2ecf20Sopenharmony_ci &hw->notify_off_multiplier); 1348c2ecf20Sopenharmony_ci hw->notify_bar = cap.bar; 1358c2ecf20Sopenharmony_ci hw->notify_base = get_cap_addr(hw, &cap); 1368c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, "hw->notify_base = %p\n", 1378c2ecf20Sopenharmony_ci hw->notify_base); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci case VIRTIO_PCI_CAP_ISR_CFG: 1408c2ecf20Sopenharmony_ci hw->isr = get_cap_addr(hw, &cap); 1418c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, "hw->isr = %p\n", hw->isr); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case VIRTIO_PCI_CAP_DEVICE_CFG: 1448c2ecf20Sopenharmony_ci hw->net_cfg = get_cap_addr(hw, &cap); 1458c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, "hw->net_cfg = %p\n", hw->net_cfg); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cinext: 1508c2ecf20Sopenharmony_ci pos = cap.cap_next; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (hw->common_cfg == NULL || hw->notify_base == NULL || 1548c2ecf20Sopenharmony_ci hw->isr == NULL || hw->net_cfg == NULL) { 1558c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Incomplete PCI capabilities\n"); 1568c2ecf20Sopenharmony_ci return -EIO; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) { 1608c2ecf20Sopenharmony_ci ifc_iowrite16(i, &hw->common_cfg->queue_select); 1618c2ecf20Sopenharmony_ci notify_off = ifc_ioread16(&hw->common_cfg->queue_notify_off); 1628c2ecf20Sopenharmony_ci hw->vring[i].notify_addr = hw->notify_base + 1638c2ecf20Sopenharmony_ci notify_off * hw->notify_off_multiplier; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci hw->lm_cfg = hw->base[IFCVF_LM_BAR]; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci IFCVF_DBG(pdev, 1698c2ecf20Sopenharmony_ci "PCI capability mapping: common cfg: %p, notify base: %p\n, isr cfg: %p, device cfg: %p, multiplier: %u\n", 1708c2ecf20Sopenharmony_ci hw->common_cfg, hw->notify_base, hw->isr, 1718c2ecf20Sopenharmony_ci hw->net_cfg, hw->notify_off_multiplier); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciu8 ifcvf_get_status(struct ifcvf_hw *hw) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return ifc_ioread8(&hw->common_cfg->device_status); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_civoid ifcvf_set_status(struct ifcvf_hw *hw, u8 status) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci ifc_iowrite8(status, &hw->common_cfg->device_status); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_civoid ifcvf_reset(struct ifcvf_hw *hw) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci hw->config_cb.callback = NULL; 1898c2ecf20Sopenharmony_ci hw->config_cb.private = NULL; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ifcvf_set_status(hw, 0); 1928c2ecf20Sopenharmony_ci /* flush set_status, make sure VF is stopped, reset */ 1938c2ecf20Sopenharmony_ci ifcvf_get_status(hw); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void ifcvf_add_status(struct ifcvf_hw *hw, u8 status) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci if (status != 0) 1998c2ecf20Sopenharmony_ci status |= ifcvf_get_status(hw); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ifcvf_set_status(hw, status); 2028c2ecf20Sopenharmony_ci ifcvf_get_status(hw); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciu64 ifcvf_get_features(struct ifcvf_hw *hw) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 2088c2ecf20Sopenharmony_ci u32 features_lo, features_hi; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci ifc_iowrite32(0, &cfg->device_feature_select); 2118c2ecf20Sopenharmony_ci features_lo = ifc_ioread32(&cfg->device_feature); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ifc_iowrite32(1, &cfg->device_feature_select); 2148c2ecf20Sopenharmony_ci features_hi = ifc_ioread32(&cfg->device_feature); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return ((u64)features_hi << 32) | features_lo; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_civoid ifcvf_read_net_config(struct ifcvf_hw *hw, u64 offset, 2208c2ecf20Sopenharmony_ci void *dst, int length) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci u8 old_gen, new_gen, *p; 2238c2ecf20Sopenharmony_ci int i; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci WARN_ON(offset + length > sizeof(struct virtio_net_config)); 2268c2ecf20Sopenharmony_ci do { 2278c2ecf20Sopenharmony_ci old_gen = ifc_ioread8(&hw->common_cfg->config_generation); 2288c2ecf20Sopenharmony_ci p = dst; 2298c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) 2308c2ecf20Sopenharmony_ci *p++ = ifc_ioread8(hw->net_cfg + offset + i); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci new_gen = ifc_ioread8(&hw->common_cfg->config_generation); 2338c2ecf20Sopenharmony_ci } while (old_gen != new_gen); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_civoid ifcvf_write_net_config(struct ifcvf_hw *hw, u64 offset, 2378c2ecf20Sopenharmony_ci const void *src, int length) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci const u8 *p; 2408c2ecf20Sopenharmony_ci int i; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci p = src; 2438c2ecf20Sopenharmony_ci WARN_ON(offset + length > sizeof(struct virtio_net_config)); 2448c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) 2458c2ecf20Sopenharmony_ci ifc_iowrite8(*p++, hw->net_cfg + offset + i); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void ifcvf_set_features(struct ifcvf_hw *hw, u64 features) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ifc_iowrite32(0, &cfg->guest_feature_select); 2538c2ecf20Sopenharmony_ci ifc_iowrite32((u32)features, &cfg->guest_feature); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ifc_iowrite32(1, &cfg->guest_feature_select); 2568c2ecf20Sopenharmony_ci ifc_iowrite32(features >> 32, &cfg->guest_feature); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int ifcvf_config_features(struct ifcvf_hw *hw) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ifcvf_adapter *ifcvf; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ifcvf = vf_to_adapter(hw); 2648c2ecf20Sopenharmony_ci ifcvf_set_features(hw, hw->req_features); 2658c2ecf20Sopenharmony_ci ifcvf_add_status(hw, VIRTIO_CONFIG_S_FEATURES_OK); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (!(ifcvf_get_status(hw) & VIRTIO_CONFIG_S_FEATURES_OK)) { 2688c2ecf20Sopenharmony_ci IFCVF_ERR(ifcvf->pdev, "Failed to set FEATURES_OK status\n"); 2698c2ecf20Sopenharmony_ci return -EIO; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciu16 ifcvf_get_vq_state(struct ifcvf_hw *hw, u16 qid) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct ifcvf_lm_cfg __iomem *ifcvf_lm; 2788c2ecf20Sopenharmony_ci void __iomem *avail_idx_addr; 2798c2ecf20Sopenharmony_ci u16 last_avail_idx; 2808c2ecf20Sopenharmony_ci u32 q_pair_id; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg; 2838c2ecf20Sopenharmony_ci q_pair_id = qid / (IFCVF_MAX_QUEUE_PAIRS * 2); 2848c2ecf20Sopenharmony_ci avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2]; 2858c2ecf20Sopenharmony_ci last_avail_idx = ifc_ioread16(avail_idx_addr); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return last_avail_idx; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ciint ifcvf_set_vq_state(struct ifcvf_hw *hw, u16 qid, u16 num) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct ifcvf_lm_cfg __iomem *ifcvf_lm; 2938c2ecf20Sopenharmony_ci void __iomem *avail_idx_addr; 2948c2ecf20Sopenharmony_ci u32 q_pair_id; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg; 2978c2ecf20Sopenharmony_ci q_pair_id = qid / (IFCVF_MAX_QUEUE_PAIRS * 2); 2988c2ecf20Sopenharmony_ci avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2]; 2998c2ecf20Sopenharmony_ci hw->vring[qid].last_avail_idx = num; 3008c2ecf20Sopenharmony_ci ifc_iowrite16(num, avail_idx_addr); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int ifcvf_hw_enable(struct ifcvf_hw *hw) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg; 3088c2ecf20Sopenharmony_ci struct ifcvf_adapter *ifcvf; 3098c2ecf20Sopenharmony_ci u32 i; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ifcvf = vf_to_adapter(hw); 3128c2ecf20Sopenharmony_ci cfg = hw->common_cfg; 3138c2ecf20Sopenharmony_ci ifc_iowrite16(IFCVF_MSI_CONFIG_OFF, &cfg->msix_config); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (ifc_ioread16(&cfg->msix_config) == VIRTIO_MSI_NO_VECTOR) { 3168c2ecf20Sopenharmony_ci IFCVF_ERR(ifcvf->pdev, "No msix vector for device config\n"); 3178c2ecf20Sopenharmony_ci return -EINVAL; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci for (i = 0; i < hw->nr_vring; i++) { 3218c2ecf20Sopenharmony_ci if (!hw->vring[i].ready) 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ifc_iowrite16(i, &cfg->queue_select); 3258c2ecf20Sopenharmony_ci ifc_iowrite64_twopart(hw->vring[i].desc, &cfg->queue_desc_lo, 3268c2ecf20Sopenharmony_ci &cfg->queue_desc_hi); 3278c2ecf20Sopenharmony_ci ifc_iowrite64_twopart(hw->vring[i].avail, &cfg->queue_avail_lo, 3288c2ecf20Sopenharmony_ci &cfg->queue_avail_hi); 3298c2ecf20Sopenharmony_ci ifc_iowrite64_twopart(hw->vring[i].used, &cfg->queue_used_lo, 3308c2ecf20Sopenharmony_ci &cfg->queue_used_hi); 3318c2ecf20Sopenharmony_ci ifc_iowrite16(hw->vring[i].size, &cfg->queue_size); 3328c2ecf20Sopenharmony_ci ifc_iowrite16(i + IFCVF_MSI_QUEUE_OFF, &cfg->queue_msix_vector); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (ifc_ioread16(&cfg->queue_msix_vector) == 3358c2ecf20Sopenharmony_ci VIRTIO_MSI_NO_VECTOR) { 3368c2ecf20Sopenharmony_ci IFCVF_ERR(ifcvf->pdev, 3378c2ecf20Sopenharmony_ci "No msix vector for queue %u\n", i); 3388c2ecf20Sopenharmony_ci return -EINVAL; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ifcvf_set_vq_state(hw, i, hw->vring[i].last_avail_idx); 3428c2ecf20Sopenharmony_ci ifc_iowrite16(1, &cfg->queue_enable); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void ifcvf_hw_disable(struct ifcvf_hw *hw) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg; 3518c2ecf20Sopenharmony_ci u32 i; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci cfg = hw->common_cfg; 3548c2ecf20Sopenharmony_ci ifc_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->msix_config); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci for (i = 0; i < hw->nr_vring; i++) { 3578c2ecf20Sopenharmony_ci ifc_iowrite16(i, &cfg->queue_select); 3588c2ecf20Sopenharmony_ci ifc_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->queue_msix_vector); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ifc_ioread16(&cfg->queue_msix_vector); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ciint ifcvf_start_hw(struct ifcvf_hw *hw) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci ifcvf_reset(hw); 3678c2ecf20Sopenharmony_ci ifcvf_add_status(hw, VIRTIO_CONFIG_S_ACKNOWLEDGE); 3688c2ecf20Sopenharmony_ci ifcvf_add_status(hw, VIRTIO_CONFIG_S_DRIVER); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (ifcvf_config_features(hw) < 0) 3718c2ecf20Sopenharmony_ci return -EINVAL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (ifcvf_hw_enable(hw) < 0) 3748c2ecf20Sopenharmony_ci return -EINVAL; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci ifcvf_add_status(hw, VIRTIO_CONFIG_S_DRIVER_OK); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_civoid ifcvf_stop_hw(struct ifcvf_hw *hw) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci ifcvf_hw_disable(hw); 3848c2ecf20Sopenharmony_ci ifcvf_reset(hw); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_civoid ifcvf_notify_queue(struct ifcvf_hw *hw, u16 qid) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci ifc_iowrite16(qid, hw->vring[qid].notify_addr); 3908c2ecf20Sopenharmony_ci} 391