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