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 56*a64917bcSEli Cohen static u64 vp_vdpa_get_device_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 63*a64917bcSEli Cohen static int vp_vdpa_set_driver_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 72*a64917bcSEli Cohen static u64 vp_vdpa_get_driver_features(struct vdpa_device *vdpa) 73*a64917bcSEli Cohen { 74*a64917bcSEli Cohen struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 75*a64917bcSEli Cohen 76*a64917bcSEli Cohen return vp_modern_get_driver_features(mdev); 77*a64917bcSEli Cohen } 78*a64917bcSEli Cohen 7964b9f64fSJason Wang static u8 vp_vdpa_get_status(struct vdpa_device *vdpa) 8064b9f64fSJason Wang { 8164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 8264b9f64fSJason Wang 8364b9f64fSJason Wang return vp_modern_get_status(mdev); 8464b9f64fSJason Wang } 8564b9f64fSJason Wang 865bbfea1eSWu Zongyong static int vp_vdpa_get_vq_irq(struct vdpa_device *vdpa, u16 idx) 875bbfea1eSWu Zongyong { 885bbfea1eSWu Zongyong struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 895bbfea1eSWu Zongyong int irq = vp_vdpa->vring[idx].irq; 905bbfea1eSWu Zongyong 915bbfea1eSWu Zongyong if (irq == VIRTIO_MSI_NO_VECTOR) 925bbfea1eSWu Zongyong return -EINVAL; 935bbfea1eSWu Zongyong 945bbfea1eSWu Zongyong return irq; 955bbfea1eSWu Zongyong } 965bbfea1eSWu Zongyong 9764b9f64fSJason Wang static void vp_vdpa_free_irq(struct vp_vdpa *vp_vdpa) 9864b9f64fSJason Wang { 9964b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 10064b9f64fSJason Wang struct pci_dev *pdev = mdev->pci_dev; 10164b9f64fSJason Wang int i; 10264b9f64fSJason Wang 10364b9f64fSJason Wang for (i = 0; i < vp_vdpa->queues; i++) { 10464b9f64fSJason Wang if (vp_vdpa->vring[i].irq != VIRTIO_MSI_NO_VECTOR) { 10564b9f64fSJason Wang vp_modern_queue_vector(mdev, i, VIRTIO_MSI_NO_VECTOR); 10664b9f64fSJason Wang devm_free_irq(&pdev->dev, vp_vdpa->vring[i].irq, 10764b9f64fSJason Wang &vp_vdpa->vring[i]); 10864b9f64fSJason Wang vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 10964b9f64fSJason Wang } 11064b9f64fSJason Wang } 11164b9f64fSJason Wang 11264b9f64fSJason Wang if (vp_vdpa->config_irq != VIRTIO_MSI_NO_VECTOR) { 11364b9f64fSJason Wang vp_modern_config_vector(mdev, VIRTIO_MSI_NO_VECTOR); 11464b9f64fSJason Wang devm_free_irq(&pdev->dev, vp_vdpa->config_irq, vp_vdpa); 11564b9f64fSJason Wang vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 11664b9f64fSJason Wang } 11764b9f64fSJason Wang 11864b9f64fSJason Wang if (vp_vdpa->vectors) { 11964b9f64fSJason Wang pci_free_irq_vectors(pdev); 12064b9f64fSJason Wang vp_vdpa->vectors = 0; 12164b9f64fSJason Wang } 12264b9f64fSJason Wang } 12364b9f64fSJason Wang 12464b9f64fSJason Wang static irqreturn_t vp_vdpa_vq_handler(int irq, void *arg) 12564b9f64fSJason Wang { 12664b9f64fSJason Wang struct vp_vring *vring = arg; 12764b9f64fSJason Wang 12864b9f64fSJason Wang if (vring->cb.callback) 12964b9f64fSJason Wang return vring->cb.callback(vring->cb.private); 13064b9f64fSJason Wang 13164b9f64fSJason Wang return IRQ_HANDLED; 13264b9f64fSJason Wang } 13364b9f64fSJason Wang 13464b9f64fSJason Wang static irqreturn_t vp_vdpa_config_handler(int irq, void *arg) 13564b9f64fSJason Wang { 13664b9f64fSJason Wang struct vp_vdpa *vp_vdpa = arg; 13764b9f64fSJason Wang 13864b9f64fSJason Wang if (vp_vdpa->config_cb.callback) 13964b9f64fSJason Wang return vp_vdpa->config_cb.callback(vp_vdpa->config_cb.private); 14064b9f64fSJason Wang 14164b9f64fSJason Wang return IRQ_HANDLED; 14264b9f64fSJason Wang } 14364b9f64fSJason Wang 14464b9f64fSJason Wang static int vp_vdpa_request_irq(struct vp_vdpa *vp_vdpa) 14564b9f64fSJason Wang { 14664b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 14764b9f64fSJason Wang struct pci_dev *pdev = mdev->pci_dev; 14864b9f64fSJason Wang int i, ret, irq; 14964b9f64fSJason Wang int queues = vp_vdpa->queues; 15064b9f64fSJason Wang int vectors = queues + 1; 15164b9f64fSJason Wang 15264b9f64fSJason Wang ret = pci_alloc_irq_vectors(pdev, vectors, vectors, PCI_IRQ_MSIX); 15364b9f64fSJason Wang if (ret != vectors) { 15464b9f64fSJason Wang dev_err(&pdev->dev, 15564b9f64fSJason Wang "vp_vdpa: fail to allocate irq vectors want %d but %d\n", 15664b9f64fSJason Wang vectors, ret); 15764b9f64fSJason Wang return ret; 15864b9f64fSJason Wang } 15964b9f64fSJason Wang 16064b9f64fSJason Wang vp_vdpa->vectors = vectors; 16164b9f64fSJason Wang 16264b9f64fSJason Wang for (i = 0; i < queues; i++) { 16364b9f64fSJason Wang snprintf(vp_vdpa->vring[i].msix_name, VP_VDPA_NAME_SIZE, 16464b9f64fSJason Wang "vp-vdpa[%s]-%d\n", pci_name(pdev), i); 16564b9f64fSJason Wang irq = pci_irq_vector(pdev, i); 16664b9f64fSJason Wang ret = devm_request_irq(&pdev->dev, irq, 16764b9f64fSJason Wang vp_vdpa_vq_handler, 16864b9f64fSJason Wang 0, vp_vdpa->vring[i].msix_name, 16964b9f64fSJason Wang &vp_vdpa->vring[i]); 17064b9f64fSJason Wang if (ret) { 17164b9f64fSJason Wang dev_err(&pdev->dev, 17264b9f64fSJason Wang "vp_vdpa: fail to request irq for vq %d\n", i); 17364b9f64fSJason Wang goto err; 17464b9f64fSJason Wang } 17564b9f64fSJason Wang vp_modern_queue_vector(mdev, i, i); 17664b9f64fSJason Wang vp_vdpa->vring[i].irq = irq; 17764b9f64fSJason Wang } 17864b9f64fSJason Wang 17964b9f64fSJason Wang snprintf(vp_vdpa->msix_name, VP_VDPA_NAME_SIZE, "vp-vdpa[%s]-config\n", 18064b9f64fSJason Wang pci_name(pdev)); 18164b9f64fSJason Wang irq = pci_irq_vector(pdev, queues); 18264b9f64fSJason Wang ret = devm_request_irq(&pdev->dev, irq, vp_vdpa_config_handler, 0, 18364b9f64fSJason Wang vp_vdpa->msix_name, vp_vdpa); 18464b9f64fSJason Wang if (ret) { 18564b9f64fSJason Wang dev_err(&pdev->dev, 18664b9f64fSJason Wang "vp_vdpa: fail to request irq for vq %d\n", i); 18764b9f64fSJason Wang goto err; 18864b9f64fSJason Wang } 18964b9f64fSJason Wang vp_modern_config_vector(mdev, queues); 19064b9f64fSJason Wang vp_vdpa->config_irq = irq; 19164b9f64fSJason Wang 19264b9f64fSJason Wang return 0; 19364b9f64fSJason Wang err: 19464b9f64fSJason Wang vp_vdpa_free_irq(vp_vdpa); 19564b9f64fSJason Wang return ret; 19664b9f64fSJason Wang } 19764b9f64fSJason Wang 19864b9f64fSJason Wang static void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status) 19964b9f64fSJason Wang { 20064b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 20164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 20264b9f64fSJason Wang u8 s = vp_vdpa_get_status(vdpa); 20364b9f64fSJason Wang 20464b9f64fSJason Wang if (status & VIRTIO_CONFIG_S_DRIVER_OK && 20564b9f64fSJason Wang !(s & VIRTIO_CONFIG_S_DRIVER_OK)) { 20664b9f64fSJason Wang vp_vdpa_request_irq(vp_vdpa); 20764b9f64fSJason Wang } 20864b9f64fSJason Wang 20964b9f64fSJason Wang vp_modern_set_status(mdev, status); 2100686082dSXie Yongji } 21164b9f64fSJason Wang 2120686082dSXie Yongji static int vp_vdpa_reset(struct vdpa_device *vdpa) 2130686082dSXie Yongji { 2140686082dSXie Yongji struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 2150686082dSXie Yongji struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 2160686082dSXie Yongji u8 s = vp_vdpa_get_status(vdpa); 2170686082dSXie Yongji 2180686082dSXie Yongji vp_modern_set_status(mdev, 0); 2190686082dSXie Yongji 2200686082dSXie Yongji if (s & VIRTIO_CONFIG_S_DRIVER_OK) 22164b9f64fSJason Wang vp_vdpa_free_irq(vp_vdpa); 2220686082dSXie Yongji 2230686082dSXie Yongji return 0; 22464b9f64fSJason Wang } 22564b9f64fSJason Wang 22664b9f64fSJason Wang static u16 vp_vdpa_get_vq_num_max(struct vdpa_device *vdpa) 22764b9f64fSJason Wang { 22864b9f64fSJason Wang return VP_VDPA_QUEUE_MAX; 22964b9f64fSJason Wang } 23064b9f64fSJason Wang 23164b9f64fSJason Wang static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid, 23264b9f64fSJason Wang struct vdpa_vq_state *state) 23364b9f64fSJason Wang { 23464b9f64fSJason Wang /* Note that this is not supported by virtio specification, so 23564b9f64fSJason Wang * we return -EOPNOTSUPP here. This means we can't support live 23664b9f64fSJason Wang * migration, vhost device start/stop. 23764b9f64fSJason Wang */ 23864b9f64fSJason Wang return -EOPNOTSUPP; 23964b9f64fSJason Wang } 24064b9f64fSJason Wang 2411225c216SJason Wang static int vp_vdpa_set_vq_state_split(struct vdpa_device *vdpa, 2421225c216SJason Wang const struct vdpa_vq_state *state) 2431225c216SJason Wang { 2441225c216SJason Wang const struct vdpa_vq_state_split *split = &state->split; 2451225c216SJason Wang 2461225c216SJason Wang if (split->avail_index == 0) 2471225c216SJason Wang return 0; 2481225c216SJason Wang 2491225c216SJason Wang return -EOPNOTSUPP; 2501225c216SJason Wang } 2511225c216SJason Wang 2521225c216SJason Wang static int vp_vdpa_set_vq_state_packed(struct vdpa_device *vdpa, 2531225c216SJason Wang const struct vdpa_vq_state *state) 2541225c216SJason Wang { 2551225c216SJason Wang const struct vdpa_vq_state_packed *packed = &state->packed; 2561225c216SJason Wang 2571225c216SJason Wang if (packed->last_avail_counter == 1 && 2581225c216SJason Wang packed->last_avail_idx == 0 && 2591225c216SJason Wang packed->last_used_counter == 1 && 2601225c216SJason Wang packed->last_used_idx == 0) 2611225c216SJason Wang return 0; 2621225c216SJason Wang 2631225c216SJason Wang return -EOPNOTSUPP; 2641225c216SJason Wang } 2651225c216SJason Wang 26664b9f64fSJason Wang static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid, 26764b9f64fSJason Wang const struct vdpa_vq_state *state) 26864b9f64fSJason Wang { 2691225c216SJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 2701225c216SJason Wang 2711225c216SJason Wang /* Note that this is not supported by virtio specification. 2721225c216SJason Wang * But if the state is by chance equal to the device initial 2731225c216SJason Wang * state, we can let it go. 27464b9f64fSJason Wang */ 2751225c216SJason Wang if ((vp_modern_get_status(mdev) & VIRTIO_CONFIG_S_FEATURES_OK) && 2761225c216SJason Wang !vp_modern_get_queue_enable(mdev, qid)) { 2771225c216SJason Wang if (vp_modern_get_driver_features(mdev) & 2781225c216SJason Wang BIT_ULL(VIRTIO_F_RING_PACKED)) 2791225c216SJason Wang return vp_vdpa_set_vq_state_packed(vdpa, state); 2801225c216SJason Wang else 2811225c216SJason Wang return vp_vdpa_set_vq_state_split(vdpa, state); 2821225c216SJason Wang } 2831225c216SJason Wang 28464b9f64fSJason Wang return -EOPNOTSUPP; 28564b9f64fSJason Wang } 28664b9f64fSJason Wang 28764b9f64fSJason Wang static void vp_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 qid, 28864b9f64fSJason Wang struct vdpa_callback *cb) 28964b9f64fSJason Wang { 29064b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 29164b9f64fSJason Wang 29264b9f64fSJason Wang vp_vdpa->vring[qid].cb = *cb; 29364b9f64fSJason Wang } 29464b9f64fSJason Wang 29564b9f64fSJason Wang static void vp_vdpa_set_vq_ready(struct vdpa_device *vdpa, 29664b9f64fSJason Wang u16 qid, bool ready) 29764b9f64fSJason Wang { 29864b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 29964b9f64fSJason Wang 30064b9f64fSJason Wang vp_modern_set_queue_enable(mdev, qid, ready); 30164b9f64fSJason Wang } 30264b9f64fSJason Wang 30364b9f64fSJason Wang static bool vp_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 qid) 30464b9f64fSJason Wang { 30564b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 30664b9f64fSJason Wang 30764b9f64fSJason Wang return vp_modern_get_queue_enable(mdev, qid); 30864b9f64fSJason Wang } 30964b9f64fSJason Wang 31064b9f64fSJason Wang static void vp_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 qid, 31164b9f64fSJason Wang u32 num) 31264b9f64fSJason Wang { 31364b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 31464b9f64fSJason Wang 31564b9f64fSJason Wang vp_modern_set_queue_size(mdev, qid, num); 31664b9f64fSJason Wang } 31764b9f64fSJason Wang 31864b9f64fSJason Wang static int vp_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 qid, 31964b9f64fSJason Wang u64 desc_area, u64 driver_area, 32064b9f64fSJason Wang u64 device_area) 32164b9f64fSJason Wang { 32264b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 32364b9f64fSJason Wang 32464b9f64fSJason Wang vp_modern_queue_address(mdev, qid, desc_area, 32564b9f64fSJason Wang driver_area, device_area); 32664b9f64fSJason Wang 32764b9f64fSJason Wang return 0; 32864b9f64fSJason Wang } 32964b9f64fSJason Wang 33064b9f64fSJason Wang static void vp_vdpa_kick_vq(struct vdpa_device *vdpa, u16 qid) 33164b9f64fSJason Wang { 33264b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 33364b9f64fSJason Wang 33464b9f64fSJason Wang vp_iowrite16(qid, vp_vdpa->vring[qid].notify); 33564b9f64fSJason Wang } 33664b9f64fSJason Wang 33764b9f64fSJason Wang static u32 vp_vdpa_get_generation(struct vdpa_device *vdpa) 33864b9f64fSJason Wang { 33964b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 34064b9f64fSJason Wang 34164b9f64fSJason Wang return vp_modern_generation(mdev); 34264b9f64fSJason Wang } 34364b9f64fSJason Wang 34464b9f64fSJason Wang static u32 vp_vdpa_get_device_id(struct vdpa_device *vdpa) 34564b9f64fSJason Wang { 34664b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 34764b9f64fSJason Wang 34864b9f64fSJason Wang return mdev->id.device; 34964b9f64fSJason Wang } 35064b9f64fSJason Wang 35164b9f64fSJason Wang static u32 vp_vdpa_get_vendor_id(struct vdpa_device *vdpa) 35264b9f64fSJason Wang { 35364b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 35464b9f64fSJason Wang 35564b9f64fSJason Wang return mdev->id.vendor; 35664b9f64fSJason Wang } 35764b9f64fSJason Wang 35864b9f64fSJason Wang static u32 vp_vdpa_get_vq_align(struct vdpa_device *vdpa) 35964b9f64fSJason Wang { 36064b9f64fSJason Wang return PAGE_SIZE; 36164b9f64fSJason Wang } 36264b9f64fSJason Wang 363442706f9SStefano Garzarella static size_t vp_vdpa_get_config_size(struct vdpa_device *vdpa) 364442706f9SStefano Garzarella { 365442706f9SStefano Garzarella struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 366442706f9SStefano Garzarella 367442706f9SStefano Garzarella return mdev->device_len; 368442706f9SStefano Garzarella } 369442706f9SStefano Garzarella 37064b9f64fSJason Wang static void vp_vdpa_get_config(struct vdpa_device *vdpa, 37164b9f64fSJason Wang unsigned int offset, 37264b9f64fSJason Wang void *buf, unsigned int len) 37364b9f64fSJason Wang { 37464b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 37564b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 37664b9f64fSJason Wang u8 old, new; 37764b9f64fSJason Wang u8 *p; 37864b9f64fSJason Wang int i; 37964b9f64fSJason Wang 38064b9f64fSJason Wang do { 38164b9f64fSJason Wang old = vp_ioread8(&mdev->common->config_generation); 38264b9f64fSJason Wang p = buf; 38364b9f64fSJason Wang for (i = 0; i < len; i++) 38464b9f64fSJason Wang *p++ = vp_ioread8(mdev->device + offset + i); 38564b9f64fSJason Wang 38664b9f64fSJason Wang new = vp_ioread8(&mdev->common->config_generation); 38764b9f64fSJason Wang } while (old != new); 38864b9f64fSJason Wang } 38964b9f64fSJason Wang 39064b9f64fSJason Wang static void vp_vdpa_set_config(struct vdpa_device *vdpa, 39164b9f64fSJason Wang unsigned int offset, const void *buf, 39264b9f64fSJason Wang unsigned int len) 39364b9f64fSJason Wang { 39464b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 39564b9f64fSJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 39664b9f64fSJason Wang const u8 *p = buf; 39764b9f64fSJason Wang int i; 39864b9f64fSJason Wang 39964b9f64fSJason Wang for (i = 0; i < len; i++) 40064b9f64fSJason Wang vp_iowrite8(*p++, mdev->device + offset + i); 40164b9f64fSJason Wang } 40264b9f64fSJason Wang 40364b9f64fSJason Wang static void vp_vdpa_set_config_cb(struct vdpa_device *vdpa, 40464b9f64fSJason Wang struct vdpa_callback *cb) 40564b9f64fSJason Wang { 40664b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 40764b9f64fSJason Wang 40864b9f64fSJason Wang vp_vdpa->config_cb = *cb; 40964b9f64fSJason Wang } 41064b9f64fSJason Wang 411526cb858SJason Wang static struct vdpa_notification_area 412526cb858SJason Wang vp_vdpa_get_vq_notification(struct vdpa_device *vdpa, u16 qid) 413526cb858SJason Wang { 414526cb858SJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 415526cb858SJason Wang struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev; 416526cb858SJason Wang struct vdpa_notification_area notify; 417526cb858SJason Wang 418526cb858SJason Wang notify.addr = vp_vdpa->vring[qid].notify_pa; 419526cb858SJason Wang notify.size = mdev->notify_offset_multiplier; 420526cb858SJason Wang 421526cb858SJason Wang return notify; 422526cb858SJason Wang } 423526cb858SJason Wang 42464b9f64fSJason Wang static const struct vdpa_config_ops vp_vdpa_ops = { 425*a64917bcSEli Cohen .get_device_features = vp_vdpa_get_device_features, 426*a64917bcSEli Cohen .set_driver_features = vp_vdpa_set_driver_features, 427*a64917bcSEli Cohen .get_driver_features = vp_vdpa_get_driver_features, 42864b9f64fSJason Wang .get_status = vp_vdpa_get_status, 42964b9f64fSJason Wang .set_status = vp_vdpa_set_status, 4300686082dSXie Yongji .reset = vp_vdpa_reset, 43164b9f64fSJason Wang .get_vq_num_max = vp_vdpa_get_vq_num_max, 43264b9f64fSJason Wang .get_vq_state = vp_vdpa_get_vq_state, 433526cb858SJason Wang .get_vq_notification = vp_vdpa_get_vq_notification, 43464b9f64fSJason Wang .set_vq_state = vp_vdpa_set_vq_state, 43564b9f64fSJason Wang .set_vq_cb = vp_vdpa_set_vq_cb, 43664b9f64fSJason Wang .set_vq_ready = vp_vdpa_set_vq_ready, 43764b9f64fSJason Wang .get_vq_ready = vp_vdpa_get_vq_ready, 43864b9f64fSJason Wang .set_vq_num = vp_vdpa_set_vq_num, 43964b9f64fSJason Wang .set_vq_address = vp_vdpa_set_vq_address, 44064b9f64fSJason Wang .kick_vq = vp_vdpa_kick_vq, 44164b9f64fSJason Wang .get_generation = vp_vdpa_get_generation, 44264b9f64fSJason Wang .get_device_id = vp_vdpa_get_device_id, 44364b9f64fSJason Wang .get_vendor_id = vp_vdpa_get_vendor_id, 44464b9f64fSJason Wang .get_vq_align = vp_vdpa_get_vq_align, 445442706f9SStefano Garzarella .get_config_size = vp_vdpa_get_config_size, 44664b9f64fSJason Wang .get_config = vp_vdpa_get_config, 44764b9f64fSJason Wang .set_config = vp_vdpa_set_config, 44864b9f64fSJason Wang .set_config_cb = vp_vdpa_set_config_cb, 4495bbfea1eSWu Zongyong .get_vq_irq = vp_vdpa_get_vq_irq, 45064b9f64fSJason Wang }; 45164b9f64fSJason Wang 45264b9f64fSJason Wang static void vp_vdpa_free_irq_vectors(void *data) 45364b9f64fSJason Wang { 45464b9f64fSJason Wang pci_free_irq_vectors(data); 45564b9f64fSJason Wang } 45664b9f64fSJason Wang 45764b9f64fSJason Wang static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) 45864b9f64fSJason Wang { 45964b9f64fSJason Wang struct virtio_pci_modern_device *mdev; 46064b9f64fSJason Wang struct device *dev = &pdev->dev; 46164b9f64fSJason Wang struct vp_vdpa *vp_vdpa; 46264b9f64fSJason Wang int ret, i; 46364b9f64fSJason Wang 46464b9f64fSJason Wang ret = pcim_enable_device(pdev); 46564b9f64fSJason Wang if (ret) 46664b9f64fSJason Wang return ret; 46764b9f64fSJason Wang 46864b9f64fSJason Wang vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa, 469d8945ec4SXie Yongji dev, &vp_vdpa_ops, NULL, false); 4709632e78eSXie Yongji if (IS_ERR(vp_vdpa)) { 47164b9f64fSJason Wang dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n"); 4729632e78eSXie Yongji return PTR_ERR(vp_vdpa); 47364b9f64fSJason Wang } 47464b9f64fSJason Wang 47564b9f64fSJason Wang mdev = &vp_vdpa->mdev; 47664b9f64fSJason Wang mdev->pci_dev = pdev; 47764b9f64fSJason Wang 47864b9f64fSJason Wang ret = vp_modern_probe(mdev); 47964b9f64fSJason Wang if (ret) { 48064b9f64fSJason Wang dev_err(&pdev->dev, "Failed to probe modern PCI device\n"); 48164b9f64fSJason Wang goto err; 48264b9f64fSJason Wang } 48364b9f64fSJason Wang 48464b9f64fSJason Wang pci_set_master(pdev); 48564b9f64fSJason Wang pci_set_drvdata(pdev, vp_vdpa); 48664b9f64fSJason Wang 48764b9f64fSJason Wang vp_vdpa->vdpa.dma_dev = &pdev->dev; 48864b9f64fSJason Wang vp_vdpa->queues = vp_modern_get_num_queues(mdev); 48964b9f64fSJason Wang 49064b9f64fSJason Wang ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev); 49164b9f64fSJason Wang if (ret) { 49264b9f64fSJason Wang dev_err(&pdev->dev, 49364b9f64fSJason Wang "Failed for adding devres for freeing irq vectors\n"); 49464b9f64fSJason Wang goto err; 49564b9f64fSJason Wang } 49664b9f64fSJason Wang 49764b9f64fSJason Wang vp_vdpa->vring = devm_kcalloc(&pdev->dev, vp_vdpa->queues, 49864b9f64fSJason Wang sizeof(*vp_vdpa->vring), 49964b9f64fSJason Wang GFP_KERNEL); 50064b9f64fSJason Wang if (!vp_vdpa->vring) { 50164b9f64fSJason Wang ret = -ENOMEM; 50264b9f64fSJason Wang dev_err(&pdev->dev, "Fail to allocate virtqueues\n"); 50364b9f64fSJason Wang goto err; 50464b9f64fSJason Wang } 50564b9f64fSJason Wang 50664b9f64fSJason Wang for (i = 0; i < vp_vdpa->queues; i++) { 50764b9f64fSJason Wang vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 5089e311bcaSJason Wang vp_vdpa->vring[i].notify = 509526cb858SJason Wang vp_modern_map_vq_notify(mdev, i, 510526cb858SJason Wang &vp_vdpa->vring[i].notify_pa); 51111d8ffedSJason Wang if (!vp_vdpa->vring[i].notify) { 51294e48d6aSJason Wang ret = -EINVAL; 51311d8ffedSJason Wang dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i); 51411d8ffedSJason Wang goto err; 51511d8ffedSJason Wang } 51664b9f64fSJason Wang } 51764b9f64fSJason Wang vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 51864b9f64fSJason Wang 51964b9f64fSJason Wang ret = vdpa_register_device(&vp_vdpa->vdpa, vp_vdpa->queues); 52064b9f64fSJason Wang if (ret) { 52164b9f64fSJason Wang dev_err(&pdev->dev, "Failed to register to vdpa bus\n"); 52264b9f64fSJason Wang goto err; 52364b9f64fSJason Wang } 52464b9f64fSJason Wang 52564b9f64fSJason Wang return 0; 52664b9f64fSJason Wang 52764b9f64fSJason Wang err: 52864b9f64fSJason Wang put_device(&vp_vdpa->vdpa.dev); 52964b9f64fSJason Wang return ret; 53064b9f64fSJason Wang } 53164b9f64fSJason Wang 53264b9f64fSJason Wang static void vp_vdpa_remove(struct pci_dev *pdev) 53364b9f64fSJason Wang { 53464b9f64fSJason Wang struct vp_vdpa *vp_vdpa = pci_get_drvdata(pdev); 53564b9f64fSJason Wang 53664b9f64fSJason Wang vdpa_unregister_device(&vp_vdpa->vdpa); 53764b9f64fSJason Wang vp_modern_remove(&vp_vdpa->mdev); 53864b9f64fSJason Wang } 53964b9f64fSJason Wang 54064b9f64fSJason Wang static struct pci_driver vp_vdpa_driver = { 54164b9f64fSJason Wang .name = "vp-vdpa", 54264b9f64fSJason Wang .id_table = NULL, /* only dynamic ids */ 54364b9f64fSJason Wang .probe = vp_vdpa_probe, 54464b9f64fSJason Wang .remove = vp_vdpa_remove, 54564b9f64fSJason Wang }; 54664b9f64fSJason Wang 54764b9f64fSJason Wang module_pci_driver(vp_vdpa_driver); 54864b9f64fSJason Wang 54964b9f64fSJason Wang MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>"); 55064b9f64fSJason Wang MODULE_DESCRIPTION("vp-vdpa"); 55164b9f64fSJason Wang MODULE_LICENSE("GPL"); 55264b9f64fSJason Wang MODULE_VERSION("1"); 553