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> 20c1ca352dSJason Wang #include <uapi/linux/vdpa.h> 2164b9f64fSJason Wang 2264b9f64fSJason Wang #define VP_VDPA_QUEUE_MAX 256 2364b9f64fSJason Wang #define VP_VDPA_DRIVER_NAME "vp_vdpa" 2464b9f64fSJason Wang #define VP_VDPA_NAME_SIZE 256 2564b9f64fSJason Wang 2664b9f64fSJason Wang struct vp_vring { 2764b9f64fSJason Wang void __iomem *notify; 2864b9f64fSJason Wang char msix_name[VP_VDPA_NAME_SIZE]; 2964b9f64fSJason Wang struct vdpa_callback cb; 30526cb858SJason Wang resource_size_t notify_pa; 3164b9f64fSJason Wang int irq; 3264b9f64fSJason Wang }; 3364b9f64fSJason Wang 3464b9f64fSJason Wang struct vp_vdpa { 3564b9f64fSJason Wang struct vdpa_device vdpa; 36ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev; 3764b9f64fSJason Wang struct vp_vring *vring; 3864b9f64fSJason Wang struct vdpa_callback config_cb; 39c1ca352dSJason Wang u64 device_features; 4064b9f64fSJason Wang char msix_name[VP_VDPA_NAME_SIZE]; 4164b9f64fSJason Wang int config_irq; 4264b9f64fSJason Wang int queues; 4364b9f64fSJason Wang int vectors; 4464b9f64fSJason Wang }; 4564b9f64fSJason Wang 46ffbda8e9SCindy Lu struct vp_vdpa_mgmtdev { 47ffbda8e9SCindy Lu struct vdpa_mgmt_dev mgtdev; 48ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev; 49ffbda8e9SCindy Lu struct vp_vdpa *vp_vdpa; 50ffbda8e9SCindy Lu }; 51ffbda8e9SCindy Lu 5264b9f64fSJason Wang static struct vp_vdpa *vdpa_to_vp(struct vdpa_device *vdpa) 5364b9f64fSJason Wang { 5464b9f64fSJason Wang return container_of(vdpa, struct vp_vdpa, vdpa); 5564b9f64fSJason Wang } 5664b9f64fSJason Wang 5764b9f64fSJason Wang static struct virtio_pci_modern_device *vdpa_to_mdev(struct vdpa_device *vdpa) 5864b9f64fSJason Wang { 5964b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 6064b9f64fSJason Wang 61ffbda8e9SCindy Lu return vp_vdpa->mdev; 62ffbda8e9SCindy Lu } 63ffbda8e9SCindy Lu 64ffbda8e9SCindy Lu static struct virtio_pci_modern_device *vp_vdpa_to_mdev(struct vp_vdpa *vp_vdpa) 65ffbda8e9SCindy Lu { 66ffbda8e9SCindy Lu return vp_vdpa->mdev; 6764b9f64fSJason Wang } 6864b9f64fSJason Wang 69a64917bcSEli Cohen static u64 vp_vdpa_get_device_features(struct vdpa_device *vdpa) 7064b9f64fSJason Wang { 71c1ca352dSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 7264b9f64fSJason Wang 73c1ca352dSJason Wang return vp_vdpa->device_features; 7464b9f64fSJason Wang } 7564b9f64fSJason Wang 76a64917bcSEli Cohen static int vp_vdpa_set_driver_features(struct vdpa_device *vdpa, u64 features) 7764b9f64fSJason Wang { 7864b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 7964b9f64fSJason Wang 8064b9f64fSJason Wang vp_modern_set_features(mdev, features); 8164b9f64fSJason Wang 8264b9f64fSJason Wang return 0; 8364b9f64fSJason Wang } 8464b9f64fSJason Wang 85a64917bcSEli Cohen static u64 vp_vdpa_get_driver_features(struct vdpa_device *vdpa) 86a64917bcSEli Cohen { 87a64917bcSEli Cohen struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 88a64917bcSEli Cohen 89a64917bcSEli Cohen return vp_modern_get_driver_features(mdev); 90a64917bcSEli Cohen } 91a64917bcSEli Cohen 9264b9f64fSJason Wang static u8 vp_vdpa_get_status(struct vdpa_device *vdpa) 9364b9f64fSJason Wang { 9464b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 9564b9f64fSJason Wang 9664b9f64fSJason Wang return vp_modern_get_status(mdev); 9764b9f64fSJason Wang } 9864b9f64fSJason Wang 995bbfea1eSWu Zongyong static int vp_vdpa_get_vq_irq(struct vdpa_device *vdpa, u16 idx) 1005bbfea1eSWu Zongyong { 1015bbfea1eSWu Zongyong struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 1025bbfea1eSWu Zongyong int irq = vp_vdpa->vring[idx].irq; 1035bbfea1eSWu Zongyong 1045bbfea1eSWu Zongyong if (irq == VIRTIO_MSI_NO_VECTOR) 1055bbfea1eSWu Zongyong return -EINVAL; 1065bbfea1eSWu Zongyong 1075bbfea1eSWu Zongyong return irq; 1085bbfea1eSWu Zongyong } 1095bbfea1eSWu Zongyong 11064b9f64fSJason Wang static void vp_vdpa_free_irq(struct vp_vdpa *vp_vdpa) 11164b9f64fSJason Wang { 112ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 11364b9f64fSJason Wang struct pci_dev *pdev = mdev->pci_dev; 11464b9f64fSJason Wang int i; 11564b9f64fSJason Wang 11664b9f64fSJason Wang for (i = 0; i < vp_vdpa->queues; i++) { 11764b9f64fSJason Wang if (vp_vdpa->vring[i].irq != VIRTIO_MSI_NO_VECTOR) { 11864b9f64fSJason Wang vp_modern_queue_vector(mdev, i, VIRTIO_MSI_NO_VECTOR); 11964b9f64fSJason Wang devm_free_irq(&pdev->dev, vp_vdpa->vring[i].irq, 12064b9f64fSJason Wang &vp_vdpa->vring[i]); 12164b9f64fSJason Wang vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 12264b9f64fSJason Wang } 12364b9f64fSJason Wang } 12464b9f64fSJason Wang 12564b9f64fSJason Wang if (vp_vdpa->config_irq != VIRTIO_MSI_NO_VECTOR) { 12664b9f64fSJason Wang vp_modern_config_vector(mdev, VIRTIO_MSI_NO_VECTOR); 12764b9f64fSJason Wang devm_free_irq(&pdev->dev, vp_vdpa->config_irq, vp_vdpa); 12864b9f64fSJason Wang vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 12964b9f64fSJason Wang } 13064b9f64fSJason Wang 13164b9f64fSJason Wang if (vp_vdpa->vectors) { 13264b9f64fSJason Wang pci_free_irq_vectors(pdev); 13364b9f64fSJason Wang vp_vdpa->vectors = 0; 13464b9f64fSJason Wang } 13564b9f64fSJason Wang } 13664b9f64fSJason Wang 13764b9f64fSJason Wang static irqreturn_t vp_vdpa_vq_handler(int irq, void *arg) 13864b9f64fSJason Wang { 13964b9f64fSJason Wang struct vp_vring *vring = arg; 14064b9f64fSJason Wang 14164b9f64fSJason Wang if (vring->cb.callback) 14264b9f64fSJason Wang return vring->cb.callback(vring->cb.private); 14364b9f64fSJason Wang 14464b9f64fSJason Wang return IRQ_HANDLED; 14564b9f64fSJason Wang } 14664b9f64fSJason Wang 14764b9f64fSJason Wang static irqreturn_t vp_vdpa_config_handler(int irq, void *arg) 14864b9f64fSJason Wang { 14964b9f64fSJason Wang struct vp_vdpa *vp_vdpa = arg; 15064b9f64fSJason Wang 15164b9f64fSJason Wang if (vp_vdpa->config_cb.callback) 15264b9f64fSJason Wang return vp_vdpa->config_cb.callback(vp_vdpa->config_cb.private); 15364b9f64fSJason Wang 15464b9f64fSJason Wang return IRQ_HANDLED; 15564b9f64fSJason Wang } 15664b9f64fSJason Wang 15764b9f64fSJason Wang static int vp_vdpa_request_irq(struct vp_vdpa *vp_vdpa) 15864b9f64fSJason Wang { 159ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 16064b9f64fSJason Wang struct pci_dev *pdev = mdev->pci_dev; 16164b9f64fSJason Wang int i, ret, irq; 16264b9f64fSJason Wang int queues = vp_vdpa->queues; 163*4d685629SYuxue Liu int vectors = 1; 164*4d685629SYuxue Liu int msix_vec = 0; 165*4d685629SYuxue Liu 166*4d685629SYuxue Liu for (i = 0; i < queues; i++) { 167*4d685629SYuxue Liu if (vp_vdpa->vring[i].cb.callback) 168*4d685629SYuxue Liu vectors++; 169*4d685629SYuxue Liu } 17064b9f64fSJason Wang 17164b9f64fSJason Wang ret = pci_alloc_irq_vectors(pdev, vectors, vectors, PCI_IRQ_MSIX); 17264b9f64fSJason Wang if (ret != vectors) { 17364b9f64fSJason Wang dev_err(&pdev->dev, 17464b9f64fSJason Wang "vp_vdpa: fail to allocate irq vectors want %d but %d\n", 17564b9f64fSJason Wang vectors, ret); 17664b9f64fSJason Wang return ret; 17764b9f64fSJason Wang } 17864b9f64fSJason Wang 17964b9f64fSJason Wang vp_vdpa->vectors = vectors; 18064b9f64fSJason Wang 18164b9f64fSJason Wang for (i = 0; i < queues; i++) { 182*4d685629SYuxue Liu if (!vp_vdpa->vring[i].cb.callback) 183*4d685629SYuxue Liu continue; 184*4d685629SYuxue Liu 18564b9f64fSJason Wang snprintf(vp_vdpa->vring[i].msix_name, VP_VDPA_NAME_SIZE, 18664b9f64fSJason Wang "vp-vdpa[%s]-%d\n", pci_name(pdev), i); 187*4d685629SYuxue Liu irq = pci_irq_vector(pdev, msix_vec); 18864b9f64fSJason Wang ret = devm_request_irq(&pdev->dev, irq, 18964b9f64fSJason Wang vp_vdpa_vq_handler, 19064b9f64fSJason Wang 0, vp_vdpa->vring[i].msix_name, 19164b9f64fSJason Wang &vp_vdpa->vring[i]); 19264b9f64fSJason Wang if (ret) { 19364b9f64fSJason Wang dev_err(&pdev->dev, 19464b9f64fSJason Wang "vp_vdpa: fail to request irq for vq %d\n", i); 19564b9f64fSJason Wang goto err; 19664b9f64fSJason Wang } 197*4d685629SYuxue Liu vp_modern_queue_vector(mdev, i, msix_vec); 19864b9f64fSJason Wang vp_vdpa->vring[i].irq = irq; 199*4d685629SYuxue Liu msix_vec++; 20064b9f64fSJason Wang } 20164b9f64fSJason Wang 20264b9f64fSJason Wang snprintf(vp_vdpa->msix_name, VP_VDPA_NAME_SIZE, "vp-vdpa[%s]-config\n", 20364b9f64fSJason Wang pci_name(pdev)); 204*4d685629SYuxue Liu irq = pci_irq_vector(pdev, msix_vec); 20564b9f64fSJason Wang ret = devm_request_irq(&pdev->dev, irq, vp_vdpa_config_handler, 0, 20664b9f64fSJason Wang vp_vdpa->msix_name, vp_vdpa); 20764b9f64fSJason Wang if (ret) { 20864b9f64fSJason Wang dev_err(&pdev->dev, 209*4d685629SYuxue Liu "vp_vdpa: fail to request irq for config: %d\n", ret); 21064b9f64fSJason Wang goto err; 21164b9f64fSJason Wang } 212*4d685629SYuxue Liu vp_modern_config_vector(mdev, msix_vec); 21364b9f64fSJason Wang vp_vdpa->config_irq = irq; 21464b9f64fSJason Wang 21564b9f64fSJason Wang return 0; 21664b9f64fSJason Wang err: 21764b9f64fSJason Wang vp_vdpa_free_irq(vp_vdpa); 21864b9f64fSJason Wang return ret; 21964b9f64fSJason Wang } 22064b9f64fSJason Wang 22164b9f64fSJason Wang static void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status) 22264b9f64fSJason Wang { 22364b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 224ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 22564b9f64fSJason Wang u8 s = vp_vdpa_get_status(vdpa); 22664b9f64fSJason Wang 22764b9f64fSJason Wang if (status & VIRTIO_CONFIG_S_DRIVER_OK && 22864b9f64fSJason Wang !(s & VIRTIO_CONFIG_S_DRIVER_OK)) { 229f181a373SYuxue Liu if (vp_vdpa_request_irq(vp_vdpa)) { 230f181a373SYuxue Liu WARN_ON(1); 231f181a373SYuxue Liu return; 232f181a373SYuxue Liu } 23364b9f64fSJason Wang } 23464b9f64fSJason Wang 23564b9f64fSJason Wang vp_modern_set_status(mdev, status); 2360686082dSXie Yongji } 23764b9f64fSJason Wang 2380686082dSXie Yongji static int vp_vdpa_reset(struct vdpa_device *vdpa) 2390686082dSXie Yongji { 2400686082dSXie Yongji struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 241ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 2420686082dSXie Yongji u8 s = vp_vdpa_get_status(vdpa); 2430686082dSXie Yongji 2440686082dSXie Yongji vp_modern_set_status(mdev, 0); 2450686082dSXie Yongji 2460686082dSXie Yongji if (s & VIRTIO_CONFIG_S_DRIVER_OK) 24764b9f64fSJason Wang vp_vdpa_free_irq(vp_vdpa); 2480686082dSXie Yongji 2490686082dSXie Yongji return 0; 25064b9f64fSJason Wang } 25164b9f64fSJason Wang 25264b9f64fSJason Wang static u16 vp_vdpa_get_vq_num_max(struct vdpa_device *vdpa) 25364b9f64fSJason Wang { 25464b9f64fSJason Wang return VP_VDPA_QUEUE_MAX; 25564b9f64fSJason Wang } 25664b9f64fSJason Wang 25764b9f64fSJason Wang static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid, 25864b9f64fSJason Wang struct vdpa_vq_state *state) 25964b9f64fSJason Wang { 26064b9f64fSJason Wang /* Note that this is not supported by virtio specification, so 26164b9f64fSJason Wang * we return -EOPNOTSUPP here. This means we can't support live 26264b9f64fSJason Wang * migration, vhost device start/stop. 26364b9f64fSJason Wang */ 26464b9f64fSJason Wang return -EOPNOTSUPP; 26564b9f64fSJason Wang } 26664b9f64fSJason Wang 2671225c216SJason Wang static int vp_vdpa_set_vq_state_split(struct vdpa_device *vdpa, 2681225c216SJason Wang const struct vdpa_vq_state *state) 2691225c216SJason Wang { 2701225c216SJason Wang const struct vdpa_vq_state_split *split = &state->split; 2711225c216SJason Wang 2721225c216SJason Wang if (split->avail_index == 0) 2731225c216SJason Wang return 0; 2741225c216SJason Wang 2751225c216SJason Wang return -EOPNOTSUPP; 2761225c216SJason Wang } 2771225c216SJason Wang 2781225c216SJason Wang static int vp_vdpa_set_vq_state_packed(struct vdpa_device *vdpa, 2791225c216SJason Wang const struct vdpa_vq_state *state) 2801225c216SJason Wang { 2811225c216SJason Wang const struct vdpa_vq_state_packed *packed = &state->packed; 2821225c216SJason Wang 2831225c216SJason Wang if (packed->last_avail_counter == 1 && 2841225c216SJason Wang packed->last_avail_idx == 0 && 2851225c216SJason Wang packed->last_used_counter == 1 && 2861225c216SJason Wang packed->last_used_idx == 0) 2871225c216SJason Wang return 0; 2881225c216SJason Wang 2891225c216SJason Wang return -EOPNOTSUPP; 2901225c216SJason Wang } 2911225c216SJason Wang 29264b9f64fSJason Wang static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid, 29364b9f64fSJason Wang const struct vdpa_vq_state *state) 29464b9f64fSJason Wang { 2951225c216SJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 2961225c216SJason Wang 2971225c216SJason Wang /* Note that this is not supported by virtio specification. 2981225c216SJason Wang * But if the state is by chance equal to the device initial 2991225c216SJason Wang * state, we can let it go. 30064b9f64fSJason Wang */ 3011225c216SJason Wang if ((vp_modern_get_status(mdev) & VIRTIO_CONFIG_S_FEATURES_OK) && 3021225c216SJason Wang !vp_modern_get_queue_enable(mdev, qid)) { 3031225c216SJason Wang if (vp_modern_get_driver_features(mdev) & 3041225c216SJason Wang BIT_ULL(VIRTIO_F_RING_PACKED)) 3051225c216SJason Wang return vp_vdpa_set_vq_state_packed(vdpa, state); 3061225c216SJason Wang else 3071225c216SJason Wang return vp_vdpa_set_vq_state_split(vdpa, state); 3081225c216SJason Wang } 3091225c216SJason Wang 31064b9f64fSJason Wang return -EOPNOTSUPP; 31164b9f64fSJason Wang } 31264b9f64fSJason Wang 31364b9f64fSJason Wang static void vp_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 qid, 31464b9f64fSJason Wang struct vdpa_callback *cb) 31564b9f64fSJason Wang { 31664b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 31764b9f64fSJason Wang 31864b9f64fSJason Wang vp_vdpa->vring[qid].cb = *cb; 31964b9f64fSJason Wang } 32064b9f64fSJason Wang 32164b9f64fSJason Wang static void vp_vdpa_set_vq_ready(struct vdpa_device *vdpa, 32264b9f64fSJason Wang u16 qid, bool ready) 32364b9f64fSJason Wang { 32464b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 32564b9f64fSJason Wang 32664b9f64fSJason Wang vp_modern_set_queue_enable(mdev, qid, ready); 32764b9f64fSJason Wang } 32864b9f64fSJason Wang 32964b9f64fSJason Wang static bool vp_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 qid) 33064b9f64fSJason Wang { 33164b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 33264b9f64fSJason Wang 33364b9f64fSJason Wang return vp_modern_get_queue_enable(mdev, qid); 33464b9f64fSJason Wang } 33564b9f64fSJason Wang 33664b9f64fSJason Wang static void vp_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 qid, 33764b9f64fSJason Wang u32 num) 33864b9f64fSJason Wang { 33964b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 34064b9f64fSJason Wang 34164b9f64fSJason Wang vp_modern_set_queue_size(mdev, qid, num); 34264b9f64fSJason Wang } 34364b9f64fSJason Wang 344a97f9c8fSZhu Lingshan static u16 vp_vdpa_get_vq_size(struct vdpa_device *vdpa, u16 qid) 345a97f9c8fSZhu Lingshan { 346a97f9c8fSZhu Lingshan struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 347a97f9c8fSZhu Lingshan 348a97f9c8fSZhu Lingshan return vp_modern_get_queue_size(mdev, qid); 349a97f9c8fSZhu Lingshan } 350a97f9c8fSZhu Lingshan 35164b9f64fSJason Wang static int vp_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 qid, 35264b9f64fSJason Wang u64 desc_area, u64 driver_area, 35364b9f64fSJason Wang u64 device_area) 35464b9f64fSJason Wang { 35564b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 35664b9f64fSJason Wang 35764b9f64fSJason Wang vp_modern_queue_address(mdev, qid, desc_area, 35864b9f64fSJason Wang driver_area, device_area); 35964b9f64fSJason Wang 36064b9f64fSJason Wang return 0; 36164b9f64fSJason Wang } 36264b9f64fSJason Wang 36364b9f64fSJason Wang static void vp_vdpa_kick_vq(struct vdpa_device *vdpa, u16 qid) 36464b9f64fSJason Wang { 36564b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 36664b9f64fSJason Wang 36764b9f64fSJason Wang vp_iowrite16(qid, vp_vdpa->vring[qid].notify); 36864b9f64fSJason Wang } 36964b9f64fSJason Wang 37064b9f64fSJason Wang static u32 vp_vdpa_get_generation(struct vdpa_device *vdpa) 37164b9f64fSJason Wang { 37264b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 37364b9f64fSJason Wang 37464b9f64fSJason Wang return vp_modern_generation(mdev); 37564b9f64fSJason Wang } 37664b9f64fSJason Wang 37764b9f64fSJason Wang static u32 vp_vdpa_get_device_id(struct vdpa_device *vdpa) 37864b9f64fSJason Wang { 37964b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 38064b9f64fSJason Wang 38164b9f64fSJason Wang return mdev->id.device; 38264b9f64fSJason Wang } 38364b9f64fSJason Wang 38464b9f64fSJason Wang static u32 vp_vdpa_get_vendor_id(struct vdpa_device *vdpa) 38564b9f64fSJason Wang { 38664b9f64fSJason Wang struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 38764b9f64fSJason Wang 38864b9f64fSJason Wang return mdev->id.vendor; 38964b9f64fSJason Wang } 39064b9f64fSJason Wang 39164b9f64fSJason Wang static u32 vp_vdpa_get_vq_align(struct vdpa_device *vdpa) 39264b9f64fSJason Wang { 39364b9f64fSJason Wang return PAGE_SIZE; 39464b9f64fSJason Wang } 39564b9f64fSJason Wang 396442706f9SStefano Garzarella static size_t vp_vdpa_get_config_size(struct vdpa_device *vdpa) 397442706f9SStefano Garzarella { 398442706f9SStefano Garzarella struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); 399442706f9SStefano Garzarella 400442706f9SStefano Garzarella return mdev->device_len; 401442706f9SStefano Garzarella } 402442706f9SStefano Garzarella 40364b9f64fSJason Wang static void vp_vdpa_get_config(struct vdpa_device *vdpa, 40464b9f64fSJason Wang unsigned int offset, 40564b9f64fSJason Wang void *buf, unsigned int len) 40664b9f64fSJason Wang { 40764b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 408ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 40964b9f64fSJason Wang u8 old, new; 41064b9f64fSJason Wang u8 *p; 41164b9f64fSJason Wang int i; 41264b9f64fSJason Wang 41364b9f64fSJason Wang do { 41464b9f64fSJason Wang old = vp_ioread8(&mdev->common->config_generation); 41564b9f64fSJason Wang p = buf; 41664b9f64fSJason Wang for (i = 0; i < len; i++) 41764b9f64fSJason Wang *p++ = vp_ioread8(mdev->device + offset + i); 41864b9f64fSJason Wang 41964b9f64fSJason Wang new = vp_ioread8(&mdev->common->config_generation); 42064b9f64fSJason Wang } while (old != new); 42164b9f64fSJason Wang } 42264b9f64fSJason Wang 42364b9f64fSJason Wang static void vp_vdpa_set_config(struct vdpa_device *vdpa, 42464b9f64fSJason Wang unsigned int offset, const void *buf, 42564b9f64fSJason Wang unsigned int len) 42664b9f64fSJason Wang { 42764b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 428ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 42964b9f64fSJason Wang const u8 *p = buf; 43064b9f64fSJason Wang int i; 43164b9f64fSJason Wang 43264b9f64fSJason Wang for (i = 0; i < len; i++) 43364b9f64fSJason Wang vp_iowrite8(*p++, mdev->device + offset + i); 43464b9f64fSJason Wang } 43564b9f64fSJason Wang 43664b9f64fSJason Wang static void vp_vdpa_set_config_cb(struct vdpa_device *vdpa, 43764b9f64fSJason Wang struct vdpa_callback *cb) 43864b9f64fSJason Wang { 43964b9f64fSJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 44064b9f64fSJason Wang 44164b9f64fSJason Wang vp_vdpa->config_cb = *cb; 44264b9f64fSJason Wang } 44364b9f64fSJason Wang 444526cb858SJason Wang static struct vdpa_notification_area 445526cb858SJason Wang vp_vdpa_get_vq_notification(struct vdpa_device *vdpa, u16 qid) 446526cb858SJason Wang { 447526cb858SJason Wang struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); 448ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); 449526cb858SJason Wang struct vdpa_notification_area notify; 450526cb858SJason Wang 451526cb858SJason Wang notify.addr = vp_vdpa->vring[qid].notify_pa; 452526cb858SJason Wang notify.size = mdev->notify_offset_multiplier; 453526cb858SJason Wang 454526cb858SJason Wang return notify; 455526cb858SJason Wang } 456526cb858SJason Wang 45764b9f64fSJason Wang static const struct vdpa_config_ops vp_vdpa_ops = { 458a64917bcSEli Cohen .get_device_features = vp_vdpa_get_device_features, 459a64917bcSEli Cohen .set_driver_features = vp_vdpa_set_driver_features, 460a64917bcSEli Cohen .get_driver_features = vp_vdpa_get_driver_features, 46164b9f64fSJason Wang .get_status = vp_vdpa_get_status, 46264b9f64fSJason Wang .set_status = vp_vdpa_set_status, 4630686082dSXie Yongji .reset = vp_vdpa_reset, 46464b9f64fSJason Wang .get_vq_num_max = vp_vdpa_get_vq_num_max, 46564b9f64fSJason Wang .get_vq_state = vp_vdpa_get_vq_state, 466526cb858SJason Wang .get_vq_notification = vp_vdpa_get_vq_notification, 46764b9f64fSJason Wang .set_vq_state = vp_vdpa_set_vq_state, 46864b9f64fSJason Wang .set_vq_cb = vp_vdpa_set_vq_cb, 46964b9f64fSJason Wang .set_vq_ready = vp_vdpa_set_vq_ready, 47064b9f64fSJason Wang .get_vq_ready = vp_vdpa_get_vq_ready, 47164b9f64fSJason Wang .set_vq_num = vp_vdpa_set_vq_num, 472a97f9c8fSZhu Lingshan .get_vq_size = vp_vdpa_get_vq_size, 47364b9f64fSJason Wang .set_vq_address = vp_vdpa_set_vq_address, 47464b9f64fSJason Wang .kick_vq = vp_vdpa_kick_vq, 47564b9f64fSJason Wang .get_generation = vp_vdpa_get_generation, 47664b9f64fSJason Wang .get_device_id = vp_vdpa_get_device_id, 47764b9f64fSJason Wang .get_vendor_id = vp_vdpa_get_vendor_id, 47864b9f64fSJason Wang .get_vq_align = vp_vdpa_get_vq_align, 479442706f9SStefano Garzarella .get_config_size = vp_vdpa_get_config_size, 48064b9f64fSJason Wang .get_config = vp_vdpa_get_config, 48164b9f64fSJason Wang .set_config = vp_vdpa_set_config, 48264b9f64fSJason Wang .set_config_cb = vp_vdpa_set_config_cb, 4835bbfea1eSWu Zongyong .get_vq_irq = vp_vdpa_get_vq_irq, 48464b9f64fSJason Wang }; 48564b9f64fSJason Wang 48664b9f64fSJason Wang static void vp_vdpa_free_irq_vectors(void *data) 48764b9f64fSJason Wang { 48864b9f64fSJason Wang pci_free_irq_vectors(data); 48964b9f64fSJason Wang } 49064b9f64fSJason Wang 491ffbda8e9SCindy Lu static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, 492ffbda8e9SCindy Lu const struct vdpa_dev_set_config *add_config) 49364b9f64fSJason Wang { 494ffbda8e9SCindy Lu struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = 495ffbda8e9SCindy Lu container_of(v_mdev, struct vp_vdpa_mgmtdev, mgtdev); 496ffbda8e9SCindy Lu 497ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = vp_vdpa_mgtdev->mdev; 498ffbda8e9SCindy Lu struct pci_dev *pdev = mdev->pci_dev; 49964b9f64fSJason Wang struct device *dev = &pdev->dev; 500ffbda8e9SCindy Lu struct vp_vdpa *vp_vdpa = NULL; 501c1ca352dSJason Wang u64 device_features; 50264b9f64fSJason Wang int ret, i; 50364b9f64fSJason Wang 50464b9f64fSJason Wang vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa, 505ffbda8e9SCindy Lu dev, &vp_vdpa_ops, 1, 1, name, false); 506ffbda8e9SCindy Lu 5079632e78eSXie Yongji if (IS_ERR(vp_vdpa)) { 50864b9f64fSJason Wang dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n"); 5099632e78eSXie Yongji return PTR_ERR(vp_vdpa); 51064b9f64fSJason Wang } 51164b9f64fSJason Wang 512ffbda8e9SCindy Lu vp_vdpa_mgtdev->vp_vdpa = vp_vdpa; 51364b9f64fSJason Wang 51464b9f64fSJason Wang vp_vdpa->vdpa.dma_dev = &pdev->dev; 51564b9f64fSJason Wang vp_vdpa->queues = vp_modern_get_num_queues(mdev); 516ffbda8e9SCindy Lu vp_vdpa->mdev = mdev; 51764b9f64fSJason Wang 518c1ca352dSJason Wang device_features = vp_modern_get_features(mdev); 519c1ca352dSJason Wang if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 520c1ca352dSJason Wang if (add_config->device_features & ~device_features) { 521c1ca352dSJason Wang ret = -EINVAL; 522c1ca352dSJason Wang dev_err(&pdev->dev, "Try to provision features " 523c1ca352dSJason Wang "that are not supported by the device: " 524c1ca352dSJason Wang "device_features 0x%llx provisioned 0x%llx\n", 525c1ca352dSJason Wang device_features, add_config->device_features); 526c1ca352dSJason Wang goto err; 527c1ca352dSJason Wang } 528c1ca352dSJason Wang device_features = add_config->device_features; 529c1ca352dSJason Wang } 530c1ca352dSJason Wang vp_vdpa->device_features = device_features; 531c1ca352dSJason Wang 53264b9f64fSJason Wang ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev); 53364b9f64fSJason Wang if (ret) { 53464b9f64fSJason Wang dev_err(&pdev->dev, 53564b9f64fSJason Wang "Failed for adding devres for freeing irq vectors\n"); 53664b9f64fSJason Wang goto err; 53764b9f64fSJason Wang } 53864b9f64fSJason Wang 53964b9f64fSJason Wang vp_vdpa->vring = devm_kcalloc(&pdev->dev, vp_vdpa->queues, 54064b9f64fSJason Wang sizeof(*vp_vdpa->vring), 54164b9f64fSJason Wang GFP_KERNEL); 54264b9f64fSJason Wang if (!vp_vdpa->vring) { 54364b9f64fSJason Wang ret = -ENOMEM; 54464b9f64fSJason Wang dev_err(&pdev->dev, "Fail to allocate virtqueues\n"); 54564b9f64fSJason Wang goto err; 54664b9f64fSJason Wang } 54764b9f64fSJason Wang 54864b9f64fSJason Wang for (i = 0; i < vp_vdpa->queues; i++) { 54964b9f64fSJason Wang vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR; 5509e311bcaSJason Wang vp_vdpa->vring[i].notify = 551526cb858SJason Wang vp_modern_map_vq_notify(mdev, i, 552526cb858SJason Wang &vp_vdpa->vring[i].notify_pa); 55311d8ffedSJason Wang if (!vp_vdpa->vring[i].notify) { 55494e48d6aSJason Wang ret = -EINVAL; 55511d8ffedSJason Wang dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i); 55611d8ffedSJason Wang goto err; 55711d8ffedSJason Wang } 55864b9f64fSJason Wang } 55964b9f64fSJason Wang vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR; 56064b9f64fSJason Wang 561ffbda8e9SCindy Lu vp_vdpa->vdpa.mdev = &vp_vdpa_mgtdev->mgtdev; 562ffbda8e9SCindy Lu ret = _vdpa_register_device(&vp_vdpa->vdpa, vp_vdpa->queues); 56364b9f64fSJason Wang if (ret) { 56464b9f64fSJason Wang dev_err(&pdev->dev, "Failed to register to vdpa bus\n"); 56564b9f64fSJason Wang goto err; 56664b9f64fSJason Wang } 56764b9f64fSJason Wang 56864b9f64fSJason Wang return 0; 56964b9f64fSJason Wang 57064b9f64fSJason Wang err: 57164b9f64fSJason Wang put_device(&vp_vdpa->vdpa.dev); 57264b9f64fSJason Wang return ret; 57364b9f64fSJason Wang } 57464b9f64fSJason Wang 575ffbda8e9SCindy Lu static void vp_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, 576ffbda8e9SCindy Lu struct vdpa_device *dev) 577ffbda8e9SCindy Lu { 578ffbda8e9SCindy Lu struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = 579ffbda8e9SCindy Lu container_of(v_mdev, struct vp_vdpa_mgmtdev, mgtdev); 580ffbda8e9SCindy Lu 581ffbda8e9SCindy Lu struct vp_vdpa *vp_vdpa = vp_vdpa_mgtdev->vp_vdpa; 582ffbda8e9SCindy Lu 583ffbda8e9SCindy Lu _vdpa_unregister_device(&vp_vdpa->vdpa); 584ffbda8e9SCindy Lu vp_vdpa_mgtdev->vp_vdpa = NULL; 585ffbda8e9SCindy Lu } 586ffbda8e9SCindy Lu 587ffbda8e9SCindy Lu static const struct vdpa_mgmtdev_ops vp_vdpa_mdev_ops = { 588ffbda8e9SCindy Lu .dev_add = vp_vdpa_dev_add, 589ffbda8e9SCindy Lu .dev_del = vp_vdpa_dev_del, 590ffbda8e9SCindy Lu }; 591ffbda8e9SCindy Lu 592ffbda8e9SCindy Lu static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) 593ffbda8e9SCindy Lu { 594ffbda8e9SCindy Lu struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = NULL; 595ffbda8e9SCindy Lu struct vdpa_mgmt_dev *mgtdev; 596ffbda8e9SCindy Lu struct device *dev = &pdev->dev; 597ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = NULL; 598ffbda8e9SCindy Lu struct virtio_device_id *mdev_id = NULL; 599ffbda8e9SCindy Lu int err; 600ffbda8e9SCindy Lu 601ffbda8e9SCindy Lu vp_vdpa_mgtdev = kzalloc(sizeof(*vp_vdpa_mgtdev), GFP_KERNEL); 602ffbda8e9SCindy Lu if (!vp_vdpa_mgtdev) 603ffbda8e9SCindy Lu return -ENOMEM; 604ffbda8e9SCindy Lu 605ffbda8e9SCindy Lu mgtdev = &vp_vdpa_mgtdev->mgtdev; 606ffbda8e9SCindy Lu mgtdev->ops = &vp_vdpa_mdev_ops; 607ffbda8e9SCindy Lu mgtdev->device = dev; 608ffbda8e9SCindy Lu 609ffbda8e9SCindy Lu mdev = kzalloc(sizeof(struct virtio_pci_modern_device), GFP_KERNEL); 610ffbda8e9SCindy Lu if (!mdev) { 611ffbda8e9SCindy Lu err = -ENOMEM; 612ffbda8e9SCindy Lu goto mdev_err; 613ffbda8e9SCindy Lu } 614ffbda8e9SCindy Lu 615ffbda8e9SCindy Lu mdev_id = kzalloc(sizeof(struct virtio_device_id), GFP_KERNEL); 616ffbda8e9SCindy Lu if (!mdev_id) { 617ffbda8e9SCindy Lu err = -ENOMEM; 618ffbda8e9SCindy Lu goto mdev_id_err; 619ffbda8e9SCindy Lu } 620ffbda8e9SCindy Lu 621ffbda8e9SCindy Lu vp_vdpa_mgtdev->mdev = mdev; 622ffbda8e9SCindy Lu mdev->pci_dev = pdev; 623ffbda8e9SCindy Lu 624ffbda8e9SCindy Lu err = pcim_enable_device(pdev); 625ffbda8e9SCindy Lu if (err) { 626ffbda8e9SCindy Lu goto probe_err; 627ffbda8e9SCindy Lu } 628ffbda8e9SCindy Lu 629ffbda8e9SCindy Lu err = vp_modern_probe(mdev); 630ffbda8e9SCindy Lu if (err) { 631ffbda8e9SCindy Lu dev_err(&pdev->dev, "Failed to probe modern PCI device\n"); 632ffbda8e9SCindy Lu goto probe_err; 633ffbda8e9SCindy Lu } 634ffbda8e9SCindy Lu 635ffbda8e9SCindy Lu mdev_id->device = mdev->id.device; 636ffbda8e9SCindy Lu mdev_id->vendor = mdev->id.vendor; 637ffbda8e9SCindy Lu mgtdev->id_table = mdev_id; 638ffbda8e9SCindy Lu mgtdev->max_supported_vqs = vp_modern_get_num_queues(mdev); 639ffbda8e9SCindy Lu mgtdev->supported_features = vp_modern_get_features(mdev); 640c1ca352dSJason Wang mgtdev->config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES); 641ffbda8e9SCindy Lu pci_set_master(pdev); 642ffbda8e9SCindy Lu pci_set_drvdata(pdev, vp_vdpa_mgtdev); 643ffbda8e9SCindy Lu 644ffbda8e9SCindy Lu err = vdpa_mgmtdev_register(mgtdev); 645ffbda8e9SCindy Lu if (err) { 646ffbda8e9SCindy Lu dev_err(&pdev->dev, "Failed to register vdpa mgmtdev device\n"); 647ffbda8e9SCindy Lu goto register_err; 648ffbda8e9SCindy Lu } 649ffbda8e9SCindy Lu 650ffbda8e9SCindy Lu return 0; 651ffbda8e9SCindy Lu 652ffbda8e9SCindy Lu register_err: 653ffbda8e9SCindy Lu vp_modern_remove(vp_vdpa_mgtdev->mdev); 654ffbda8e9SCindy Lu probe_err: 655ffbda8e9SCindy Lu kfree(mdev_id); 656ffbda8e9SCindy Lu mdev_id_err: 657ffbda8e9SCindy Lu kfree(mdev); 658ffbda8e9SCindy Lu mdev_err: 659ffbda8e9SCindy Lu kfree(vp_vdpa_mgtdev); 660ffbda8e9SCindy Lu return err; 661ffbda8e9SCindy Lu } 662ffbda8e9SCindy Lu 66364b9f64fSJason Wang static void vp_vdpa_remove(struct pci_dev *pdev) 66464b9f64fSJason Wang { 665ffbda8e9SCindy Lu struct vp_vdpa_mgmtdev *vp_vdpa_mgtdev = pci_get_drvdata(pdev); 666ffbda8e9SCindy Lu struct virtio_pci_modern_device *mdev = NULL; 66764b9f64fSJason Wang 668ffbda8e9SCindy Lu mdev = vp_vdpa_mgtdev->mdev; 669ffbda8e9SCindy Lu vdpa_mgmtdev_unregister(&vp_vdpa_mgtdev->mgtdev); 670aed8efddSCindy Lu vp_modern_remove(mdev); 671ed843d6eSRong Wang kfree(vp_vdpa_mgtdev->mgtdev.id_table); 672ffbda8e9SCindy Lu kfree(mdev); 673ffbda8e9SCindy Lu kfree(vp_vdpa_mgtdev); 67464b9f64fSJason Wang } 67564b9f64fSJason Wang 67664b9f64fSJason Wang static struct pci_driver vp_vdpa_driver = { 67764b9f64fSJason Wang .name = "vp-vdpa", 67864b9f64fSJason Wang .id_table = NULL, /* only dynamic ids */ 67964b9f64fSJason Wang .probe = vp_vdpa_probe, 68064b9f64fSJason Wang .remove = vp_vdpa_remove, 68164b9f64fSJason Wang }; 68264b9f64fSJason Wang 68364b9f64fSJason Wang module_pci_driver(vp_vdpa_driver); 68464b9f64fSJason Wang 68564b9f64fSJason Wang MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>"); 68664b9f64fSJason Wang MODULE_DESCRIPTION("vp-vdpa"); 68764b9f64fSJason Wang MODULE_LICENSE("GPL"); 68864b9f64fSJason Wang MODULE_VERSION("1"); 689