162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel IFC VF NIC driver for virtio dataplane offloading 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Intel Corporation. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Zhu Lingshan <lingshan.zhu@intel.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "ifcvf_base.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ciu16 ifcvf_set_vq_vector(struct ifcvf_hw *hw, u16 qid, int vector) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci vp_iowrite16(qid, &cfg->queue_select); 1862306a36Sopenharmony_ci vp_iowrite16(vector, &cfg->queue_msix_vector); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci return vp_ioread16(&cfg->queue_msix_vector); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciu16 ifcvf_set_config_vector(struct ifcvf_hw *hw, int vector) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci vp_iowrite16(vector, &cfg->msix_config); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return vp_ioread16(&cfg->msix_config); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void __iomem *get_cap_addr(struct ifcvf_hw *hw, 3362306a36Sopenharmony_ci struct virtio_pci_cap *cap) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci u32 length, offset; 3662306a36Sopenharmony_ci u8 bar; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci length = le32_to_cpu(cap->length); 3962306a36Sopenharmony_ci offset = le32_to_cpu(cap->offset); 4062306a36Sopenharmony_ci bar = cap->bar; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (bar >= IFCVF_PCI_MAX_RESOURCE) { 4362306a36Sopenharmony_ci IFCVF_DBG(hw->pdev, 4462306a36Sopenharmony_ci "Invalid bar number %u to get capabilities\n", bar); 4562306a36Sopenharmony_ci return NULL; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (offset + length > pci_resource_len(hw->pdev, bar)) { 4962306a36Sopenharmony_ci IFCVF_DBG(hw->pdev, 5062306a36Sopenharmony_ci "offset(%u) + len(%u) overflows bar%u's capability\n", 5162306a36Sopenharmony_ci offset, length, bar); 5262306a36Sopenharmony_ci return NULL; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return hw->base[bar] + offset; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int ifcvf_read_config_range(struct pci_dev *dev, 5962306a36Sopenharmony_ci uint32_t *val, int size, int where) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int ret, i; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci for (i = 0; i < size; i += 4) { 6462306a36Sopenharmony_ci ret = pci_read_config_dword(dev, where + i, val + i / 4); 6562306a36Sopenharmony_ci if (ret < 0) 6662306a36Sopenharmony_ci return ret; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic u16 ifcvf_get_vq_size(struct ifcvf_hw *hw, u16 qid) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci u16 queue_size; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci vp_iowrite16(qid, &hw->common_cfg->queue_select); 7762306a36Sopenharmony_ci queue_size = vp_ioread16(&hw->common_cfg->queue_size); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return queue_size; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* This function returns the max allowed safe size for 8362306a36Sopenharmony_ci * all virtqueues. It is the minimal size that can be 8462306a36Sopenharmony_ci * suppprted by all virtqueues. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ciu16 ifcvf_get_max_vq_size(struct ifcvf_hw *hw) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci u16 queue_size, max_size, qid; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci max_size = ifcvf_get_vq_size(hw, 0); 9162306a36Sopenharmony_ci for (qid = 1; qid < hw->nr_vring; qid++) { 9262306a36Sopenharmony_ci queue_size = ifcvf_get_vq_size(hw, qid); 9362306a36Sopenharmony_ci /* 0 means the queue is unavailable */ 9462306a36Sopenharmony_ci if (!queue_size) 9562306a36Sopenharmony_ci continue; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci max_size = min(queue_size, max_size); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return max_size; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciint ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct virtio_pci_cap cap; 10662306a36Sopenharmony_ci u16 notify_off; 10762306a36Sopenharmony_ci int ret; 10862306a36Sopenharmony_ci u8 pos; 10962306a36Sopenharmony_ci u32 i; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos); 11262306a36Sopenharmony_ci if (ret < 0) { 11362306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to read PCI capability list\n"); 11462306a36Sopenharmony_ci return -EIO; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci hw->pdev = pdev; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci while (pos) { 11962306a36Sopenharmony_ci ret = ifcvf_read_config_range(pdev, (u32 *)&cap, 12062306a36Sopenharmony_ci sizeof(cap), pos); 12162306a36Sopenharmony_ci if (ret < 0) { 12262306a36Sopenharmony_ci IFCVF_ERR(pdev, 12362306a36Sopenharmony_ci "Failed to get PCI capability at %x\n", pos); 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (cap.cap_vndr != PCI_CAP_ID_VNDR) 12862306a36Sopenharmony_ci goto next; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci switch (cap.cfg_type) { 13162306a36Sopenharmony_ci case VIRTIO_PCI_CAP_COMMON_CFG: 13262306a36Sopenharmony_ci hw->common_cfg = get_cap_addr(hw, &cap); 13362306a36Sopenharmony_ci IFCVF_DBG(pdev, "hw->common_cfg = %p\n", 13462306a36Sopenharmony_ci hw->common_cfg); 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci case VIRTIO_PCI_CAP_NOTIFY_CFG: 13762306a36Sopenharmony_ci pci_read_config_dword(pdev, pos + sizeof(cap), 13862306a36Sopenharmony_ci &hw->notify_off_multiplier); 13962306a36Sopenharmony_ci hw->notify_bar = cap.bar; 14062306a36Sopenharmony_ci hw->notify_base = get_cap_addr(hw, &cap); 14162306a36Sopenharmony_ci hw->notify_base_pa = pci_resource_start(pdev, cap.bar) + 14262306a36Sopenharmony_ci le32_to_cpu(cap.offset); 14362306a36Sopenharmony_ci IFCVF_DBG(pdev, "hw->notify_base = %p\n", 14462306a36Sopenharmony_ci hw->notify_base); 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case VIRTIO_PCI_CAP_ISR_CFG: 14762306a36Sopenharmony_ci hw->isr = get_cap_addr(hw, &cap); 14862306a36Sopenharmony_ci IFCVF_DBG(pdev, "hw->isr = %p\n", hw->isr); 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case VIRTIO_PCI_CAP_DEVICE_CFG: 15162306a36Sopenharmony_ci hw->dev_cfg = get_cap_addr(hw, &cap); 15262306a36Sopenharmony_ci hw->cap_dev_config_size = le32_to_cpu(cap.length); 15362306a36Sopenharmony_ci IFCVF_DBG(pdev, "hw->dev_cfg = %p\n", hw->dev_cfg); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cinext: 15862306a36Sopenharmony_ci pos = cap.cap_next; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (hw->common_cfg == NULL || hw->notify_base == NULL || 16262306a36Sopenharmony_ci hw->isr == NULL || hw->dev_cfg == NULL) { 16362306a36Sopenharmony_ci IFCVF_ERR(pdev, "Incomplete PCI capabilities\n"); 16462306a36Sopenharmony_ci return -EIO; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci hw->nr_vring = vp_ioread16(&hw->common_cfg->num_queues); 16862306a36Sopenharmony_ci hw->vring = kzalloc(sizeof(struct vring_info) * hw->nr_vring, GFP_KERNEL); 16962306a36Sopenharmony_ci if (!hw->vring) 17062306a36Sopenharmony_ci return -ENOMEM; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci for (i = 0; i < hw->nr_vring; i++) { 17362306a36Sopenharmony_ci vp_iowrite16(i, &hw->common_cfg->queue_select); 17462306a36Sopenharmony_ci notify_off = vp_ioread16(&hw->common_cfg->queue_notify_off); 17562306a36Sopenharmony_ci hw->vring[i].notify_addr = hw->notify_base + 17662306a36Sopenharmony_ci notify_off * hw->notify_off_multiplier; 17762306a36Sopenharmony_ci hw->vring[i].notify_pa = hw->notify_base_pa + 17862306a36Sopenharmony_ci notify_off * hw->notify_off_multiplier; 17962306a36Sopenharmony_ci hw->vring[i].irq = -EINVAL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci hw->lm_cfg = hw->base[IFCVF_LM_BAR]; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci IFCVF_DBG(pdev, 18562306a36Sopenharmony_ci "PCI capability mapping: common cfg: %p, notify base: %p\n, isr cfg: %p, device cfg: %p, multiplier: %u\n", 18662306a36Sopenharmony_ci hw->common_cfg, hw->notify_base, hw->isr, 18762306a36Sopenharmony_ci hw->dev_cfg, hw->notify_off_multiplier); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci hw->vqs_reused_irq = -EINVAL; 19062306a36Sopenharmony_ci hw->config_irq = -EINVAL; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ciu8 ifcvf_get_status(struct ifcvf_hw *hw) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci return vp_ioread8(&hw->common_cfg->device_status); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_civoid ifcvf_set_status(struct ifcvf_hw *hw, u8 status) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci vp_iowrite8(status, &hw->common_cfg->device_status); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_civoid ifcvf_reset(struct ifcvf_hw *hw) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci ifcvf_set_status(hw, 0); 20862306a36Sopenharmony_ci while (ifcvf_get_status(hw)) 20962306a36Sopenharmony_ci msleep(1); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciu64 ifcvf_get_hw_features(struct ifcvf_hw *hw) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 21562306a36Sopenharmony_ci u32 features_lo, features_hi; 21662306a36Sopenharmony_ci u64 features; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci vp_iowrite32(0, &cfg->device_feature_select); 21962306a36Sopenharmony_ci features_lo = vp_ioread32(&cfg->device_feature); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci vp_iowrite32(1, &cfg->device_feature_select); 22262306a36Sopenharmony_ci features_hi = vp_ioread32(&cfg->device_feature); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci features = ((u64)features_hi << 32) | features_lo; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return features; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* return provisioned vDPA dev features */ 23062306a36Sopenharmony_ciu64 ifcvf_get_dev_features(struct ifcvf_hw *hw) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return hw->dev_features; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ciu64 ifcvf_get_driver_features(struct ifcvf_hw *hw) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 23862306a36Sopenharmony_ci u32 features_lo, features_hi; 23962306a36Sopenharmony_ci u64 features; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci vp_iowrite32(0, &cfg->device_feature_select); 24262306a36Sopenharmony_ci features_lo = vp_ioread32(&cfg->guest_feature); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci vp_iowrite32(1, &cfg->device_feature_select); 24562306a36Sopenharmony_ci features_hi = vp_ioread32(&cfg->guest_feature); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci features = ((u64)features_hi << 32) | features_lo; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return features; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciint ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) { 25562306a36Sopenharmony_ci IFCVF_ERR(hw->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n"); 25662306a36Sopenharmony_ci return -EINVAL; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciu32 ifcvf_get_config_size(struct ifcvf_hw *hw) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci u32 net_config_size = sizeof(struct virtio_net_config); 26562306a36Sopenharmony_ci u32 blk_config_size = sizeof(struct virtio_blk_config); 26662306a36Sopenharmony_ci u32 cap_size = hw->cap_dev_config_size; 26762306a36Sopenharmony_ci u32 config_size; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* If the onboard device config space size is greater than 27062306a36Sopenharmony_ci * the size of struct virtio_net/blk_config, only the spec 27162306a36Sopenharmony_ci * implementing contents size is returned, this is very 27262306a36Sopenharmony_ci * unlikely, defensive programming. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci switch (hw->dev_type) { 27562306a36Sopenharmony_ci case VIRTIO_ID_NET: 27662306a36Sopenharmony_ci config_size = min(cap_size, net_config_size); 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci case VIRTIO_ID_BLOCK: 27962306a36Sopenharmony_ci config_size = min(cap_size, blk_config_size); 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci default: 28262306a36Sopenharmony_ci config_size = 0; 28362306a36Sopenharmony_ci IFCVF_ERR(hw->pdev, "VIRTIO ID %u not supported\n", hw->dev_type); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return config_size; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_civoid ifcvf_read_dev_config(struct ifcvf_hw *hw, u64 offset, 29062306a36Sopenharmony_ci void *dst, int length) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci u8 old_gen, new_gen, *p; 29362306a36Sopenharmony_ci int i; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci WARN_ON(offset + length > hw->config_size); 29662306a36Sopenharmony_ci do { 29762306a36Sopenharmony_ci old_gen = vp_ioread8(&hw->common_cfg->config_generation); 29862306a36Sopenharmony_ci p = dst; 29962306a36Sopenharmony_ci for (i = 0; i < length; i++) 30062306a36Sopenharmony_ci *p++ = vp_ioread8(hw->dev_cfg + offset + i); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci new_gen = vp_ioread8(&hw->common_cfg->config_generation); 30362306a36Sopenharmony_ci } while (old_gen != new_gen); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_civoid ifcvf_write_dev_config(struct ifcvf_hw *hw, u64 offset, 30762306a36Sopenharmony_ci const void *src, int length) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci const u8 *p; 31062306a36Sopenharmony_ci int i; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci p = src; 31362306a36Sopenharmony_ci WARN_ON(offset + length > hw->config_size); 31462306a36Sopenharmony_ci for (i = 0; i < length; i++) 31562306a36Sopenharmony_ci vp_iowrite8(*p++, hw->dev_cfg + offset + i); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_civoid ifcvf_set_driver_features(struct ifcvf_hw *hw, u64 features) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci vp_iowrite32(0, &cfg->guest_feature_select); 32362306a36Sopenharmony_ci vp_iowrite32((u32)features, &cfg->guest_feature); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci vp_iowrite32(1, &cfg->guest_feature_select); 32662306a36Sopenharmony_ci vp_iowrite32(features >> 32, &cfg->guest_feature); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ciu16 ifcvf_get_vq_state(struct ifcvf_hw *hw, u16 qid) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct ifcvf_lm_cfg __iomem *lm_cfg = hw->lm_cfg; 33262306a36Sopenharmony_ci u16 last_avail_idx; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci last_avail_idx = vp_ioread16(&lm_cfg->vq_state_region + qid * 2); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return last_avail_idx; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ciint ifcvf_set_vq_state(struct ifcvf_hw *hw, u16 qid, u16 num) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct ifcvf_lm_cfg __iomem *lm_cfg = hw->lm_cfg; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci vp_iowrite16(num, &lm_cfg->vq_state_region + qid * 2); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_civoid ifcvf_set_vq_num(struct ifcvf_hw *hw, u16 qid, u32 num) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci vp_iowrite16(qid, &cfg->queue_select); 35362306a36Sopenharmony_ci vp_iowrite16(num, &cfg->queue_size); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciint ifcvf_set_vq_address(struct ifcvf_hw *hw, u16 qid, u64 desc_area, 35762306a36Sopenharmony_ci u64 driver_area, u64 device_area) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci vp_iowrite16(qid, &cfg->queue_select); 36262306a36Sopenharmony_ci vp_iowrite64_twopart(desc_area, &cfg->queue_desc_lo, 36362306a36Sopenharmony_ci &cfg->queue_desc_hi); 36462306a36Sopenharmony_ci vp_iowrite64_twopart(driver_area, &cfg->queue_avail_lo, 36562306a36Sopenharmony_ci &cfg->queue_avail_hi); 36662306a36Sopenharmony_ci vp_iowrite64_twopart(device_area, &cfg->queue_used_lo, 36762306a36Sopenharmony_ci &cfg->queue_used_hi); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cibool ifcvf_get_vq_ready(struct ifcvf_hw *hw, u16 qid) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 37562306a36Sopenharmony_ci u16 queue_enable; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci vp_iowrite16(qid, &cfg->queue_select); 37862306a36Sopenharmony_ci queue_enable = vp_ioread16(&cfg->queue_enable); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return (bool)queue_enable; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_civoid ifcvf_set_vq_ready(struct ifcvf_hw *hw, u16 qid, bool ready) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci vp_iowrite16(qid, &cfg->queue_select); 38862306a36Sopenharmony_ci vp_iowrite16(ready, &cfg->queue_enable); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void ifcvf_reset_vring(struct ifcvf_hw *hw) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci u16 qid; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci for (qid = 0; qid < hw->nr_vring; qid++) { 39662306a36Sopenharmony_ci hw->vring[qid].cb.callback = NULL; 39762306a36Sopenharmony_ci hw->vring[qid].cb.private = NULL; 39862306a36Sopenharmony_ci ifcvf_set_vq_vector(hw, qid, VIRTIO_MSI_NO_VECTOR); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void ifcvf_reset_config_handler(struct ifcvf_hw *hw) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci hw->config_cb.callback = NULL; 40562306a36Sopenharmony_ci hw->config_cb.private = NULL; 40662306a36Sopenharmony_ci ifcvf_set_config_vector(hw, VIRTIO_MSI_NO_VECTOR); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void ifcvf_synchronize_irq(struct ifcvf_hw *hw) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci u32 nvectors = hw->num_msix_vectors; 41262306a36Sopenharmony_ci struct pci_dev *pdev = hw->pdev; 41362306a36Sopenharmony_ci int i, irq; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < nvectors; i++) { 41662306a36Sopenharmony_ci irq = pci_irq_vector(pdev, i); 41762306a36Sopenharmony_ci if (irq >= 0) 41862306a36Sopenharmony_ci synchronize_irq(irq); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_civoid ifcvf_stop(struct ifcvf_hw *hw) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci ifcvf_synchronize_irq(hw); 42562306a36Sopenharmony_ci ifcvf_reset_vring(hw); 42662306a36Sopenharmony_ci ifcvf_reset_config_handler(hw); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_civoid ifcvf_notify_queue(struct ifcvf_hw *hw, u16 qid) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci vp_iowrite16(qid, hw->vring[qid].notify_addr); 43262306a36Sopenharmony_ci} 433