162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vDPA bridge driver for modern virtio-pci device 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020, Red Hat Inc. All rights reserved. 662306a36Sopenharmony_ci * Author: Jason Wang <jasowang@redhat.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on virtio_pci_modern.c. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/vdpa.h> 1562306a36Sopenharmony_ci#include <linux/virtio.h> 1662306a36Sopenharmony_ci#include <linux/virtio_config.h> 1762306a36Sopenharmony_ci#include <linux/virtio_ring.h> 1862306a36Sopenharmony_ci#include <linux/virtio_pci.h> 1962306a36Sopenharmony_ci#include <linux/virtio_pci_modern.h> 2062306a36Sopenharmony_ci#include <uapi/linux/vdpa.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define VP_VDPA_QUEUE_MAX 256 2362306a36Sopenharmony_ci#define VP_VDPA_DRIVER_NAME "vp_vdpa" 2462306a36Sopenharmony_ci#define VP_VDPA_NAME_SIZE 256 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct vp_vring { 2762306a36Sopenharmony_ci void __iomem *notify; 2862306a36Sopenharmony_ci char msix_name[VP_VDPA_NAME_SIZE]; 2962306a36Sopenharmony_ci struct vdpa_callback cb; 3062306a36Sopenharmony_ci resource_size_t notify_pa; 3162306a36Sopenharmony_ci int irq; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct vp_vdpa { 3562306a36Sopenharmony_ci struct vdpa_device vdpa; 3662306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev; 3762306a36Sopenharmony_ci struct vp_vring *vring; 3862306a36Sopenharmony_ci struct vdpa_callback config_cb; 3962306a36Sopenharmony_ci u64 device_features; 4062306a36Sopenharmony_ci char msix_name[VP_VDPA_NAME_SIZE]; 4162306a36Sopenharmony_ci int config_irq; 4262306a36Sopenharmony_ci int queues; 4362306a36Sopenharmony_ci int vectors; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct vp_vdpa_mgmtdev { 4762306a36Sopenharmony_ci struct vdpa_mgmt_dev mgtdev; 4862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev; 4962306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic struct vp_vdpa *vdpa_to_vp(struct vdpa_device *vdpa) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci return container_of(vdpa, struct vp_vdpa, vdpa); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic struct virtio_pci_modern_device *vdpa_to_mdev(struct vdpa_device *vdpa) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return vp_vdpa->mdev; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic struct virtio_pci_modern_device *vp_vdpa_to_mdev(struct vp_vdpa *vp_vdpa) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci return vp_vdpa->mdev; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic u64 vp_vdpa_get_device_features(struct vdpa_device *vdpa) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return vp_vdpa->device_features; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int vp_vdpa_set_driver_features(struct vdpa_device *vdpa, u64 features) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci vp_modern_set_features(mdev, features); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic u64 vp_vdpa_get_driver_features(struct vdpa_device *vdpa) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return vp_modern_get_driver_features(mdev); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic u8 vp_vdpa_get_status(struct vdpa_device *vdpa) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return vp_modern_get_status(mdev); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int vp_vdpa_get_vq_irq(struct vdpa_device *vdpa, u16 idx) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 10262306a36Sopenharmony_ci int irq = vp_vdpa->vring[idx].irq; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (irq == VIRTIO_MSI_NO_VECTOR) 10562306a36Sopenharmony_ci return -EINVAL; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return irq; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void vp_vdpa_free_irq(struct vp_vdpa *vp_vdpa) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 11362306a36Sopenharmony_ci struct pci_dev *pdev = mdev->pci_dev; 11462306a36Sopenharmony_ci int i; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci for (i = 0; i < vp_vdpa->queues; i++) { 11762306a36Sopenharmony_ci if (vp_vdpa->vring[i].irq != VIRTIO_MSI_NO_VECTOR) { 11862306a36Sopenharmony_ci vp_modern_queue_vector(mdev, i, VIRTIO_MSI_NO_VECTOR); 11962306a36Sopenharmony_ci devm_free_irq(&pdev->dev, vp_vdpa->vring[i].irq, 12062306a36Sopenharmony_ci &vp_vdpa->vring[i]); 12162306a36Sopenharmony_ci vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (vp_vdpa->config_irq != VIRTIO_MSI_NO_VECTOR) { 12662306a36Sopenharmony_ci vp_modern_config_vector(mdev, VIRTIO_MSI_NO_VECTOR); 12762306a36Sopenharmony_ci devm_free_irq(&pdev->dev, vp_vdpa->config_irq, vp_vdpa); 12862306a36Sopenharmony_ci vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (vp_vdpa->vectors) { 13262306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 13362306a36Sopenharmony_ci vp_vdpa->vectors = 0; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic irqreturn_t vp_vdpa_vq_handler(int irq, void *arg) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct vp_vring *vring = arg; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (vring->cb.callback) 14262306a36Sopenharmony_ci return vring->cb.callback(vring->cb.private); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return IRQ_HANDLED; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic irqreturn_t vp_vdpa_config_handler(int irq, void *arg) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = arg; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (vp_vdpa->config_cb.callback) 15262306a36Sopenharmony_ci return vp_vdpa->config_cb.callback(vp_vdpa->config_cb.private); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return IRQ_HANDLED; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int vp_vdpa_request_irq(struct vp_vdpa *vp_vdpa) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 16062306a36Sopenharmony_ci struct pci_dev *pdev = mdev->pci_dev; 16162306a36Sopenharmony_ci int i, ret, irq; 16262306a36Sopenharmony_ci int queues = vp_vdpa->queues; 16362306a36Sopenharmony_ci int vectors = queues + 1; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, vectors, vectors, PCI_IRQ_MSIX); 16662306a36Sopenharmony_ci if (ret != vectors) { 16762306a36Sopenharmony_ci dev_err(&pdev->dev, 16862306a36Sopenharmony_ci "vp_vdpa: fail to allocate irq vectors want %d but %d\n", 16962306a36Sopenharmony_ci vectors, ret); 17062306a36Sopenharmony_ci return ret; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci vp_vdpa->vectors = vectors; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci for (i = 0; i < queues; i++) { 17662306a36Sopenharmony_ci snprintf(vp_vdpa->vring[i].msix_name, VP_VDPA_NAME_SIZE, 17762306a36Sopenharmony_ci "vp-vdpa[%s]-%d\n", pci_name(pdev), i); 17862306a36Sopenharmony_ci irq = pci_irq_vector(pdev, i); 17962306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, 18062306a36Sopenharmony_ci vp_vdpa_vq_handler, 18162306a36Sopenharmony_ci 0, vp_vdpa->vring[i].msix_name, 18262306a36Sopenharmony_ci &vp_vdpa->vring[i]); 18362306a36Sopenharmony_ci if (ret) { 18462306a36Sopenharmony_ci dev_err(&pdev->dev, 18562306a36Sopenharmony_ci "vp_vdpa: fail to request irq for vq %d\n", i); 18662306a36Sopenharmony_ci goto err; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci vp_modern_queue_vector(mdev, i, i); 18962306a36Sopenharmony_ci vp_vdpa->vring[i].irq = irq; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci snprintf(vp_vdpa->msix_name, VP_VDPA_NAME_SIZE, "vp-vdpa[%s]-config\n", 19362306a36Sopenharmony_ci pci_name(pdev)); 19462306a36Sopenharmony_ci irq = pci_irq_vector(pdev, queues); 19562306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, vp_vdpa_config_handler, 0, 19662306a36Sopenharmony_ci vp_vdpa->msix_name, vp_vdpa); 19762306a36Sopenharmony_ci if (ret) { 19862306a36Sopenharmony_ci dev_err(&pdev->dev, 19962306a36Sopenharmony_ci "vp_vdpa: fail to request irq for vq %d\n", i); 20062306a36Sopenharmony_ci goto err; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci vp_modern_config_vector(mdev, queues); 20362306a36Sopenharmony_ci vp_vdpa->config_irq = irq; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_cierr: 20762306a36Sopenharmony_ci vp_vdpa_free_irq(vp_vdpa); 20862306a36Sopenharmony_ci return ret; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 21462306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 21562306a36Sopenharmony_ci u8 s = vp_vdpa_get_status(vdpa); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (status & VIRTIO_CONFIG_S_DRIVER_OK && 21862306a36Sopenharmony_ci !(s & VIRTIO_CONFIG_S_DRIVER_OK)) { 21962306a36Sopenharmony_ci vp_vdpa_request_irq(vp_vdpa); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci vp_modern_set_status(mdev, status); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int vp_vdpa_reset(struct vdpa_device *vdpa) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 22862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 22962306a36Sopenharmony_ci u8 s = vp_vdpa_get_status(vdpa); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci vp_modern_set_status(mdev, 0); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (s & VIRTIO_CONFIG_S_DRIVER_OK) 23462306a36Sopenharmony_ci vp_vdpa_free_irq(vp_vdpa); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic u16 vp_vdpa_get_vq_num_max(struct vdpa_device *vdpa) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return VP_VDPA_QUEUE_MAX; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid, 24562306a36Sopenharmony_ci struct vdpa_vq_state *state) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci /* Note that this is not supported by virtio specification, so 24862306a36Sopenharmony_ci * we return -EOPNOTSUPP here. This means we can't support live 24962306a36Sopenharmony_ci * migration, vhost device start/stop. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci return -EOPNOTSUPP; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int vp_vdpa_set_vq_state_split(struct vdpa_device *vdpa, 25562306a36Sopenharmony_ci const struct vdpa_vq_state *state) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci const struct vdpa_vq_state_split *split = &state->split; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (split->avail_index == 0) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return -EOPNOTSUPP; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int vp_vdpa_set_vq_state_packed(struct vdpa_device *vdpa, 26662306a36Sopenharmony_ci const struct vdpa_vq_state *state) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci const struct vdpa_vq_state_packed *packed = &state->packed; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (packed->last_avail_counter == 1 && 27162306a36Sopenharmony_ci packed->last_avail_idx == 0 && 27262306a36Sopenharmony_ci packed->last_used_counter == 1 && 27362306a36Sopenharmony_ci packed->last_used_idx == 0) 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return -EOPNOTSUPP; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid, 28062306a36Sopenharmony_ci const struct vdpa_vq_state *state) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Note that this is not supported by virtio specification. 28562306a36Sopenharmony_ci * But if the state is by chance equal to the device initial 28662306a36Sopenharmony_ci * state, we can let it go. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci if ((vp_modern_get_status(mdev) & VIRTIO_CONFIG_S_FEATURES_OK) && 28962306a36Sopenharmony_ci !vp_modern_get_queue_enable(mdev, qid)) { 29062306a36Sopenharmony_ci if (vp_modern_get_driver_features(mdev) & 29162306a36Sopenharmony_ci BIT_ULL(VIRTIO_F_RING_PACKED)) 29262306a36Sopenharmony_ci return vp_vdpa_set_vq_state_packed(vdpa, state); 29362306a36Sopenharmony_ci else 29462306a36Sopenharmony_ci return vp_vdpa_set_vq_state_split(vdpa, state); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return -EOPNOTSUPP; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void vp_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 qid, 30162306a36Sopenharmony_ci struct vdpa_callback *cb) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci vp_vdpa->vring[qid].cb = *cb; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void vp_vdpa_set_vq_ready(struct vdpa_device *vdpa, 30962306a36Sopenharmony_ci u16 qid, bool ready) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci vp_modern_set_queue_enable(mdev, qid, ready); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic bool vp_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 qid) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return vp_modern_get_queue_enable(mdev, qid); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void vp_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 qid, 32462306a36Sopenharmony_ci u32 num) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci vp_modern_set_queue_size(mdev, qid, num); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int vp_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 qid, 33262306a36Sopenharmony_ci u64 desc_area, u64 driver_area, 33362306a36Sopenharmony_ci u64 device_area) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci vp_modern_queue_address(mdev, qid, desc_area, 33862306a36Sopenharmony_ci driver_area, device_area); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void vp_vdpa_kick_vq(struct vdpa_device *vdpa, u16 qid) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci vp_iowrite16(qid, vp_vdpa->vring[qid].notify); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic u32 vp_vdpa_get_generation(struct vdpa_device *vdpa) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return vp_modern_generation(mdev); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic u32 vp_vdpa_get_device_id(struct vdpa_device *vdpa) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return mdev->id.device; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic u32 vp_vdpa_get_vendor_id(struct vdpa_device *vdpa) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return mdev->id.vendor; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic u32 vp_vdpa_get_vq_align(struct vdpa_device *vdpa) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci return PAGE_SIZE; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic size_t vp_vdpa_get_config_size(struct vdpa_device *vdpa) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return mdev->device_len; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic void vp_vdpa_get_config(struct vdpa_device *vdpa, 38462306a36Sopenharmony_ci unsigned int offset, 38562306a36Sopenharmony_ci void *buf, unsigned int len) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 38862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 38962306a36Sopenharmony_ci u8 old, new; 39062306a36Sopenharmony_ci u8 *p; 39162306a36Sopenharmony_ci int i; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci do { 39462306a36Sopenharmony_ci old = vp_ioread8(&mdev->common->config_generation); 39562306a36Sopenharmony_ci p = buf; 39662306a36Sopenharmony_ci for (i = 0; i < len; i++) 39762306a36Sopenharmony_ci *p++ = vp_ioread8(mdev->device + offset + i); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci new = vp_ioread8(&mdev->common->config_generation); 40062306a36Sopenharmony_ci } while (old != new); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void vp_vdpa_set_config(struct vdpa_device *vdpa, 40462306a36Sopenharmony_ci unsigned int offset, const void *buf, 40562306a36Sopenharmony_ci unsigned int len) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 40862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 40962306a36Sopenharmony_ci const u8 *p = buf; 41062306a36Sopenharmony_ci int i; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci for (i = 0; i < len; i++) 41362306a36Sopenharmony_ci vp_iowrite8(*p++, mdev->device + offset + i); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void vp_vdpa_set_config_cb(struct vdpa_device *vdpa, 41762306a36Sopenharmony_ci struct vdpa_callback *cb) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci vp_vdpa->config_cb = *cb; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic struct vdpa_notification_area 42562306a36Sopenharmony_civp_vdpa_get_vq_notification(struct vdpa_device *vdpa, u16 qid) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 42862306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 42962306a36Sopenharmony_ci struct vdpa_notification_area notify; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci notify.addr = vp_vdpa->vring[qid].notify_pa; 43262306a36Sopenharmony_ci notify.size = mdev->notify_offset_multiplier; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return notify; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct vdpa_config_ops vp_vdpa_ops = { 43862306a36Sopenharmony_ci .get_device_features = vp_vdpa_get_device_features, 43962306a36Sopenharmony_ci .set_driver_features = vp_vdpa_set_driver_features, 44062306a36Sopenharmony_ci .get_driver_features = vp_vdpa_get_driver_features, 44162306a36Sopenharmony_ci .get_status = vp_vdpa_get_status, 44262306a36Sopenharmony_ci .set_status = vp_vdpa_set_status, 44362306a36Sopenharmony_ci .reset = vp_vdpa_reset, 44462306a36Sopenharmony_ci .get_vq_num_max = vp_vdpa_get_vq_num_max, 44562306a36Sopenharmony_ci .get_vq_state = vp_vdpa_get_vq_state, 44662306a36Sopenharmony_ci .get_vq_notification = vp_vdpa_get_vq_notification, 44762306a36Sopenharmony_ci .set_vq_state = vp_vdpa_set_vq_state, 44862306a36Sopenharmony_ci .set_vq_cb = vp_vdpa_set_vq_cb, 44962306a36Sopenharmony_ci .set_vq_ready = vp_vdpa_set_vq_ready, 45062306a36Sopenharmony_ci .get_vq_ready = vp_vdpa_get_vq_ready, 45162306a36Sopenharmony_ci .set_vq_num = vp_vdpa_set_vq_num, 45262306a36Sopenharmony_ci .set_vq_address = vp_vdpa_set_vq_address, 45362306a36Sopenharmony_ci .kick_vq = vp_vdpa_kick_vq, 45462306a36Sopenharmony_ci .get_generation = vp_vdpa_get_generation, 45562306a36Sopenharmony_ci .get_device_id = vp_vdpa_get_device_id, 45662306a36Sopenharmony_ci .get_vendor_id = vp_vdpa_get_vendor_id, 45762306a36Sopenharmony_ci .get_vq_align = vp_vdpa_get_vq_align, 45862306a36Sopenharmony_ci .get_config_size = vp_vdpa_get_config_size, 45962306a36Sopenharmony_ci .get_config = vp_vdpa_get_config, 46062306a36Sopenharmony_ci .set_config = vp_vdpa_set_config, 46162306a36Sopenharmony_ci .set_config_cb = vp_vdpa_set_config_cb, 46262306a36Sopenharmony_ci .get_vq_irq = vp_vdpa_get_vq_irq, 46362306a36Sopenharmony_ci}; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void vp_vdpa_free_irq_vectors(void *data) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci pci_free_irq_vectors(data); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, 47162306a36Sopenharmony_ci const struct vdpa_dev_set_config *add_config) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = 47462306a36Sopenharmony_ci container_of(v_mdev, struct vp_vdpa_mgmtdev, mgtdev); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = vp_vdpa_mgtdev->mdev; 47762306a36Sopenharmony_ci struct pci_dev *pdev = mdev->pci_dev; 47862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 47962306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = NULL; 48062306a36Sopenharmony_ci u64 device_features; 48162306a36Sopenharmony_ci int ret, i; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa, 48462306a36Sopenharmony_ci dev, &vp_vdpa_ops, 1, 1, name, false); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (IS_ERR(vp_vdpa)) { 48762306a36Sopenharmony_ci dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n"); 48862306a36Sopenharmony_ci return PTR_ERR(vp_vdpa); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci vp_vdpa_mgtdev->vp_vdpa = vp_vdpa; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci vp_vdpa->vdpa.dma_dev = &pdev->dev; 49462306a36Sopenharmony_ci vp_vdpa->queues = vp_modern_get_num_queues(mdev); 49562306a36Sopenharmony_ci vp_vdpa->mdev = mdev; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci device_features = vp_modern_get_features(mdev); 49862306a36Sopenharmony_ci if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 49962306a36Sopenharmony_ci if (add_config->device_features & ~device_features) { 50062306a36Sopenharmony_ci ret = -EINVAL; 50162306a36Sopenharmony_ci dev_err(&pdev->dev, "Try to provision features " 50262306a36Sopenharmony_ci "that are not supported by the device: " 50362306a36Sopenharmony_ci "device_features 0x%llx provisioned 0x%llx\n", 50462306a36Sopenharmony_ci device_features, add_config->device_features); 50562306a36Sopenharmony_ci goto err; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci device_features = add_config->device_features; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci vp_vdpa->device_features = device_features; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev); 51262306a36Sopenharmony_ci if (ret) { 51362306a36Sopenharmony_ci dev_err(&pdev->dev, 51462306a36Sopenharmony_ci "Failed for adding devres for freeing irq vectors\n"); 51562306a36Sopenharmony_ci goto err; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci vp_vdpa->vring = devm_kcalloc(&pdev->dev, vp_vdpa->queues, 51962306a36Sopenharmony_ci sizeof(*vp_vdpa->vring), 52062306a36Sopenharmony_ci GFP_KERNEL); 52162306a36Sopenharmony_ci if (!vp_vdpa->vring) { 52262306a36Sopenharmony_ci ret = -ENOMEM; 52362306a36Sopenharmony_ci dev_err(&pdev->dev, "Fail to allocate virtqueues\n"); 52462306a36Sopenharmony_ci goto err; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci for (i = 0; i < vp_vdpa->queues; i++) { 52862306a36Sopenharmony_ci vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 52962306a36Sopenharmony_ci vp_vdpa->vring[i].notify = 53062306a36Sopenharmony_ci vp_modern_map_vq_notify(mdev, i, 53162306a36Sopenharmony_ci &vp_vdpa->vring[i].notify_pa); 53262306a36Sopenharmony_ci if (!vp_vdpa->vring[i].notify) { 53362306a36Sopenharmony_ci ret = -EINVAL; 53462306a36Sopenharmony_ci dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i); 53562306a36Sopenharmony_ci goto err; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci vp_vdpa->vdpa.mdev = &vp_vdpa_mgtdev->mgtdev; 54162306a36Sopenharmony_ci ret = _vdpa_register_device(&vp_vdpa->vdpa, vp_vdpa->queues); 54262306a36Sopenharmony_ci if (ret) { 54362306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register to vdpa bus\n"); 54462306a36Sopenharmony_ci goto err; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return 0; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cierr: 55062306a36Sopenharmony_ci put_device(&vp_vdpa->vdpa.dev); 55162306a36Sopenharmony_ci return ret; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void vp_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, 55562306a36Sopenharmony_ci struct vdpa_device *dev) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = 55862306a36Sopenharmony_ci container_of(v_mdev, struct vp_vdpa_mgmtdev, mgtdev); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci struct vp_vdpa *vp_vdpa = vp_vdpa_mgtdev->vp_vdpa; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci _vdpa_unregister_device(&vp_vdpa->vdpa); 56362306a36Sopenharmony_ci vp_vdpa_mgtdev->vp_vdpa = NULL; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic const struct vdpa_mgmtdev_ops vp_vdpa_mdev_ops = { 56762306a36Sopenharmony_ci .dev_add = vp_vdpa_dev_add, 56862306a36Sopenharmony_ci .dev_del = vp_vdpa_dev_del, 56962306a36Sopenharmony_ci}; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = NULL; 57462306a36Sopenharmony_ci struct vdpa_mgmt_dev *mgtdev; 57562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 57662306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = NULL; 57762306a36Sopenharmony_ci struct virtio_device_id *mdev_id = NULL; 57862306a36Sopenharmony_ci int err; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci vp_vdpa_mgtdev = kzalloc(sizeof(*vp_vdpa_mgtdev), GFP_KERNEL); 58162306a36Sopenharmony_ci if (!vp_vdpa_mgtdev) 58262306a36Sopenharmony_ci return -ENOMEM; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci mgtdev = &vp_vdpa_mgtdev->mgtdev; 58562306a36Sopenharmony_ci mgtdev->ops = &vp_vdpa_mdev_ops; 58662306a36Sopenharmony_ci mgtdev->device = dev; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci mdev = kzalloc(sizeof(struct virtio_pci_modern_device), GFP_KERNEL); 58962306a36Sopenharmony_ci if (!mdev) { 59062306a36Sopenharmony_ci err = -ENOMEM; 59162306a36Sopenharmony_ci goto mdev_err; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci mdev_id = kzalloc(sizeof(struct virtio_device_id), GFP_KERNEL); 59562306a36Sopenharmony_ci if (!mdev_id) { 59662306a36Sopenharmony_ci err = -ENOMEM; 59762306a36Sopenharmony_ci goto mdev_id_err; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci vp_vdpa_mgtdev->mdev = mdev; 60162306a36Sopenharmony_ci mdev->pci_dev = pdev; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci err = pcim_enable_device(pdev); 60462306a36Sopenharmony_ci if (err) { 60562306a36Sopenharmony_ci goto probe_err; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci err = vp_modern_probe(mdev); 60962306a36Sopenharmony_ci if (err) { 61062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to probe modern PCI device\n"); 61162306a36Sopenharmony_ci goto probe_err; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci mdev_id->device = mdev->id.device; 61562306a36Sopenharmony_ci mdev_id->vendor = mdev->id.vendor; 61662306a36Sopenharmony_ci mgtdev->id_table = mdev_id; 61762306a36Sopenharmony_ci mgtdev->max_supported_vqs = vp_modern_get_num_queues(mdev); 61862306a36Sopenharmony_ci mgtdev->supported_features = vp_modern_get_features(mdev); 61962306a36Sopenharmony_ci mgtdev->config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES); 62062306a36Sopenharmony_ci pci_set_master(pdev); 62162306a36Sopenharmony_ci pci_set_drvdata(pdev, vp_vdpa_mgtdev); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci err = vdpa_mgmtdev_register(mgtdev); 62462306a36Sopenharmony_ci if (err) { 62562306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register vdpa mgmtdev device\n"); 62662306a36Sopenharmony_ci goto register_err; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return 0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ciregister_err: 63262306a36Sopenharmony_ci vp_modern_remove(vp_vdpa_mgtdev->mdev); 63362306a36Sopenharmony_ciprobe_err: 63462306a36Sopenharmony_ci kfree(mdev_id); 63562306a36Sopenharmony_cimdev_id_err: 63662306a36Sopenharmony_ci kfree(mdev); 63762306a36Sopenharmony_cimdev_err: 63862306a36Sopenharmony_ci kfree(vp_vdpa_mgtdev); 63962306a36Sopenharmony_ci return err; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void vp_vdpa_remove(struct pci_dev *pdev) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = pci_get_drvdata(pdev); 64562306a36Sopenharmony_ci struct virtio_pci_modern_device *mdev = NULL; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mdev = vp_vdpa_mgtdev->mdev; 64862306a36Sopenharmony_ci vdpa_mgmtdev_unregister(&vp_vdpa_mgtdev->mgtdev); 64962306a36Sopenharmony_ci vp_modern_remove(mdev); 65062306a36Sopenharmony_ci kfree(vp_vdpa_mgtdev->mgtdev.id_table); 65162306a36Sopenharmony_ci kfree(mdev); 65262306a36Sopenharmony_ci kfree(vp_vdpa_mgtdev); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic struct pci_driver vp_vdpa_driver = { 65662306a36Sopenharmony_ci .name = "vp-vdpa", 65762306a36Sopenharmony_ci .id_table = NULL, /* only dynamic ids */ 65862306a36Sopenharmony_ci .probe = vp_vdpa_probe, 65962306a36Sopenharmony_ci .remove = vp_vdpa_remove, 66062306a36Sopenharmony_ci}; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cimodule_pci_driver(vp_vdpa_driver); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ciMODULE_AUTHOR("Jason Wang <jasowang@redhat.com>"); 66562306a36Sopenharmony_ciMODULE_DESCRIPTION("vp-vdpa"); 66662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 66762306a36Sopenharmony_ciMODULE_VERSION("1"); 668