162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright(c) 2023 Advanced Micro Devices, Inc */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/pci.h> 562306a36Sopenharmony_ci#include <linux/vdpa.h> 662306a36Sopenharmony_ci#include <uapi/linux/vdpa.h> 762306a36Sopenharmony_ci#include <linux/virtio_pci_modern.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/pds/pds_common.h> 1062306a36Sopenharmony_ci#include <linux/pds/pds_core_if.h> 1162306a36Sopenharmony_ci#include <linux/pds/pds_adminq.h> 1262306a36Sopenharmony_ci#include <linux/pds/pds_auxbus.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "vdpa_dev.h" 1562306a36Sopenharmony_ci#include "aux_drv.h" 1662306a36Sopenharmony_ci#include "cmds.h" 1762306a36Sopenharmony_ci#include "debugfs.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic u64 pds_vdpa_get_driver_features(struct vdpa_device *vdpa_dev); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct pds_vdpa_device *vdpa_to_pdsv(struct vdpa_device *vdpa_dev) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return container_of(vdpa_dev, struct pds_vdpa_device, vdpa_dev); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic int pds_vdpa_notify_handler(struct notifier_block *nb, 2762306a36Sopenharmony_ci unsigned long ecode, 2862306a36Sopenharmony_ci void *data) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = container_of(nb, struct pds_vdpa_device, nb); 3162306a36Sopenharmony_ci struct device *dev = &pdsv->vdpa_aux->padev->aux_dev.dev; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci dev_dbg(dev, "%s: event code %lu\n", __func__, ecode); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (ecode == PDS_EVENT_RESET || ecode == PDS_EVENT_LINK_CHANGE) { 3662306a36Sopenharmony_ci if (pdsv->config_cb.callback) 3762306a36Sopenharmony_ci pdsv->config_cb.callback(pdsv->config_cb.private); 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int pds_vdpa_register_event_handler(struct pds_vdpa_device *pdsv) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct device *dev = &pdsv->vdpa_aux->padev->aux_dev.dev; 4662306a36Sopenharmony_ci struct notifier_block *nb = &pdsv->nb; 4762306a36Sopenharmony_ci int err; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (!nb->notifier_call) { 5062306a36Sopenharmony_ci nb->notifier_call = pds_vdpa_notify_handler; 5162306a36Sopenharmony_ci err = pdsc_register_notify(nb); 5262306a36Sopenharmony_ci if (err) { 5362306a36Sopenharmony_ci nb->notifier_call = NULL; 5462306a36Sopenharmony_ci dev_err(dev, "failed to register pds event handler: %ps\n", 5562306a36Sopenharmony_ci ERR_PTR(err)); 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci dev_dbg(dev, "pds event handler registered\n"); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void pds_vdpa_unregister_event_handler(struct pds_vdpa_device *pdsv) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci if (pdsv->nb.notifier_call) { 6762306a36Sopenharmony_ci pdsc_unregister_notify(&pdsv->nb); 6862306a36Sopenharmony_ci pdsv->nb.notifier_call = NULL; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int pds_vdpa_set_vq_address(struct vdpa_device *vdpa_dev, u16 qid, 7362306a36Sopenharmony_ci u64 desc_addr, u64 driver_addr, u64 device_addr) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci pdsv->vqs[qid].desc_addr = desc_addr; 7862306a36Sopenharmony_ci pdsv->vqs[qid].avail_addr = driver_addr; 7962306a36Sopenharmony_ci pdsv->vqs[qid].used_addr = device_addr; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void pds_vdpa_set_vq_num(struct vdpa_device *vdpa_dev, u16 qid, u32 num) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci pdsv->vqs[qid].q_len = num; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void pds_vdpa_kick_vq(struct vdpa_device *vdpa_dev, u16 qid) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci iowrite16(qid, pdsv->vqs[qid].notify); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void pds_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid, 9962306a36Sopenharmony_ci struct vdpa_callback *cb) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci pdsv->vqs[qid].event_cb = *cb; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic irqreturn_t pds_vdpa_isr(int irq, void *data) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct pds_vdpa_vq_info *vq; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci vq = data; 11162306a36Sopenharmony_ci if (vq->event_cb.callback) 11262306a36Sopenharmony_ci vq->event_cb.callback(vq->event_cb.private); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return IRQ_HANDLED; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void pds_vdpa_release_irq(struct pds_vdpa_device *pdsv, int qid) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci if (pdsv->vqs[qid].irq == VIRTIO_MSI_NO_VECTOR) 12062306a36Sopenharmony_ci return; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci free_irq(pdsv->vqs[qid].irq, &pdsv->vqs[qid]); 12362306a36Sopenharmony_ci pdsv->vqs[qid].irq = VIRTIO_MSI_NO_VECTOR; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void pds_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, u16 qid, bool ready) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 12962306a36Sopenharmony_ci struct device *dev = &pdsv->vdpa_dev.dev; 13062306a36Sopenharmony_ci u64 driver_features; 13162306a36Sopenharmony_ci u16 invert_idx = 0; 13262306a36Sopenharmony_ci int err; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci dev_dbg(dev, "%s: qid %d ready %d => %d\n", 13562306a36Sopenharmony_ci __func__, qid, pdsv->vqs[qid].ready, ready); 13662306a36Sopenharmony_ci if (ready == pdsv->vqs[qid].ready) 13762306a36Sopenharmony_ci return; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci driver_features = pds_vdpa_get_driver_features(vdpa_dev); 14062306a36Sopenharmony_ci if (driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) 14162306a36Sopenharmony_ci invert_idx = PDS_VDPA_PACKED_INVERT_IDX; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (ready) { 14462306a36Sopenharmony_ci /* Pass vq setup info to DSC using adminq to gather up and 14562306a36Sopenharmony_ci * send all info at once so FW can do its full set up in 14662306a36Sopenharmony_ci * one easy operation 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci err = pds_vdpa_cmd_init_vq(pdsv, qid, invert_idx, &pdsv->vqs[qid]); 14962306a36Sopenharmony_ci if (err) { 15062306a36Sopenharmony_ci dev_err(dev, "Failed to init vq %d: %pe\n", 15162306a36Sopenharmony_ci qid, ERR_PTR(err)); 15262306a36Sopenharmony_ci ready = false; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci } else { 15562306a36Sopenharmony_ci err = pds_vdpa_cmd_reset_vq(pdsv, qid, invert_idx, &pdsv->vqs[qid]); 15662306a36Sopenharmony_ci if (err) 15762306a36Sopenharmony_ci dev_err(dev, "%s: reset_vq failed qid %d: %pe\n", 15862306a36Sopenharmony_ci __func__, qid, ERR_PTR(err)); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci pdsv->vqs[qid].ready = ready; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic bool pds_vdpa_get_vq_ready(struct vdpa_device *vdpa_dev, u16 qid) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return pdsv->vqs[qid].ready; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int pds_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid, 17262306a36Sopenharmony_ci const struct vdpa_vq_state *state) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 17562306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 17662306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 17762306a36Sopenharmony_ci u64 driver_features; 17862306a36Sopenharmony_ci u16 avail; 17962306a36Sopenharmony_ci u16 used; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (pdsv->vqs[qid].ready) { 18262306a36Sopenharmony_ci dev_err(dev, "Setting device position is denied while vq is enabled\n"); 18362306a36Sopenharmony_ci return -EINVAL; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci driver_features = pds_vdpa_get_driver_features(vdpa_dev); 18762306a36Sopenharmony_ci if (driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) { 18862306a36Sopenharmony_ci avail = state->packed.last_avail_idx | 18962306a36Sopenharmony_ci (state->packed.last_avail_counter << 15); 19062306a36Sopenharmony_ci used = state->packed.last_used_idx | 19162306a36Sopenharmony_ci (state->packed.last_used_counter << 15); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* The avail and used index are stored with the packed wrap 19462306a36Sopenharmony_ci * counter bit inverted. This way, in case set_vq_state is 19562306a36Sopenharmony_ci * not called, the initial value can be set to zero prior to 19662306a36Sopenharmony_ci * feature negotiation, and it is good for both packed and 19762306a36Sopenharmony_ci * split vq. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci avail ^= PDS_VDPA_PACKED_INVERT_IDX; 20062306a36Sopenharmony_ci used ^= PDS_VDPA_PACKED_INVERT_IDX; 20162306a36Sopenharmony_ci } else { 20262306a36Sopenharmony_ci avail = state->split.avail_index; 20362306a36Sopenharmony_ci /* state->split does not provide a used_index: 20462306a36Sopenharmony_ci * the vq will be set to "empty" here, and the vq will read 20562306a36Sopenharmony_ci * the current used index the next time the vq is kicked. 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci used = avail; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (used != avail) { 21162306a36Sopenharmony_ci dev_dbg(dev, "Setting used equal to avail, for interoperability\n"); 21262306a36Sopenharmony_ci used = avail; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci pdsv->vqs[qid].avail_idx = avail; 21662306a36Sopenharmony_ci pdsv->vqs[qid].used_idx = used; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int pds_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid, 22262306a36Sopenharmony_ci struct vdpa_vq_state *state) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 22562306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 22662306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 22762306a36Sopenharmony_ci u64 driver_features; 22862306a36Sopenharmony_ci u16 avail; 22962306a36Sopenharmony_ci u16 used; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (pdsv->vqs[qid].ready) { 23262306a36Sopenharmony_ci dev_err(dev, "Getting device position is denied while vq is enabled\n"); 23362306a36Sopenharmony_ci return -EINVAL; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci avail = pdsv->vqs[qid].avail_idx; 23762306a36Sopenharmony_ci used = pdsv->vqs[qid].used_idx; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci driver_features = pds_vdpa_get_driver_features(vdpa_dev); 24062306a36Sopenharmony_ci if (driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) { 24162306a36Sopenharmony_ci avail ^= PDS_VDPA_PACKED_INVERT_IDX; 24262306a36Sopenharmony_ci used ^= PDS_VDPA_PACKED_INVERT_IDX; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci state->packed.last_avail_idx = avail & 0x7fff; 24562306a36Sopenharmony_ci state->packed.last_avail_counter = avail >> 15; 24662306a36Sopenharmony_ci state->packed.last_used_idx = used & 0x7fff; 24762306a36Sopenharmony_ci state->packed.last_used_counter = used >> 15; 24862306a36Sopenharmony_ci } else { 24962306a36Sopenharmony_ci state->split.avail_index = avail; 25062306a36Sopenharmony_ci /* state->split does not provide a used_index. */ 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic struct vdpa_notification_area 25762306a36Sopenharmony_cipds_vdpa_get_vq_notification(struct vdpa_device *vdpa_dev, u16 qid) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 26062306a36Sopenharmony_ci struct virtio_pci_modern_device *vd_mdev; 26162306a36Sopenharmony_ci struct vdpa_notification_area area; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci area.addr = pdsv->vqs[qid].notify_pa; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci vd_mdev = &pdsv->vdpa_aux->vd_mdev; 26662306a36Sopenharmony_ci if (!vd_mdev->notify_offset_multiplier) 26762306a36Sopenharmony_ci area.size = PDS_PAGE_SIZE; 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci area.size = vd_mdev->notify_offset_multiplier; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return area; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int pds_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev, u16 qid) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return pdsv->vqs[qid].irq; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic u32 pds_vdpa_get_vq_align(struct vdpa_device *vdpa_dev) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci return PDS_PAGE_SIZE; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic u32 pds_vdpa_get_vq_group(struct vdpa_device *vdpa_dev, u16 idx) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic u64 pds_vdpa_get_device_features(struct vdpa_device *vdpa_dev) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return pdsv->supported_features; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int pds_vdpa_set_driver_features(struct vdpa_device *vdpa_dev, u64 features) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 30162306a36Sopenharmony_ci struct device *dev = &pdsv->vdpa_dev.dev; 30262306a36Sopenharmony_ci u64 driver_features; 30362306a36Sopenharmony_ci u64 nego_features; 30462306a36Sopenharmony_ci u64 hw_features; 30562306a36Sopenharmony_ci u64 missing; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) { 30862306a36Sopenharmony_ci dev_err(dev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n"); 30962306a36Sopenharmony_ci return -EOPNOTSUPP; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Check for valid feature bits */ 31362306a36Sopenharmony_ci nego_features = features & pdsv->supported_features; 31462306a36Sopenharmony_ci missing = features & ~nego_features; 31562306a36Sopenharmony_ci if (missing) { 31662306a36Sopenharmony_ci dev_err(dev, "Can't support all requested features in %#llx, missing %#llx features\n", 31762306a36Sopenharmony_ci features, missing); 31862306a36Sopenharmony_ci return -EOPNOTSUPP; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci driver_features = pds_vdpa_get_driver_features(vdpa_dev); 32262306a36Sopenharmony_ci pdsv->negotiated_features = nego_features; 32362306a36Sopenharmony_ci dev_dbg(dev, "%s: %#llx => %#llx\n", 32462306a36Sopenharmony_ci __func__, driver_features, nego_features); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* if we're faking the F_MAC, strip it before writing to device */ 32762306a36Sopenharmony_ci hw_features = le64_to_cpu(pdsv->vdpa_aux->ident.hw_features); 32862306a36Sopenharmony_ci if (!(hw_features & BIT_ULL(VIRTIO_NET_F_MAC))) 32962306a36Sopenharmony_ci nego_features &= ~BIT_ULL(VIRTIO_NET_F_MAC); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (driver_features == nego_features) 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci vp_modern_set_features(&pdsv->vdpa_aux->vd_mdev, nego_features); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic u64 pds_vdpa_get_driver_features(struct vdpa_device *vdpa_dev) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return pdsv->negotiated_features; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void pds_vdpa_set_config_cb(struct vdpa_device *vdpa_dev, 34762306a36Sopenharmony_ci struct vdpa_callback *cb) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci pdsv->config_cb.callback = cb->callback; 35262306a36Sopenharmony_ci pdsv->config_cb.private = cb->private; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic u16 pds_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* qemu has assert() that vq_num_max <= VIRTQUEUE_MAX_SIZE (1024) */ 36062306a36Sopenharmony_ci return min_t(u16, 1024, BIT(le16_to_cpu(pdsv->vdpa_aux->ident.max_qlen))); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic u32 pds_vdpa_get_device_id(struct vdpa_device *vdpa_dev) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci return VIRTIO_ID_NET; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic u32 pds_vdpa_get_vendor_id(struct vdpa_device *vdpa_dev) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci return PCI_VENDOR_ID_PENSANDO; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic u8 pds_vdpa_get_status(struct vdpa_device *vdpa_dev) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return vp_modern_get_status(&pdsv->vdpa_aux->vd_mdev); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int pds_vdpa_request_irqs(struct pds_vdpa_device *pdsv) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct pci_dev *pdev = pdsv->vdpa_aux->padev->vf_pdev; 38362306a36Sopenharmony_ci struct pds_vdpa_aux *vdpa_aux = pdsv->vdpa_aux; 38462306a36Sopenharmony_ci struct device *dev = &pdsv->vdpa_dev.dev; 38562306a36Sopenharmony_ci int max_vq, nintrs, qid, err; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci max_vq = vdpa_aux->vdpa_mdev.max_supported_vqs; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci nintrs = pci_alloc_irq_vectors(pdev, max_vq, max_vq, PCI_IRQ_MSIX); 39062306a36Sopenharmony_ci if (nintrs < 0) { 39162306a36Sopenharmony_ci dev_err(dev, "Couldn't get %d msix vectors: %pe\n", 39262306a36Sopenharmony_ci max_vq, ERR_PTR(nintrs)); 39362306a36Sopenharmony_ci return nintrs; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci for (qid = 0; qid < pdsv->num_vqs; ++qid) { 39762306a36Sopenharmony_ci int irq = pci_irq_vector(pdev, qid); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci snprintf(pdsv->vqs[qid].irq_name, sizeof(pdsv->vqs[qid].irq_name), 40062306a36Sopenharmony_ci "vdpa-%s-%d", dev_name(dev), qid); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci err = request_irq(irq, pds_vdpa_isr, 0, 40362306a36Sopenharmony_ci pdsv->vqs[qid].irq_name, 40462306a36Sopenharmony_ci &pdsv->vqs[qid]); 40562306a36Sopenharmony_ci if (err) { 40662306a36Sopenharmony_ci dev_err(dev, "%s: no irq for qid %d: %pe\n", 40762306a36Sopenharmony_ci __func__, qid, ERR_PTR(err)); 40862306a36Sopenharmony_ci goto err_release; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci pdsv->vqs[qid].irq = irq; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci vdpa_aux->nintrs = nintrs; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cierr_release: 41962306a36Sopenharmony_ci while (qid--) 42062306a36Sopenharmony_ci pds_vdpa_release_irq(pdsv, qid); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci vdpa_aux->nintrs = 0; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return err; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic void pds_vdpa_release_irqs(struct pds_vdpa_device *pdsv) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct pci_dev *pdev = pdsv->vdpa_aux->padev->vf_pdev; 43262306a36Sopenharmony_ci struct pds_vdpa_aux *vdpa_aux = pdsv->vdpa_aux; 43362306a36Sopenharmony_ci int qid; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (!vdpa_aux->nintrs) 43662306a36Sopenharmony_ci return; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci for (qid = 0; qid < pdsv->num_vqs; qid++) 43962306a36Sopenharmony_ci pds_vdpa_release_irq(pdsv, qid); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci vdpa_aux->nintrs = 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic void pds_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 44962306a36Sopenharmony_ci struct device *dev = &pdsv->vdpa_dev.dev; 45062306a36Sopenharmony_ci u8 old_status; 45162306a36Sopenharmony_ci int i; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci old_status = pds_vdpa_get_status(vdpa_dev); 45462306a36Sopenharmony_ci dev_dbg(dev, "%s: old %#x new %#x\n", __func__, old_status, status); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (status & ~old_status & VIRTIO_CONFIG_S_DRIVER_OK) { 45762306a36Sopenharmony_ci if (pds_vdpa_request_irqs(pdsv)) 45862306a36Sopenharmony_ci status = old_status | VIRTIO_CONFIG_S_FAILED; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci pds_vdpa_cmd_set_status(pdsv, status); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (status == 0) { 46462306a36Sopenharmony_ci struct vdpa_callback null_cb = { }; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci pds_vdpa_set_config_cb(vdpa_dev, &null_cb); 46762306a36Sopenharmony_ci pds_vdpa_cmd_reset(pdsv); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci for (i = 0; i < pdsv->num_vqs; i++) { 47062306a36Sopenharmony_ci pdsv->vqs[i].avail_idx = 0; 47162306a36Sopenharmony_ci pdsv->vqs[i].used_idx = 0; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci pds_vdpa_cmd_set_mac(pdsv, pdsv->mac); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (status & ~old_status & VIRTIO_CONFIG_S_FEATURES_OK) { 47862306a36Sopenharmony_ci for (i = 0; i < pdsv->num_vqs; i++) { 47962306a36Sopenharmony_ci pdsv->vqs[i].notify = 48062306a36Sopenharmony_ci vp_modern_map_vq_notify(&pdsv->vdpa_aux->vd_mdev, 48162306a36Sopenharmony_ci i, &pdsv->vqs[i].notify_pa); 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (old_status & ~status & VIRTIO_CONFIG_S_DRIVER_OK) 48662306a36Sopenharmony_ci pds_vdpa_release_irqs(pdsv); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void pds_vdpa_init_vqs_entry(struct pds_vdpa_device *pdsv, int qid, 49062306a36Sopenharmony_ci void __iomem *notify) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci memset(&pdsv->vqs[qid], 0, sizeof(pdsv->vqs[0])); 49362306a36Sopenharmony_ci pdsv->vqs[qid].qid = qid; 49462306a36Sopenharmony_ci pdsv->vqs[qid].pdsv = pdsv; 49562306a36Sopenharmony_ci pdsv->vqs[qid].ready = false; 49662306a36Sopenharmony_ci pdsv->vqs[qid].irq = VIRTIO_MSI_NO_VECTOR; 49762306a36Sopenharmony_ci pdsv->vqs[qid].notify = notify; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int pds_vdpa_reset(struct vdpa_device *vdpa_dev) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 50362306a36Sopenharmony_ci struct device *dev; 50462306a36Sopenharmony_ci int err = 0; 50562306a36Sopenharmony_ci u8 status; 50662306a36Sopenharmony_ci int i; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci dev = &pdsv->vdpa_aux->padev->aux_dev.dev; 50962306a36Sopenharmony_ci status = pds_vdpa_get_status(vdpa_dev); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (status == 0) 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 51562306a36Sopenharmony_ci /* Reset the vqs */ 51662306a36Sopenharmony_ci for (i = 0; i < pdsv->num_vqs && !err; i++) { 51762306a36Sopenharmony_ci err = pds_vdpa_cmd_reset_vq(pdsv, i, 0, &pdsv->vqs[i]); 51862306a36Sopenharmony_ci if (err) 51962306a36Sopenharmony_ci dev_err(dev, "%s: reset_vq failed qid %d: %pe\n", 52062306a36Sopenharmony_ci __func__, i, ERR_PTR(err)); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci pds_vdpa_set_status(vdpa_dev, 0); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 52762306a36Sopenharmony_ci /* Reset the vq info */ 52862306a36Sopenharmony_ci for (i = 0; i < pdsv->num_vqs && !err; i++) 52962306a36Sopenharmony_ci pds_vdpa_init_vqs_entry(pdsv, i, pdsv->vqs[i].notify); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic size_t pds_vdpa_get_config_size(struct vdpa_device *vdpa_dev) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return sizeof(struct virtio_net_config); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void pds_vdpa_get_config(struct vdpa_device *vdpa_dev, 54162306a36Sopenharmony_ci unsigned int offset, 54262306a36Sopenharmony_ci void *buf, unsigned int len) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 54562306a36Sopenharmony_ci void __iomem *device; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (offset + len > sizeof(struct virtio_net_config)) { 54862306a36Sopenharmony_ci WARN(true, "%s: bad read, offset %d len %d\n", __func__, offset, len); 54962306a36Sopenharmony_ci return; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci device = pdsv->vdpa_aux->vd_mdev.device; 55362306a36Sopenharmony_ci memcpy_fromio(buf, device + offset, len); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic void pds_vdpa_set_config(struct vdpa_device *vdpa_dev, 55762306a36Sopenharmony_ci unsigned int offset, const void *buf, 55862306a36Sopenharmony_ci unsigned int len) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 56162306a36Sopenharmony_ci void __iomem *device; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (offset + len > sizeof(struct virtio_net_config)) { 56462306a36Sopenharmony_ci WARN(true, "%s: bad read, offset %d len %d\n", __func__, offset, len); 56562306a36Sopenharmony_ci return; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci device = pdsv->vdpa_aux->vd_mdev.device; 56962306a36Sopenharmony_ci memcpy_toio(device + offset, buf, len); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic const struct vdpa_config_ops pds_vdpa_ops = { 57362306a36Sopenharmony_ci .set_vq_address = pds_vdpa_set_vq_address, 57462306a36Sopenharmony_ci .set_vq_num = pds_vdpa_set_vq_num, 57562306a36Sopenharmony_ci .kick_vq = pds_vdpa_kick_vq, 57662306a36Sopenharmony_ci .set_vq_cb = pds_vdpa_set_vq_cb, 57762306a36Sopenharmony_ci .set_vq_ready = pds_vdpa_set_vq_ready, 57862306a36Sopenharmony_ci .get_vq_ready = pds_vdpa_get_vq_ready, 57962306a36Sopenharmony_ci .set_vq_state = pds_vdpa_set_vq_state, 58062306a36Sopenharmony_ci .get_vq_state = pds_vdpa_get_vq_state, 58162306a36Sopenharmony_ci .get_vq_notification = pds_vdpa_get_vq_notification, 58262306a36Sopenharmony_ci .get_vq_irq = pds_vdpa_get_vq_irq, 58362306a36Sopenharmony_ci .get_vq_align = pds_vdpa_get_vq_align, 58462306a36Sopenharmony_ci .get_vq_group = pds_vdpa_get_vq_group, 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci .get_device_features = pds_vdpa_get_device_features, 58762306a36Sopenharmony_ci .set_driver_features = pds_vdpa_set_driver_features, 58862306a36Sopenharmony_ci .get_driver_features = pds_vdpa_get_driver_features, 58962306a36Sopenharmony_ci .set_config_cb = pds_vdpa_set_config_cb, 59062306a36Sopenharmony_ci .get_vq_num_max = pds_vdpa_get_vq_num_max, 59162306a36Sopenharmony_ci .get_device_id = pds_vdpa_get_device_id, 59262306a36Sopenharmony_ci .get_vendor_id = pds_vdpa_get_vendor_id, 59362306a36Sopenharmony_ci .get_status = pds_vdpa_get_status, 59462306a36Sopenharmony_ci .set_status = pds_vdpa_set_status, 59562306a36Sopenharmony_ci .reset = pds_vdpa_reset, 59662306a36Sopenharmony_ci .get_config_size = pds_vdpa_get_config_size, 59762306a36Sopenharmony_ci .get_config = pds_vdpa_get_config, 59862306a36Sopenharmony_ci .set_config = pds_vdpa_set_config, 59962306a36Sopenharmony_ci}; 60062306a36Sopenharmony_cistatic struct virtio_device_id pds_vdpa_id_table[] = { 60162306a36Sopenharmony_ci {VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID}, 60262306a36Sopenharmony_ci {0}, 60362306a36Sopenharmony_ci}; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, 60662306a36Sopenharmony_ci const struct vdpa_dev_set_config *add_config) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct pds_vdpa_aux *vdpa_aux; 60962306a36Sopenharmony_ci struct pds_vdpa_device *pdsv; 61062306a36Sopenharmony_ci struct vdpa_mgmt_dev *mgmt; 61162306a36Sopenharmony_ci u16 fw_max_vqs, vq_pairs; 61262306a36Sopenharmony_ci struct device *dma_dev; 61362306a36Sopenharmony_ci struct pci_dev *pdev; 61462306a36Sopenharmony_ci struct device *dev; 61562306a36Sopenharmony_ci int err; 61662306a36Sopenharmony_ci int i; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci vdpa_aux = container_of(mdev, struct pds_vdpa_aux, vdpa_mdev); 61962306a36Sopenharmony_ci dev = &vdpa_aux->padev->aux_dev.dev; 62062306a36Sopenharmony_ci mgmt = &vdpa_aux->vdpa_mdev; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (vdpa_aux->pdsv) { 62362306a36Sopenharmony_ci dev_warn(dev, "Multiple vDPA devices on a VF is not supported.\n"); 62462306a36Sopenharmony_ci return -EOPNOTSUPP; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci pdsv = vdpa_alloc_device(struct pds_vdpa_device, vdpa_dev, 62862306a36Sopenharmony_ci dev, &pds_vdpa_ops, 1, 1, name, false); 62962306a36Sopenharmony_ci if (IS_ERR(pdsv)) { 63062306a36Sopenharmony_ci dev_err(dev, "Failed to allocate vDPA structure: %pe\n", pdsv); 63162306a36Sopenharmony_ci return PTR_ERR(pdsv); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci vdpa_aux->pdsv = pdsv; 63562306a36Sopenharmony_ci pdsv->vdpa_aux = vdpa_aux; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci pdev = vdpa_aux->padev->vf_pdev; 63862306a36Sopenharmony_ci dma_dev = &pdev->dev; 63962306a36Sopenharmony_ci pdsv->vdpa_dev.dma_dev = dma_dev; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci pdsv->supported_features = mgmt->supported_features; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 64462306a36Sopenharmony_ci u64 unsupp_features = 64562306a36Sopenharmony_ci add_config->device_features & ~pdsv->supported_features; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (unsupp_features) { 64862306a36Sopenharmony_ci dev_err(dev, "Unsupported features: %#llx\n", unsupp_features); 64962306a36Sopenharmony_ci err = -EOPNOTSUPP; 65062306a36Sopenharmony_ci goto err_unmap; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci pdsv->supported_features = add_config->device_features; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci err = pds_vdpa_cmd_reset(pdsv); 65762306a36Sopenharmony_ci if (err) { 65862306a36Sopenharmony_ci dev_err(dev, "Failed to reset hw: %pe\n", ERR_PTR(err)); 65962306a36Sopenharmony_ci goto err_unmap; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci err = pds_vdpa_init_hw(pdsv); 66362306a36Sopenharmony_ci if (err) { 66462306a36Sopenharmony_ci dev_err(dev, "Failed to init hw: %pe\n", ERR_PTR(err)); 66562306a36Sopenharmony_ci goto err_unmap; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci fw_max_vqs = le16_to_cpu(pdsv->vdpa_aux->ident.max_vqs); 66962306a36Sopenharmony_ci vq_pairs = fw_max_vqs / 2; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* Make sure we have the queues being requested */ 67262306a36Sopenharmony_ci if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MAX_VQP)) 67362306a36Sopenharmony_ci vq_pairs = add_config->net.max_vq_pairs; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci pdsv->num_vqs = 2 * vq_pairs; 67662306a36Sopenharmony_ci if (pdsv->supported_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)) 67762306a36Sopenharmony_ci pdsv->num_vqs++; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (pdsv->num_vqs > fw_max_vqs) { 68062306a36Sopenharmony_ci dev_err(dev, "%s: queue count requested %u greater than max %u\n", 68162306a36Sopenharmony_ci __func__, pdsv->num_vqs, fw_max_vqs); 68262306a36Sopenharmony_ci err = -ENOSPC; 68362306a36Sopenharmony_ci goto err_unmap; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (pdsv->num_vqs != fw_max_vqs) { 68762306a36Sopenharmony_ci err = pds_vdpa_cmd_set_max_vq_pairs(pdsv, vq_pairs); 68862306a36Sopenharmony_ci if (err) { 68962306a36Sopenharmony_ci dev_err(dev, "Failed to set max_vq_pairs: %pe\n", 69062306a36Sopenharmony_ci ERR_PTR(err)); 69162306a36Sopenharmony_ci goto err_unmap; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Set a mac, either from the user config if provided 69662306a36Sopenharmony_ci * or use the device's mac if not 00:..:00 69762306a36Sopenharmony_ci * or set a random mac 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR)) { 70062306a36Sopenharmony_ci ether_addr_copy(pdsv->mac, add_config->net.mac); 70162306a36Sopenharmony_ci } else { 70262306a36Sopenharmony_ci struct virtio_net_config __iomem *vc; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci vc = pdsv->vdpa_aux->vd_mdev.device; 70562306a36Sopenharmony_ci memcpy_fromio(pdsv->mac, vc->mac, sizeof(pdsv->mac)); 70662306a36Sopenharmony_ci if (is_zero_ether_addr(pdsv->mac) && 70762306a36Sopenharmony_ci (pdsv->supported_features & BIT_ULL(VIRTIO_NET_F_MAC))) { 70862306a36Sopenharmony_ci eth_random_addr(pdsv->mac); 70962306a36Sopenharmony_ci dev_info(dev, "setting random mac %pM\n", pdsv->mac); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci pds_vdpa_cmd_set_mac(pdsv, pdsv->mac); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci for (i = 0; i < pdsv->num_vqs; i++) { 71562306a36Sopenharmony_ci void __iomem *notify; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci notify = vp_modern_map_vq_notify(&pdsv->vdpa_aux->vd_mdev, 71862306a36Sopenharmony_ci i, &pdsv->vqs[i].notify_pa); 71962306a36Sopenharmony_ci pds_vdpa_init_vqs_entry(pdsv, i, notify); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci pdsv->vdpa_dev.mdev = &vdpa_aux->vdpa_mdev; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci err = pds_vdpa_register_event_handler(pdsv); 72562306a36Sopenharmony_ci if (err) { 72662306a36Sopenharmony_ci dev_err(dev, "Failed to register for PDS events: %pe\n", ERR_PTR(err)); 72762306a36Sopenharmony_ci goto err_unmap; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* We use the _vdpa_register_device() call rather than the 73162306a36Sopenharmony_ci * vdpa_register_device() to avoid a deadlock because our 73262306a36Sopenharmony_ci * dev_add() is called with the vdpa_dev_lock already set 73362306a36Sopenharmony_ci * by vdpa_nl_cmd_dev_add_set_doit() 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci err = _vdpa_register_device(&pdsv->vdpa_dev, pdsv->num_vqs); 73662306a36Sopenharmony_ci if (err) { 73762306a36Sopenharmony_ci dev_err(dev, "Failed to register to vDPA bus: %pe\n", ERR_PTR(err)); 73862306a36Sopenharmony_ci goto err_unevent; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci pds_vdpa_debugfs_add_vdpadev(vdpa_aux); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci return 0; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cierr_unevent: 74662306a36Sopenharmony_ci pds_vdpa_unregister_event_handler(pdsv); 74762306a36Sopenharmony_cierr_unmap: 74862306a36Sopenharmony_ci put_device(&pdsv->vdpa_dev.dev); 74962306a36Sopenharmony_ci vdpa_aux->pdsv = NULL; 75062306a36Sopenharmony_ci return err; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic void pds_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, 75462306a36Sopenharmony_ci struct vdpa_device *vdpa_dev) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); 75762306a36Sopenharmony_ci struct pds_vdpa_aux *vdpa_aux; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci pds_vdpa_unregister_event_handler(pdsv); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci vdpa_aux = container_of(mdev, struct pds_vdpa_aux, vdpa_mdev); 76262306a36Sopenharmony_ci _vdpa_unregister_device(vdpa_dev); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci pds_vdpa_cmd_reset(vdpa_aux->pdsv); 76562306a36Sopenharmony_ci pds_vdpa_debugfs_reset_vdpadev(vdpa_aux); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci vdpa_aux->pdsv = NULL; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci dev_info(&vdpa_aux->padev->aux_dev.dev, "Removed vdpa device\n"); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic const struct vdpa_mgmtdev_ops pds_vdpa_mgmt_dev_ops = { 77362306a36Sopenharmony_ci .dev_add = pds_vdpa_dev_add, 77462306a36Sopenharmony_ci .dev_del = pds_vdpa_dev_del 77562306a36Sopenharmony_ci}; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ciint pds_vdpa_get_mgmt_info(struct pds_vdpa_aux *vdpa_aux) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 78062306a36Sopenharmony_ci .vdpa_ident.opcode = PDS_VDPA_CMD_IDENT, 78162306a36Sopenharmony_ci .vdpa_ident.vf_id = cpu_to_le16(vdpa_aux->vf_id), 78262306a36Sopenharmony_ci }; 78362306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 78462306a36Sopenharmony_ci struct vdpa_mgmt_dev *mgmt; 78562306a36Sopenharmony_ci struct pci_dev *pf_pdev; 78662306a36Sopenharmony_ci struct device *pf_dev; 78762306a36Sopenharmony_ci struct pci_dev *pdev; 78862306a36Sopenharmony_ci dma_addr_t ident_pa; 78962306a36Sopenharmony_ci struct device *dev; 79062306a36Sopenharmony_ci u16 dev_intrs; 79162306a36Sopenharmony_ci u16 max_vqs; 79262306a36Sopenharmony_ci int err; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci dev = &vdpa_aux->padev->aux_dev.dev; 79562306a36Sopenharmony_ci pdev = vdpa_aux->padev->vf_pdev; 79662306a36Sopenharmony_ci mgmt = &vdpa_aux->vdpa_mdev; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* Get resource info through the PF's adminq. It is a block of info, 79962306a36Sopenharmony_ci * so we need to map some memory for PF to make available to the 80062306a36Sopenharmony_ci * firmware for writing the data. 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_ci pf_pdev = pci_physfn(vdpa_aux->padev->vf_pdev); 80362306a36Sopenharmony_ci pf_dev = &pf_pdev->dev; 80462306a36Sopenharmony_ci ident_pa = dma_map_single(pf_dev, &vdpa_aux->ident, 80562306a36Sopenharmony_ci sizeof(vdpa_aux->ident), DMA_FROM_DEVICE); 80662306a36Sopenharmony_ci if (dma_mapping_error(pf_dev, ident_pa)) { 80762306a36Sopenharmony_ci dev_err(dev, "Failed to map ident space\n"); 80862306a36Sopenharmony_ci return -ENOMEM; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci cmd.vdpa_ident.ident_pa = cpu_to_le64(ident_pa); 81262306a36Sopenharmony_ci cmd.vdpa_ident.len = cpu_to_le32(sizeof(vdpa_aux->ident)); 81362306a36Sopenharmony_ci err = pds_client_adminq_cmd(vdpa_aux->padev, &cmd, 81462306a36Sopenharmony_ci sizeof(cmd.vdpa_ident), &comp, 0); 81562306a36Sopenharmony_ci dma_unmap_single(pf_dev, ident_pa, 81662306a36Sopenharmony_ci sizeof(vdpa_aux->ident), DMA_FROM_DEVICE); 81762306a36Sopenharmony_ci if (err) { 81862306a36Sopenharmony_ci dev_err(dev, "Failed to ident hw, status %d: %pe\n", 81962306a36Sopenharmony_ci comp.status, ERR_PTR(err)); 82062306a36Sopenharmony_ci return err; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci max_vqs = le16_to_cpu(vdpa_aux->ident.max_vqs); 82462306a36Sopenharmony_ci dev_intrs = pci_msix_vec_count(pdev); 82562306a36Sopenharmony_ci dev_dbg(dev, "ident.max_vqs %d dev_intrs %d\n", max_vqs, dev_intrs); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci max_vqs = min_t(u16, dev_intrs, max_vqs); 82862306a36Sopenharmony_ci mgmt->max_supported_vqs = min_t(u16, PDS_VDPA_MAX_QUEUES, max_vqs); 82962306a36Sopenharmony_ci vdpa_aux->nintrs = 0; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci mgmt->ops = &pds_vdpa_mgmt_dev_ops; 83262306a36Sopenharmony_ci mgmt->id_table = pds_vdpa_id_table; 83362306a36Sopenharmony_ci mgmt->device = dev; 83462306a36Sopenharmony_ci mgmt->supported_features = le64_to_cpu(vdpa_aux->ident.hw_features); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* advertise F_MAC even if the device doesn't */ 83762306a36Sopenharmony_ci mgmt->supported_features |= BIT_ULL(VIRTIO_NET_F_MAC); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci mgmt->config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR); 84062306a36Sopenharmony_ci mgmt->config_attr_mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP); 84162306a36Sopenharmony_ci mgmt->config_attr_mask |= BIT_ULL(VDPA_ATTR_DEV_FEATURES); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 845