drivers/fpga/dfl-fme-mgr.c

Source file repositories/reference/linux-study-clean/drivers/fpga/dfl-fme-mgr.c

File Facts

System
Linux kernel
Corpus path
drivers/fpga/dfl-fme-mgr.c
Extension
.c
Size
9025 bytes
Lines
322
Domain
Driver Families
Bucket
drivers/fpga
Inferred role
Driver Families: implementation source
Status
source 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

struct fme_mgr_priv {
	void __iomem *ioaddr;
	u64 pr_error;
};

static u64 pr_error_to_mgr_status(u64 err)
{
	u64 status = 0;

	if (err & FME_PR_ERR_OPERATION_ERR)
		status |= FPGA_MGR_STATUS_OPERATION_ERR;
	if (err & FME_PR_ERR_CRC_ERR)
		status |= FPGA_MGR_STATUS_CRC_ERR;
	if (err & FME_PR_ERR_INCOMPATIBLE_BS)
		status |= FPGA_MGR_STATUS_INCOMPATIBLE_IMAGE_ERR;
	if (err & FME_PR_ERR_PROTOCOL_ERR)
		status |= FPGA_MGR_STATUS_IP_PROTOCOL_ERR;
	if (err & FME_PR_ERR_FIFO_OVERFLOW)
		status |= FPGA_MGR_STATUS_FIFO_OVERFLOW_ERR;

	return status;
}

static u64 fme_mgr_pr_error_handle(void __iomem *fme_pr)
{
	u64 pr_status, pr_error;

	pr_status = readq(fme_pr + FME_PR_STS);
	if (!(pr_status & FME_PR_STS_PR_STS))
		return 0;

	pr_error = readq(fme_pr + FME_PR_ERR);
	writeq(pr_error, fme_pr + FME_PR_ERR);

	return pr_error;
}

static int fme_mgr_write_init(struct fpga_manager *mgr,
			      struct fpga_image_info *info,
			      const char *buf, size_t count)
{
	struct device *dev = &mgr->dev;
	struct fme_mgr_priv *priv = mgr->priv;
	void __iomem *fme_pr = priv->ioaddr;
	u64 pr_ctrl, pr_status;

	if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
		dev_err(dev, "only supports partial reconfiguration.\n");
		return -EINVAL;
	}

	dev_dbg(dev, "resetting PR before initiated PR\n");

	pr_ctrl = readq(fme_pr + FME_PR_CTRL);
	pr_ctrl |= FME_PR_CTRL_PR_RST;
	writeq(pr_ctrl, fme_pr + FME_PR_CTRL);

	if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl,
			       pr_ctrl & FME_PR_CTRL_PR_RSTACK, 1,
			       PR_WAIT_TIMEOUT)) {
		dev_err(dev, "PR Reset ACK timeout\n");
		return -ETIMEDOUT;
	}

	pr_ctrl = readq(fme_pr + FME_PR_CTRL);
	pr_ctrl &= ~FME_PR_CTRL_PR_RST;
	writeq(pr_ctrl, fme_pr + FME_PR_CTRL);

	dev_dbg(dev,
		"waiting for PR resource in HW to be initialized and ready\n");

	if (readq_poll_timeout(fme_pr + FME_PR_STS, pr_status,
			       (pr_status & FME_PR_STS_PR_STS) ==
			       FME_PR_STS_PR_STS_IDLE, 1, PR_WAIT_TIMEOUT)) {
		dev_err(dev, "PR Status timeout\n");
		priv->pr_error = fme_mgr_pr_error_handle(fme_pr);
		return -ETIMEDOUT;
	}

	dev_dbg(dev, "check and clear previous PR error\n");
	priv->pr_error = fme_mgr_pr_error_handle(fme_pr);
	if (priv->pr_error)
		dev_dbg(dev, "previous PR error detected %llx\n",
			(unsigned long long)priv->pr_error);

	dev_dbg(dev, "set PR port ID\n");

	pr_ctrl = readq(fme_pr + FME_PR_CTRL);
	pr_ctrl &= ~FME_PR_CTRL_PR_RGN_ID;
	pr_ctrl |= FIELD_PREP(FME_PR_CTRL_PR_RGN_ID, info->region_id);

Annotation

Implementation Notes