162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright(c) 2023 Advanced Micro Devices, Inc */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/vdpa.h> 562306a36Sopenharmony_ci#include <linux/virtio_pci_modern.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/pds/pds_common.h> 862306a36Sopenharmony_ci#include <linux/pds/pds_core_if.h> 962306a36Sopenharmony_ci#include <linux/pds/pds_adminq.h> 1062306a36Sopenharmony_ci#include <linux/pds/pds_auxbus.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "vdpa_dev.h" 1362306a36Sopenharmony_ci#include "aux_drv.h" 1462306a36Sopenharmony_ci#include "cmds.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciint pds_vdpa_init_hw(struct pds_vdpa_device *pdsv) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 1962306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 2062306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 2162306a36Sopenharmony_ci .vdpa_init.opcode = PDS_VDPA_CMD_INIT, 2262306a36Sopenharmony_ci .vdpa_init.vdpa_index = pdsv->vdpa_index, 2362306a36Sopenharmony_ci .vdpa_init.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 2462306a36Sopenharmony_ci }; 2562306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 2662306a36Sopenharmony_ci int err; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci /* Initialize the vdpa/virtio device */ 2962306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa_init), 3062306a36Sopenharmony_ci &comp, 0); 3162306a36Sopenharmony_ci if (err) 3262306a36Sopenharmony_ci dev_dbg(dev, "Failed to init hw, status %d: %pe\n", 3362306a36Sopenharmony_ci comp.status, ERR_PTR(err)); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return err; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint pds_vdpa_cmd_reset(struct pds_vdpa_device *pdsv) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 4162306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 4262306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 4362306a36Sopenharmony_ci .vdpa.opcode = PDS_VDPA_CMD_RESET, 4462306a36Sopenharmony_ci .vdpa.vdpa_index = pdsv->vdpa_index, 4562306a36Sopenharmony_ci .vdpa.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 4662306a36Sopenharmony_ci }; 4762306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 4862306a36Sopenharmony_ci int err; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa), &comp, 0); 5162306a36Sopenharmony_ci if (err) 5262306a36Sopenharmony_ci dev_dbg(dev, "Failed to reset hw, status %d: %pe\n", 5362306a36Sopenharmony_ci comp.status, ERR_PTR(err)); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return err; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciint pds_vdpa_cmd_set_status(struct pds_vdpa_device *pdsv, u8 status) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 6162306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 6262306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 6362306a36Sopenharmony_ci .vdpa_status.opcode = PDS_VDPA_CMD_STATUS_UPDATE, 6462306a36Sopenharmony_ci .vdpa_status.vdpa_index = pdsv->vdpa_index, 6562306a36Sopenharmony_ci .vdpa_status.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 6662306a36Sopenharmony_ci .vdpa_status.status = status, 6762306a36Sopenharmony_ci }; 6862306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 6962306a36Sopenharmony_ci int err; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa_status), &comp, 0); 7262306a36Sopenharmony_ci if (err) 7362306a36Sopenharmony_ci dev_dbg(dev, "Failed to set status to %#x, error status %d: %pe\n", 7462306a36Sopenharmony_ci status, comp.status, ERR_PTR(err)); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return err; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciint pds_vdpa_cmd_set_mac(struct pds_vdpa_device *pdsv, u8 *mac) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 8262306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 8362306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 8462306a36Sopenharmony_ci .vdpa_setattr.opcode = PDS_VDPA_CMD_SET_ATTR, 8562306a36Sopenharmony_ci .vdpa_setattr.vdpa_index = pdsv->vdpa_index, 8662306a36Sopenharmony_ci .vdpa_setattr.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 8762306a36Sopenharmony_ci .vdpa_setattr.attr = PDS_VDPA_ATTR_MAC, 8862306a36Sopenharmony_ci }; 8962306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 9062306a36Sopenharmony_ci int err; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ether_addr_copy(cmd.vdpa_setattr.mac, mac); 9362306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa_setattr), 9462306a36Sopenharmony_ci &comp, 0); 9562306a36Sopenharmony_ci if (err) 9662306a36Sopenharmony_ci dev_dbg(dev, "Failed to set mac address %pM, status %d: %pe\n", 9762306a36Sopenharmony_ci mac, comp.status, ERR_PTR(err)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return err; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciint pds_vdpa_cmd_set_max_vq_pairs(struct pds_vdpa_device *pdsv, u16 max_vqp) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 10562306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 10662306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 10762306a36Sopenharmony_ci .vdpa_setattr.opcode = PDS_VDPA_CMD_SET_ATTR, 10862306a36Sopenharmony_ci .vdpa_setattr.vdpa_index = pdsv->vdpa_index, 10962306a36Sopenharmony_ci .vdpa_setattr.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 11062306a36Sopenharmony_ci .vdpa_setattr.attr = PDS_VDPA_ATTR_MAX_VQ_PAIRS, 11162306a36Sopenharmony_ci .vdpa_setattr.max_vq_pairs = cpu_to_le16(max_vqp), 11262306a36Sopenharmony_ci }; 11362306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 11462306a36Sopenharmony_ci int err; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa_setattr), 11762306a36Sopenharmony_ci &comp, 0); 11862306a36Sopenharmony_ci if (err) 11962306a36Sopenharmony_ci dev_dbg(dev, "Failed to set max vq pairs %u, status %d: %pe\n", 12062306a36Sopenharmony_ci max_vqp, comp.status, ERR_PTR(err)); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return err; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciint pds_vdpa_cmd_init_vq(struct pds_vdpa_device *pdsv, u16 qid, u16 invert_idx, 12662306a36Sopenharmony_ci struct pds_vdpa_vq_info *vq_info) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 12962306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 13062306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 13162306a36Sopenharmony_ci .vdpa_vq_init.opcode = PDS_VDPA_CMD_VQ_INIT, 13262306a36Sopenharmony_ci .vdpa_vq_init.vdpa_index = pdsv->vdpa_index, 13362306a36Sopenharmony_ci .vdpa_vq_init.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 13462306a36Sopenharmony_ci .vdpa_vq_init.qid = cpu_to_le16(qid), 13562306a36Sopenharmony_ci .vdpa_vq_init.len = cpu_to_le16(ilog2(vq_info->q_len)), 13662306a36Sopenharmony_ci .vdpa_vq_init.desc_addr = cpu_to_le64(vq_info->desc_addr), 13762306a36Sopenharmony_ci .vdpa_vq_init.avail_addr = cpu_to_le64(vq_info->avail_addr), 13862306a36Sopenharmony_ci .vdpa_vq_init.used_addr = cpu_to_le64(vq_info->used_addr), 13962306a36Sopenharmony_ci .vdpa_vq_init.intr_index = cpu_to_le16(qid), 14062306a36Sopenharmony_ci .vdpa_vq_init.avail_index = cpu_to_le16(vq_info->avail_idx ^ invert_idx), 14162306a36Sopenharmony_ci .vdpa_vq_init.used_index = cpu_to_le16(vq_info->used_idx ^ invert_idx), 14262306a36Sopenharmony_ci }; 14362306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 14462306a36Sopenharmony_ci int err; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci dev_dbg(dev, "%s: qid %d len %d desc_addr %#llx avail_addr %#llx used_addr %#llx\n", 14762306a36Sopenharmony_ci __func__, qid, ilog2(vq_info->q_len), 14862306a36Sopenharmony_ci vq_info->desc_addr, vq_info->avail_addr, vq_info->used_addr); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa_vq_init), 15162306a36Sopenharmony_ci &comp, 0); 15262306a36Sopenharmony_ci if (err) 15362306a36Sopenharmony_ci dev_dbg(dev, "Failed to init vq %d, status %d: %pe\n", 15462306a36Sopenharmony_ci qid, comp.status, ERR_PTR(err)); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return err; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ciint pds_vdpa_cmd_reset_vq(struct pds_vdpa_device *pdsv, u16 qid, u16 invert_idx, 16062306a36Sopenharmony_ci struct pds_vdpa_vq_info *vq_info) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = pdsv->vdpa_aux->padev; 16362306a36Sopenharmony_ci struct device *dev = &padev->aux_dev.dev; 16462306a36Sopenharmony_ci union pds_core_adminq_cmd cmd = { 16562306a36Sopenharmony_ci .vdpa_vq_reset.opcode = PDS_VDPA_CMD_VQ_RESET, 16662306a36Sopenharmony_ci .vdpa_vq_reset.vdpa_index = pdsv->vdpa_index, 16762306a36Sopenharmony_ci .vdpa_vq_reset.vf_id = cpu_to_le16(pdsv->vdpa_aux->vf_id), 16862306a36Sopenharmony_ci .vdpa_vq_reset.qid = cpu_to_le16(qid), 16962306a36Sopenharmony_ci }; 17062306a36Sopenharmony_ci union pds_core_adminq_comp comp = {}; 17162306a36Sopenharmony_ci int err; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci err = pds_client_adminq_cmd(padev, &cmd, sizeof(cmd.vdpa_vq_reset), 17462306a36Sopenharmony_ci &comp, 0); 17562306a36Sopenharmony_ci if (err) { 17662306a36Sopenharmony_ci dev_dbg(dev, "Failed to reset vq %d, status %d: %pe\n", 17762306a36Sopenharmony_ci qid, comp.status, ERR_PTR(err)); 17862306a36Sopenharmony_ci return err; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci vq_info->avail_idx = le16_to_cpu(comp.vdpa_vq_reset.avail_index) ^ invert_idx; 18262306a36Sopenharmony_ci vq_info->used_idx = le16_to_cpu(comp.vdpa_vq_reset.used_index) ^ invert_idx; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 186