Path: blob/master/drivers/cdx/controller/cdx_controller.c
26444 views
// SPDX-License-Identifier: GPL-2.01/*2* CDX host controller driver for AMD versal-net platform.3*4* Copyright (C) 2022-2023, Advanced Micro Devices, Inc.5*/67#include <linux/mod_devicetable.h>8#include <linux/platform_device.h>9#include <linux/slab.h>10#include <linux/cdx/cdx_bus.h>11#include <linux/irqdomain.h>1213#include "cdx_controller.h"14#include "../cdx.h"15#include "mcdi_functions.h"16#include "mcdi.h"1718static unsigned int cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd)19{20return MCDI_RPC_TIMEOUT;21}2223static void cdx_mcdi_request(struct cdx_mcdi *cdx,24const struct cdx_dword *hdr, size_t hdr_len,25const struct cdx_dword *sdu, size_t sdu_len)26{27if (cdx_rpmsg_send(cdx, hdr, hdr_len, sdu, sdu_len))28dev_err(&cdx->rpdev->dev, "Failed to send rpmsg data\n");29}3031static const struct cdx_mcdi_ops mcdi_ops = {32.mcdi_rpc_timeout = cdx_mcdi_rpc_timeout,33.mcdi_request = cdx_mcdi_request,34};3536static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num)37{38return cdx_mcdi_bus_enable(cdx->priv, bus_num);39}4041static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num)42{43return cdx_mcdi_bus_disable(cdx->priv, bus_num);44}4546void cdx_rpmsg_post_probe(struct cdx_controller *cdx)47{48/* Register CDX controller with CDX bus driver */49if (cdx_register_controller(cdx))50dev_err(cdx->dev, "Failed to register CDX controller\n");51}5253void cdx_rpmsg_pre_remove(struct cdx_controller *cdx)54{55cdx_unregister_controller(cdx);56cdx_mcdi_wait_for_quiescence(cdx->priv, MCDI_RPC_TIMEOUT);57}5859static int cdx_configure_device(struct cdx_controller *cdx,60u8 bus_num, u8 dev_num,61struct cdx_device_config *dev_config)62{63u16 msi_index;64int ret = 0;65u32 data;66u64 addr;6768switch (dev_config->type) {69case CDX_DEV_MSI_CONF:70msi_index = dev_config->msi.msi_index;71data = dev_config->msi.data;72addr = dev_config->msi.addr;7374ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data);75break;76case CDX_DEV_RESET_CONF:77ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num);78break;79case CDX_DEV_BUS_MASTER_CONF:80ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num,81dev_config->bus_master_enable);82break;83case CDX_DEV_MSI_ENABLE:84ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable);85break;86default:87ret = -EINVAL;88}8990return ret;91}9293static int cdx_scan_devices(struct cdx_controller *cdx)94{95struct cdx_mcdi *cdx_mcdi = cdx->priv;96u8 bus_num, dev_num, num_cdx_bus;97int ret;9899/* MCDI FW Read: Fetch the number of CDX buses on this controller */100ret = cdx_mcdi_get_num_buses(cdx_mcdi);101if (ret < 0) {102dev_err(cdx->dev,103"Get number of CDX buses failed: %d\n", ret);104return ret;105}106num_cdx_bus = (u8)ret;107108for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) {109struct device *bus_dev;110u8 num_cdx_dev;111112/* Add the bus on cdx subsystem */113bus_dev = cdx_bus_add(cdx, bus_num);114if (!bus_dev)115continue;116117/* MCDI FW Read: Fetch the number of devices present */118ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num);119if (ret < 0) {120dev_err(cdx->dev,121"Get devices on CDX bus %d failed: %d\n", bus_num, ret);122continue;123}124num_cdx_dev = (u8)ret;125126for (dev_num = 0; dev_num < num_cdx_dev; dev_num++) {127struct cdx_dev_params dev_params;128129/* MCDI FW: Get the device config */130ret = cdx_mcdi_get_dev_config(cdx_mcdi, bus_num,131dev_num, &dev_params);132if (ret) {133dev_err(cdx->dev,134"CDX device config get failed for %d(bus):%d(dev), %d\n",135bus_num, dev_num, ret);136continue;137}138dev_params.cdx = cdx;139dev_params.parent = bus_dev;140141/* Add the device to the cdx bus */142ret = cdx_device_add(&dev_params);143if (ret) {144dev_err(cdx->dev, "registering cdx dev: %d failed: %d\n",145dev_num, ret);146continue;147}148149dev_dbg(cdx->dev, "CDX dev: %d on cdx bus: %d created\n",150dev_num, bus_num);151}152}153154return 0;155}156157static struct cdx_ops cdx_ops = {158.bus_enable = cdx_bus_enable,159.bus_disable = cdx_bus_disable,160.scan = cdx_scan_devices,161.dev_configure = cdx_configure_device,162};163164static int xlnx_cdx_probe(struct platform_device *pdev)165{166struct cdx_controller *cdx;167struct cdx_mcdi *cdx_mcdi;168int ret;169170cdx_mcdi = kzalloc(sizeof(*cdx_mcdi), GFP_KERNEL);171if (!cdx_mcdi)172return -ENOMEM;173174/* Store the MCDI ops */175cdx_mcdi->mcdi_ops = &mcdi_ops;176/* MCDI FW: Initialize the FW path */177ret = cdx_mcdi_init(cdx_mcdi);178if (ret) {179dev_err_probe(&pdev->dev, ret, "MCDI Initialization failed\n");180goto mcdi_init_fail;181}182183cdx = kzalloc(sizeof(*cdx), GFP_KERNEL);184if (!cdx) {185ret = -ENOMEM;186goto cdx_alloc_fail;187}188platform_set_drvdata(pdev, cdx);189190cdx->dev = &pdev->dev;191cdx->priv = cdx_mcdi;192cdx->ops = &cdx_ops;193194/* Create MSI domain */195cdx->msi_domain = cdx_msi_domain_init(&pdev->dev);196if (!cdx->msi_domain) {197ret = dev_err_probe(&pdev->dev, -ENODEV, "cdx_msi_domain_init() failed");198goto cdx_msi_fail;199}200201ret = cdx_setup_rpmsg(pdev);202if (ret) {203dev_err_probe(&pdev->dev, ret, "Failed to register CDX RPMsg transport\n");204goto cdx_rpmsg_fail;205}206207return 0;208209cdx_rpmsg_fail:210irq_domain_remove(cdx->msi_domain);211cdx_msi_fail:212kfree(cdx);213cdx_alloc_fail:214cdx_mcdi_finish(cdx_mcdi);215mcdi_init_fail:216kfree(cdx_mcdi);217218return ret;219}220221static void xlnx_cdx_remove(struct platform_device *pdev)222{223struct cdx_controller *cdx = platform_get_drvdata(pdev);224struct cdx_mcdi *cdx_mcdi = cdx->priv;225226cdx_destroy_rpmsg(pdev);227228irq_domain_remove(cdx->msi_domain);229kfree(cdx);230231cdx_mcdi_finish(cdx_mcdi);232kfree(cdx_mcdi);233}234235static const struct of_device_id cdx_match_table[] = {236{.compatible = "xlnx,versal-net-cdx",},237{ },238};239240MODULE_DEVICE_TABLE(of, cdx_match_table);241242static struct platform_driver cdx_pdriver = {243.driver = {244.name = "cdx-controller",245.of_match_table = cdx_match_table,246},247.probe = xlnx_cdx_probe,248.remove = xlnx_cdx_remove,249};250251module_platform_driver(cdx_pdriver);252253MODULE_AUTHOR("AMD Inc.");254MODULE_DESCRIPTION("CDX controller for AMD devices");255MODULE_LICENSE("GPL");256MODULE_IMPORT_NS("CDX_BUS_CONTROLLER");257258259