164b9f64fSJason Wang // SPDX-License-Identifier: GPL-2.0-only 264b9f64fSJason Wang /* 364b9f64fSJason Wang * vDPA bridge driver for modern virtio-pci device 464b9f64fSJason Wang * 564b9f64fSJason Wang * Copyright (c) 2020, Red Hat Inc. All rights reserved. 664b9f64fSJason Wang * Author: Jason Wang <jasowang@redhat.com> 764b9f64fSJason Wang * 864b9f64fSJason Wang * Based on virtio_pci_modern.c. 964b9f64fSJason Wang */ 1064b9f64fSJason Wang 1164b9f64fSJason Wang #include <linux/interrupt.h> 1264b9f64fSJason Wang #include <linux/module.h> 1364b9f64fSJason Wang #include <linux/pci.h> 1464b9f64fSJason Wang #include <linux/vdpa.h> 1564b9f64fSJason Wang #include <linux/virtio.h> 1664b9f64fSJason Wang #include <linux/virtio_config.h> 1764b9f64fSJason Wang #include <linux/virtio_ring.h> 1864b9f64fSJason Wang #include <linux/virtio_pci.h> 1964b9f64fSJason Wang #include <linux/virtio_pci_modern.h> 2064b9f64fSJason Wang 2164b9f64fSJason Wang #define VP_VDPA_QUEUE_MAX 256 2264b9f64fSJason Wang #define VP_VDPA_DRIVER_NAME "vp_vdpa" 2364b9f64fSJason Wang #define VP_VDPA_NAME_SIZE 256 2464b9f64fSJason Wang 2564b9f64fSJason Wang struct vp_vring { 2664b9f64fSJason Wang void __iomem *notify; 2764b9f64fSJason Wang char msix_name[VP_VDPA_NAME_SIZE]; 2864b9f64fSJason Wang struct vdpa_callback cb; 29526cb858SJason Wang resource_size_t notify_pa; 3064b9f64fSJason Wang int irq; 3164b9f64fSJason Wang }; 3264b9f64fSJason Wang 3364b9f64fSJason Wang struct vp_vdpa { 3464b9f64fSJason Wang struct vdpa_device vdpa; 3564b9f64fSJason Wang struct virtio_pci_modern_device mdev; 3664b9f64fSJason Wang struct vp_vring *vring; 3764b9f64fSJason Wang struct vdpa_callback config_cb; 3864b9f64fSJason Wang char msix_name[VP_VDPA_NAME_SIZE]; 3964b9f64fSJason Wang int config_irq; 4064b9f64fSJason Wang int queues; 4164b9f64fSJason Wang int vectors; 4264b9f64fSJason Wang }; 4364b9f64fSJason Wang 4464b9f64fSJason Wang static struct vp_vdpa *vdpa_to_vp(struct vdpa_device *vdpa) 4564b9f64fSJason Wang { 4664b9f64fSJason Wang return container_of(vdpa, struct vp_vdpa, vdpa); 4764b9f64fSJason Wang } 4864b9f64fSJason Wang 4964b9f64fSJason Wang static struct virtio_pci_modern_device *vdpa_to_mdev(struct vdpa_device *vdpa) 5064b9f64fSJason Wang { 5164b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 5264b9f64fSJason Wang 5364b9f64fSJason Wang return &vp_vdpa->mdev; 5464b9f64fSJason Wang } 5564b9f64fSJason Wang 5664b9f64fSJason Wang static u64 vp_vdpa_get_features(struct vdpa_device *vdpa) 5764b9f64fSJason Wang { 5864b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 5964b9f64fSJason Wang 6064b9f64fSJason Wang return vp_modern_get_features(mdev); 6164b9f64fSJason Wang } 6264b9f64fSJason Wang 6364b9f64fSJason Wang static int vp_vdpa_set_features(struct vdpa_device *vdpa, u64 features) 6464b9f64fSJason Wang { 6564b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 6664b9f64fSJason Wang 6764b9f64fSJason Wang vp_modern_set_features(mdev, features); 6864b9f64fSJason Wang 6964b9f64fSJason Wang return 0; 7064b9f64fSJason Wang } 7164b9f64fSJason Wang 7264b9f64fSJason Wang static u8 vp_vdpa_get_status(struct vdpa_device *vdpa) 7364b9f64fSJason Wang { 7464b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 7564b9f64fSJason Wang 7664b9f64fSJason Wang return vp_modern_get_status(mdev); 7764b9f64fSJason Wang } 7864b9f64fSJason Wang 7964b9f64fSJason Wang static void vp_vdpa_free_irq(struct vp_vdpa *vp_vdpa) 8064b9f64fSJason Wang { 8164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 8264b9f64fSJason Wang struct pci_dev *pdev = mdev->pci_dev; 8364b9f64fSJason Wang int i; 8464b9f64fSJason Wang 8564b9f64fSJason Wang for (i = 0; i < vp_vdpa->queues; i++) { 8664b9f64fSJason Wang if (vp_vdpa->vring[i].irq != VIRTIO_MSI_NO_VECTOR) { 8764b9f64fSJason Wang vp_modern_queue_vector(mdev, i, VIRTIO_MSI_NO_VECTOR); 8864b9f64fSJason Wang devm_free_irq(&pdev->dev, vp_vdpa->vring[i].irq, 8964b9f64fSJason Wang &vp_vdpa->vring[i]); 9064b9f64fSJason Wang vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 9164b9f64fSJason Wang } 9264b9f64fSJason Wang } 9364b9f64fSJason Wang 9464b9f64fSJason Wang if (vp_vdpa->config_irq != VIRTIO_MSI_NO_VECTOR) { 9564b9f64fSJason Wang vp_modern_config_vector(mdev, VIRTIO_MSI_NO_VECTOR); 9664b9f64fSJason Wang devm_free_irq(&pdev->dev, vp_vdpa->config_irq, vp_vdpa); 9764b9f64fSJason Wang vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 9864b9f64fSJason Wang } 9964b9f64fSJason Wang 10064b9f64fSJason Wang if (vp_vdpa->vectors) { 10164b9f64fSJason Wang pci_free_irq_vectors(pdev); 10264b9f64fSJason Wang vp_vdpa->vectors = 0; 10364b9f64fSJason Wang } 10464b9f64fSJason Wang } 10564b9f64fSJason Wang 10664b9f64fSJason Wang static irqreturn_t vp_vdpa_vq_handler(int irq, void *arg) 10764b9f64fSJason Wang { 10864b9f64fSJason Wang struct vp_vring *vring = arg; 10964b9f64fSJason Wang 11064b9f64fSJason Wang if (vring->cb.callback) 11164b9f64fSJason Wang return vring->cb.callback(vring->cb.private); 11264b9f64fSJason Wang 11364b9f64fSJason Wang return IRQ_HANDLED; 11464b9f64fSJason Wang } 11564b9f64fSJason Wang 11664b9f64fSJason Wang static irqreturn_t vp_vdpa_config_handler(int irq, void *arg) 11764b9f64fSJason Wang { 11864b9f64fSJason Wang struct vp_vdpa *vp_vdpa = arg; 11964b9f64fSJason Wang 12064b9f64fSJason Wang if (vp_vdpa->config_cb.callback) 12164b9f64fSJason Wang return vp_vdpa->config_cb.callback(vp_vdpa->config_cb.private); 12264b9f64fSJason Wang 12364b9f64fSJason Wang return IRQ_HANDLED; 12464b9f64fSJason Wang } 12564b9f64fSJason Wang 12664b9f64fSJason Wang static int vp_vdpa_request_irq(struct vp_vdpa *vp_vdpa) 12764b9f64fSJason Wang { 12864b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 12964b9f64fSJason Wang struct pci_dev *pdev = mdev->pci_dev; 13064b9f64fSJason Wang int i, ret, irq; 13164b9f64fSJason Wang int queues = vp_vdpa->queues; 13264b9f64fSJason Wang int vectors = queues + 1; 13364b9f64fSJason Wang 13464b9f64fSJason Wang ret = pci_alloc_irq_vectors(pdev, vectors, vectors, PCI_IRQ_MSIX); 13564b9f64fSJason Wang if (ret != vectors) { 13664b9f64fSJason Wang dev_err(&pdev->dev, 13764b9f64fSJason Wang "vp_vdpa: fail to allocate irq vectors want %d but %d\n", 13864b9f64fSJason Wang vectors, ret); 13964b9f64fSJason Wang return ret; 14064b9f64fSJason Wang } 14164b9f64fSJason Wang 14264b9f64fSJason Wang vp_vdpa->vectors = vectors; 14364b9f64fSJason Wang 14464b9f64fSJason Wang for (i = 0; i < queues; i++) { 14564b9f64fSJason Wang snprintf(vp_vdpa->vring[i].msix_name, VP_VDPA_NAME_SIZE, 14664b9f64fSJason Wang "vp-vdpa[%s]-%d\n", pci_name(pdev), i); 14764b9f64fSJason Wang irq = pci_irq_vector(pdev, i); 14864b9f64fSJason Wang ret = devm_request_irq(&pdev->dev, irq, 14964b9f64fSJason Wang vp_vdpa_vq_handler, 15064b9f64fSJason Wang 0, vp_vdpa->vring[i].msix_name, 15164b9f64fSJason Wang &vp_vdpa->vring[i]); 15264b9f64fSJason Wang if (ret) { 15364b9f64fSJason Wang dev_err(&pdev->dev, 15464b9f64fSJason Wang "vp_vdpa: fail to request irq for vq %d\n", i); 15564b9f64fSJason Wang goto err; 15664b9f64fSJason Wang } 15764b9f64fSJason Wang vp_modern_queue_vector(mdev, i, i); 15864b9f64fSJason Wang vp_vdpa->vring[i].irq = irq; 15964b9f64fSJason Wang } 16064b9f64fSJason Wang 16164b9f64fSJason Wang snprintf(vp_vdpa->msix_name, VP_VDPA_NAME_SIZE, "vp-vdpa[%s]-config\n", 16264b9f64fSJason Wang pci_name(pdev)); 16364b9f64fSJason Wang irq = pci_irq_vector(pdev, queues); 16464b9f64fSJason Wang ret = devm_request_irq(&pdev->dev, irq, vp_vdpa_config_handler, 0, 16564b9f64fSJason Wang vp_vdpa->msix_name, vp_vdpa); 16664b9f64fSJason Wang if (ret) { 16764b9f64fSJason Wang dev_err(&pdev->dev, 16864b9f64fSJason Wang "vp_vdpa: fail to request irq for vq %d\n", i); 16964b9f64fSJason Wang goto err; 17064b9f64fSJason Wang } 17164b9f64fSJason Wang vp_modern_config_vector(mdev, queues); 17264b9f64fSJason Wang vp_vdpa->config_irq = irq; 17364b9f64fSJason Wang 17464b9f64fSJason Wang return 0; 17564b9f64fSJason Wang err: 17664b9f64fSJason Wang vp_vdpa_free_irq(vp_vdpa); 17764b9f64fSJason Wang return ret; 17864b9f64fSJason Wang } 17964b9f64fSJason Wang 18064b9f64fSJason Wang static void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status) 18164b9f64fSJason Wang { 18264b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 18364b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 18464b9f64fSJason Wang u8 s = vp_vdpa_get_status(vdpa); 18564b9f64fSJason Wang 18664b9f64fSJason Wang if (status & VIRTIO_CONFIG_S_DRIVER_OK && 18764b9f64fSJason Wang !(s & VIRTIO_CONFIG_S_DRIVER_OK)) { 18864b9f64fSJason Wang vp_vdpa_request_irq(vp_vdpa); 18964b9f64fSJason Wang } 19064b9f64fSJason Wang 19164b9f64fSJason Wang vp_modern_set_status(mdev, status); 19264b9f64fSJason Wang 19364b9f64fSJason Wang if (!(status & VIRTIO_CONFIG_S_DRIVER_OK) && 19464b9f64fSJason Wang (s & VIRTIO_CONFIG_S_DRIVER_OK)) 19564b9f64fSJason Wang vp_vdpa_free_irq(vp_vdpa); 19664b9f64fSJason Wang } 19764b9f64fSJason Wang 19864b9f64fSJason Wang static u16 vp_vdpa_get_vq_num_max(struct vdpa_device *vdpa) 19964b9f64fSJason Wang { 20064b9f64fSJason Wang return VP_VDPA_QUEUE_MAX; 20164b9f64fSJason Wang } 20264b9f64fSJason Wang 20364b9f64fSJason Wang static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid, 20464b9f64fSJason Wang struct vdpa_vq_state *state) 20564b9f64fSJason Wang { 20664b9f64fSJason Wang /* Note that this is not supported by virtio specification, so 20764b9f64fSJason Wang * we return -EOPNOTSUPP here. This means we can't support live 20864b9f64fSJason Wang * migration, vhost device start/stop. 20964b9f64fSJason Wang */ 21064b9f64fSJason Wang return -EOPNOTSUPP; 21164b9f64fSJason Wang } 21264b9f64fSJason Wang 21364b9f64fSJason Wang static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid, 21464b9f64fSJason Wang const struct vdpa_vq_state *state) 21564b9f64fSJason Wang { 21664b9f64fSJason Wang /* Note that this is not supported by virtio specification, so 21764b9f64fSJason Wang * we return -ENOPOTSUPP here. This means we can't support live 21864b9f64fSJason Wang * migration, vhost device start/stop. 21964b9f64fSJason Wang */ 22064b9f64fSJason Wang return -EOPNOTSUPP; 22164b9f64fSJason Wang } 22264b9f64fSJason Wang 22364b9f64fSJason Wang static void vp_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 qid, 22464b9f64fSJason Wang struct vdpa_callback *cb) 22564b9f64fSJason Wang { 22664b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 22764b9f64fSJason Wang 22864b9f64fSJason Wang vp_vdpa->vring[qid].cb = *cb; 22964b9f64fSJason Wang } 23064b9f64fSJason Wang 23164b9f64fSJason Wang static void vp_vdpa_set_vq_ready(struct vdpa_device *vdpa, 23264b9f64fSJason Wang u16 qid, bool ready) 23364b9f64fSJason Wang { 23464b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 23564b9f64fSJason Wang 23664b9f64fSJason Wang vp_modern_set_queue_enable(mdev, qid, ready); 23764b9f64fSJason Wang } 23864b9f64fSJason Wang 23964b9f64fSJason Wang static bool vp_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 qid) 24064b9f64fSJason Wang { 24164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 24264b9f64fSJason Wang 24364b9f64fSJason Wang return vp_modern_get_queue_enable(mdev, qid); 24464b9f64fSJason Wang } 24564b9f64fSJason Wang 24664b9f64fSJason Wang static void vp_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 qid, 24764b9f64fSJason Wang u32 num) 24864b9f64fSJason Wang { 24964b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 25064b9f64fSJason Wang 25164b9f64fSJason Wang vp_modern_set_queue_size(mdev, qid, num); 25264b9f64fSJason Wang } 25364b9f64fSJason Wang 25464b9f64fSJason Wang static int vp_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 qid, 25564b9f64fSJason Wang u64 desc_area, u64 driver_area, 25664b9f64fSJason Wang u64 device_area) 25764b9f64fSJason Wang { 25864b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 25964b9f64fSJason Wang 26064b9f64fSJason Wang vp_modern_queue_address(mdev, qid, desc_area, 26164b9f64fSJason Wang driver_area, device_area); 26264b9f64fSJason Wang 26364b9f64fSJason Wang return 0; 26464b9f64fSJason Wang } 26564b9f64fSJason Wang 26664b9f64fSJason Wang static void vp_vdpa_kick_vq(struct vdpa_device *vdpa, u16 qid) 26764b9f64fSJason Wang { 26864b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 26964b9f64fSJason Wang 27064b9f64fSJason Wang vp_iowrite16(qid, vp_vdpa->vring[qid].notify); 27164b9f64fSJason Wang } 27264b9f64fSJason Wang 27364b9f64fSJason Wang static u32 vp_vdpa_get_generation(struct vdpa_device *vdpa) 27464b9f64fSJason Wang { 27564b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 27664b9f64fSJason Wang 27764b9f64fSJason Wang return vp_modern_generation(mdev); 27864b9f64fSJason Wang } 27964b9f64fSJason Wang 28064b9f64fSJason Wang static u32 vp_vdpa_get_device_id(struct vdpa_device *vdpa) 28164b9f64fSJason Wang { 28264b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 28364b9f64fSJason Wang 28464b9f64fSJason Wang return mdev->id.device; 28564b9f64fSJason Wang } 28664b9f64fSJason Wang 28764b9f64fSJason Wang static u32 vp_vdpa_get_vendor_id(struct vdpa_device *vdpa) 28864b9f64fSJason Wang { 28964b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 29064b9f64fSJason Wang 29164b9f64fSJason Wang return mdev->id.vendor; 29264b9f64fSJason Wang } 29364b9f64fSJason Wang 29464b9f64fSJason Wang static u32 vp_vdpa_get_vq_align(struct vdpa_device *vdpa) 29564b9f64fSJason Wang { 29664b9f64fSJason Wang return PAGE_SIZE; 29764b9f64fSJason Wang } 29864b9f64fSJason Wang 299442706f9SStefano Garzarella static size_t vp_vdpa_get_config_size(struct vdpa_device *vdpa) 300442706f9SStefano Garzarella { 301442706f9SStefano Garzarella struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 302442706f9SStefano Garzarella 303442706f9SStefano Garzarella return mdev->device_len; 304442706f9SStefano Garzarella } 305442706f9SStefano Garzarella 30664b9f64fSJason Wang static void vp_vdpa_get_config(struct vdpa_device *vdpa, 30764b9f64fSJason Wang unsigned int offset, 30864b9f64fSJason Wang void *buf, unsigned int len) 30964b9f64fSJason Wang { 31064b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 31164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 31264b9f64fSJason Wang u8 old, new; 31364b9f64fSJason Wang u8 *p; 31464b9f64fSJason Wang int i; 31564b9f64fSJason Wang 31664b9f64fSJason Wang do { 31764b9f64fSJason Wang old = vp_ioread8(&mdev->common->config_generation); 31864b9f64fSJason Wang p = buf; 31964b9f64fSJason Wang for (i = 0; i < len; i++) 32064b9f64fSJason Wang *p++ = vp_ioread8(mdev->device + offset + i); 32164b9f64fSJason Wang 32264b9f64fSJason Wang new = vp_ioread8(&mdev->common->config_generation); 32364b9f64fSJason Wang } while (old != new); 32464b9f64fSJason Wang } 32564b9f64fSJason Wang 32664b9f64fSJason Wang static void vp_vdpa_set_config(struct vdpa_device *vdpa, 32764b9f64fSJason Wang unsigned int offset, const void *buf, 32864b9f64fSJason Wang unsigned int len) 32964b9f64fSJason Wang { 33064b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 33164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 33264b9f64fSJason Wang const u8 *p = buf; 33364b9f64fSJason Wang int i; 33464b9f64fSJason Wang 33564b9f64fSJason Wang for (i = 0; i < len; i++) 33664b9f64fSJason Wang vp_iowrite8(*p++, mdev->device + offset + i); 33764b9f64fSJason Wang } 33864b9f64fSJason Wang 33964b9f64fSJason Wang static void vp_vdpa_set_config_cb(struct vdpa_device *vdpa, 34064b9f64fSJason Wang struct vdpa_callback *cb) 34164b9f64fSJason Wang { 34264b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 34364b9f64fSJason Wang 34464b9f64fSJason Wang vp_vdpa->config_cb = *cb; 34564b9f64fSJason Wang } 34664b9f64fSJason Wang 347526cb858SJason Wang static struct vdpa_notification_area 348526cb858SJason Wang vp_vdpa_get_vq_notification(struct vdpa_device *vdpa, u16 qid) 349526cb858SJason Wang { 350526cb858SJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 351526cb858SJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 352526cb858SJason Wang struct vdpa_notification_area notify; 353526cb858SJason Wang 354526cb858SJason Wang notify.addr = vp_vdpa->vring[qid].notify_pa; 355526cb858SJason Wang notify.size = mdev->notify_offset_multiplier; 356526cb858SJason Wang 357526cb858SJason Wang return notify; 358526cb858SJason Wang } 359526cb858SJason Wang 36064b9f64fSJason Wang static const struct vdpa_config_ops vp_vdpa_ops = { 36164b9f64fSJason Wang .get_features = vp_vdpa_get_features, 36264b9f64fSJason Wang .set_features = vp_vdpa_set_features, 36364b9f64fSJason Wang .get_status = vp_vdpa_get_status, 36464b9f64fSJason Wang .set_status = vp_vdpa_set_status, 36564b9f64fSJason Wang .get_vq_num_max = vp_vdpa_get_vq_num_max, 36664b9f64fSJason Wang .get_vq_state = vp_vdpa_get_vq_state, 367526cb858SJason Wang .get_vq_notification = vp_vdpa_get_vq_notification, 36864b9f64fSJason Wang .set_vq_state = vp_vdpa_set_vq_state, 36964b9f64fSJason Wang .set_vq_cb = vp_vdpa_set_vq_cb, 37064b9f64fSJason Wang .set_vq_ready = vp_vdpa_set_vq_ready, 37164b9f64fSJason Wang .get_vq_ready = vp_vdpa_get_vq_ready, 37264b9f64fSJason Wang .set_vq_num = vp_vdpa_set_vq_num, 37364b9f64fSJason Wang .set_vq_address = vp_vdpa_set_vq_address, 37464b9f64fSJason Wang .kick_vq = vp_vdpa_kick_vq, 37564b9f64fSJason Wang .get_generation = vp_vdpa_get_generation, 37664b9f64fSJason Wang .get_device_id = vp_vdpa_get_device_id, 37764b9f64fSJason Wang .get_vendor_id = vp_vdpa_get_vendor_id, 37864b9f64fSJason Wang .get_vq_align = vp_vdpa_get_vq_align, 379442706f9SStefano Garzarella .get_config_size = vp_vdpa_get_config_size, 38064b9f64fSJason Wang .get_config = vp_vdpa_get_config, 38164b9f64fSJason Wang .set_config = vp_vdpa_set_config, 38264b9f64fSJason Wang .set_config_cb = vp_vdpa_set_config_cb, 38364b9f64fSJason Wang }; 38464b9f64fSJason Wang 38564b9f64fSJason Wang static void vp_vdpa_free_irq_vectors(void *data) 38664b9f64fSJason Wang { 38764b9f64fSJason Wang pci_free_irq_vectors(data); 38864b9f64fSJason Wang } 38964b9f64fSJason Wang 39064b9f64fSJason Wang static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) 39164b9f64fSJason Wang { 39264b9f64fSJason Wang struct virtio_pci_modern_device *mdev; 39364b9f64fSJason Wang struct device *dev = &pdev->dev; 39464b9f64fSJason Wang struct vp_vdpa *vp_vdpa; 39564b9f64fSJason Wang int ret, i; 39664b9f64fSJason Wang 39764b9f64fSJason Wang ret = pcim_enable_device(pdev); 39864b9f64fSJason Wang if (ret) 39964b9f64fSJason Wang return ret; 40064b9f64fSJason Wang 40164b9f64fSJason Wang vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa, 40264b9f64fSJason Wang dev, &vp_vdpa_ops, NULL); 40364b9f64fSJason Wang if (vp_vdpa == NULL) { 40464b9f64fSJason Wang dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n"); 40564b9f64fSJason Wang return -ENOMEM; 40664b9f64fSJason Wang } 40764b9f64fSJason Wang 40864b9f64fSJason Wang mdev = &vp_vdpa->mdev; 40964b9f64fSJason Wang mdev->pci_dev = pdev; 41064b9f64fSJason Wang 41164b9f64fSJason Wang ret = vp_modern_probe(mdev); 41264b9f64fSJason Wang if (ret) { 41364b9f64fSJason Wang dev_err(&pdev->dev, "Failed to probe modern PCI device\n"); 41464b9f64fSJason Wang goto err; 41564b9f64fSJason Wang } 41664b9f64fSJason Wang 41764b9f64fSJason Wang pci_set_master(pdev); 41864b9f64fSJason Wang pci_set_drvdata(pdev, vp_vdpa); 41964b9f64fSJason Wang 42064b9f64fSJason Wang vp_vdpa->vdpa.dma_dev = &pdev->dev; 42164b9f64fSJason Wang vp_vdpa->queues = vp_modern_get_num_queues(mdev); 42264b9f64fSJason Wang 42364b9f64fSJason Wang ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev); 42464b9f64fSJason Wang if (ret) { 42564b9f64fSJason Wang dev_err(&pdev->dev, 42664b9f64fSJason Wang "Failed for adding devres for freeing irq vectors\n"); 42764b9f64fSJason Wang goto err; 42864b9f64fSJason Wang } 42964b9f64fSJason Wang 43064b9f64fSJason Wang vp_vdpa->vring = devm_kcalloc(&pdev->dev, vp_vdpa->queues, 43164b9f64fSJason Wang sizeof(*vp_vdpa->vring), 43264b9f64fSJason Wang GFP_KERNEL); 43364b9f64fSJason Wang if (!vp_vdpa->vring) { 43464b9f64fSJason Wang ret = -ENOMEM; 43564b9f64fSJason Wang dev_err(&pdev->dev, "Fail to allocate virtqueues\n"); 43664b9f64fSJason Wang goto err; 43764b9f64fSJason Wang } 43864b9f64fSJason Wang 43964b9f64fSJason Wang for (i = 0; i < vp_vdpa->queues; i++) { 44064b9f64fSJason Wang vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 4419e311bcaSJason Wang vp_vdpa->vring[i].notify = 442526cb858SJason Wang vp_modern_map_vq_notify(mdev, i, 443526cb858SJason Wang &vp_vdpa->vring[i].notify_pa); 44411d8ffedSJason Wang if (!vp_vdpa->vring[i].notify) { 445*94e48d6aSJason Wang ret = -EINVAL; 44611d8ffedSJason Wang dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i); 44711d8ffedSJason Wang goto err; 44811d8ffedSJason Wang } 44964b9f64fSJason Wang } 45064b9f64fSJason Wang vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 45164b9f64fSJason Wang 45264b9f64fSJason Wang ret = vdpa_register_device(&vp_vdpa->vdpa, vp_vdpa->queues); 45364b9f64fSJason Wang if (ret) { 45464b9f64fSJason Wang dev_err(&pdev->dev, "Failed to register to vdpa bus\n"); 45564b9f64fSJason Wang goto err; 45664b9f64fSJason Wang } 45764b9f64fSJason Wang 45864b9f64fSJason Wang return 0; 45964b9f64fSJason Wang 46064b9f64fSJason Wang err: 46164b9f64fSJason Wang put_device(&vp_vdpa->vdpa.dev); 46264b9f64fSJason Wang return ret; 46364b9f64fSJason Wang } 46464b9f64fSJason Wang 46564b9f64fSJason Wang static void vp_vdpa_remove(struct pci_dev *pdev) 46664b9f64fSJason Wang { 46764b9f64fSJason Wang struct vp_vdpa *vp_vdpa = pci_get_drvdata(pdev); 46864b9f64fSJason Wang 46964b9f64fSJason Wang vdpa_unregister_device(&vp_vdpa->vdpa); 47064b9f64fSJason Wang vp_modern_remove(&vp_vdpa->mdev); 47164b9f64fSJason Wang } 47264b9f64fSJason Wang 47364b9f64fSJason Wang static struct pci_driver vp_vdpa_driver = { 47464b9f64fSJason Wang .name = "vp-vdpa", 47564b9f64fSJason Wang .id_table = NULL, /* only dynamic ids */ 47664b9f64fSJason Wang .probe = vp_vdpa_probe, 47764b9f64fSJason Wang .remove = vp_vdpa_remove, 47864b9f64fSJason Wang }; 47964b9f64fSJason Wang 48064b9f64fSJason Wang module_pci_driver(vp_vdpa_driver); 48164b9f64fSJason Wang 48264b9f64fSJason Wang MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>"); 48364b9f64fSJason Wang MODULE_DESCRIPTION("vp-vdpa"); 48464b9f64fSJason Wang MODULE_LICENSE("GPL"); 48564b9f64fSJason Wang MODULE_VERSION("1"); 486