drivers/cdx/cdx_msi.c

Source file repositories/reference/linux-study-clean/drivers/cdx/cdx_msi.c

File Facts

System
Linux kernel
Corpus path
drivers/cdx/cdx_msi.c
Extension
.c
Size
5621 bytes
Lines
194
Domain
Driver Families
Bucket
drivers/cdx
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * AMD CDX bus driver MSI support
 *
 * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
 */

#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/msi.h>
#include <linux/cdx/cdx_bus.h>

#include "cdx.h"

static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
{
	struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
	struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);

	/* We would not operate on msg here rather we wait for irq_bus_sync_unlock()
	 * to be called from preemptible task context.
	 */
	msi_desc->msg = *msg;
	cdx_dev->msi_write_pending = true;
}

static void cdx_msi_write_irq_lock(struct irq_data *irq_data)
{
	struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
	struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);

	mutex_lock(&cdx_dev->irqchip_lock);
}

static void cdx_msi_write_irq_unlock(struct irq_data *irq_data)
{
	struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
	struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
	struct cdx_controller *cdx = cdx_dev->cdx;
	struct cdx_device_config dev_config;

	if (!cdx_dev->msi_write_pending) {
		mutex_unlock(&cdx_dev->irqchip_lock);
		return;
	}

	cdx_dev->msi_write_pending = false;
	mutex_unlock(&cdx_dev->irqchip_lock);

	dev_config.msi.msi_index = msi_desc->msi_index;
	dev_config.msi.data = msi_desc->msg.data;
	dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo;

	/*
	 * dev_configure() is a controller callback which can interact with
	 * Firmware or other entities, and can sleep, so invoke this function
	 * outside of the mutex held region.
	 */
	dev_config.type = CDX_DEV_MSI_CONF;
	if (cdx->ops->dev_configure)
		cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
}

int cdx_enable_msi(struct cdx_device *cdx_dev)
{
	struct cdx_controller *cdx = cdx_dev->cdx;
	struct cdx_device_config dev_config;

	dev_config.type = CDX_DEV_MSI_ENABLE;
	dev_config.msi_enable = true;
	if (cdx->ops->dev_configure) {
		return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num,
					       &dev_config);
	}

	return -EOPNOTSUPP;
}
EXPORT_SYMBOL_GPL(cdx_enable_msi);

void cdx_disable_msi(struct cdx_device *cdx_dev)
{
	struct cdx_controller *cdx = cdx_dev->cdx;
	struct cdx_device_config dev_config;

	dev_config.type = CDX_DEV_MSI_ENABLE;
	dev_config.msi_enable = false;

Annotation

Implementation Notes