drivers/mmc/host/cqhci-core.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/cqhci-core.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/cqhci-core.c
Extension
.c
Size
31125 bytes
Lines
1233
Domain
Driver Families
Bucket
drivers/mmc
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

struct cqhci_slot {
	struct mmc_request *mrq;
	unsigned int flags;
#define CQHCI_EXTERNAL_TIMEOUT	BIT(0)
#define CQHCI_COMPLETED		BIT(1)
#define CQHCI_HOST_CRC		BIT(2)
#define CQHCI_HOST_TIMEOUT	BIT(3)
#define CQHCI_HOST_OTHER	BIT(4)
};

static bool cqhci_halted(struct cqhci_host *cq_host)
{
	return cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT;
}

static inline u8 *get_desc(struct cqhci_host *cq_host, u8 tag)
{
	return cq_host->desc_base + (tag * cq_host->slot_sz);
}

static inline u8 *get_link_desc(struct cqhci_host *cq_host, u8 tag)
{
	u8 *desc = get_desc(cq_host, tag);

	return desc + cq_host->task_desc_len;
}

static inline size_t get_trans_desc_offset(struct cqhci_host *cq_host, u8 tag)
{
	return cq_host->trans_desc_len * cq_host->mmc->max_segs * tag;
}

static inline dma_addr_t get_trans_desc_dma(struct cqhci_host *cq_host, u8 tag)
{
	size_t offset = get_trans_desc_offset(cq_host, tag);

	return cq_host->trans_desc_dma_base + offset;
}

static inline u8 *get_trans_desc(struct cqhci_host *cq_host, u8 tag)
{
	size_t offset = get_trans_desc_offset(cq_host, tag);

	return cq_host->trans_desc_base + offset;
}

static void setup_trans_desc(struct cqhci_host *cq_host, u8 tag)
{
	u8 *link_temp;
	dma_addr_t trans_temp;

	link_temp = get_link_desc(cq_host, tag);
	trans_temp = get_trans_desc_dma(cq_host, tag);

	memset(link_temp, 0, cq_host->link_desc_len);
	if (cq_host->link_desc_len > 8)
		*(link_temp + 8) = 0;

	if (tag == DCMD_SLOT && (cq_host->mmc->caps2 & MMC_CAP2_CQE_DCMD)) {
		*link_temp = CQHCI_VALID(0) | CQHCI_ACT(0) | CQHCI_END(1);
		return;
	}

	*link_temp = CQHCI_VALID(1) | CQHCI_ACT(0x6) | CQHCI_END(0);

	if (cq_host->dma64) {
		__le64 *data_addr = (__le64 __force *)(link_temp + 4);

		data_addr[0] = cpu_to_le64(trans_temp);
	} else {
		__le32 *data_addr = (__le32 __force *)(link_temp + 4);

		data_addr[0] = cpu_to_le32(trans_temp);
	}
}

static void cqhci_set_irqs(struct cqhci_host *cq_host, u32 set)
{
	cqhci_writel(cq_host, set, CQHCI_ISTE);
	cqhci_writel(cq_host, set, CQHCI_ISGE);
}

#define DRV_NAME "cqhci"

#define CQHCI_DUMP(f, x...) \
	pr_err("%s: " DRV_NAME ": " f, mmc_hostname(mmc), ## x)

static void cqhci_dumpregs(struct cqhci_host *cq_host)
{
	struct mmc_host *mmc = cq_host->mmc;

Annotation

Implementation Notes