drivers/mmc/host/mmc_hsq.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/mmc_hsq.c
Extension
.c
Size
8341 bytes
Lines
388
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

// SPDX-License-Identifier: GPL-2.0
/*
 *
 * MMC software queue support based on command queue interfaces
 *
 * Copyright (C) 2019 Linaro, Inc.
 * Author: Baolin Wang <baolin.wang@linaro.org>
 */

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/module.h>

#include "mmc_hsq.h"

static void mmc_hsq_retry_handler(struct work_struct *work)
{
	struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work);
	struct mmc_host *mmc = hsq->mmc;

	mmc->ops->request(mmc, hsq->mrq);
}

static void mmc_hsq_modify_threshold(struct mmc_hsq *hsq)
{
	struct mmc_host *mmc = hsq->mmc;
	struct mmc_request *mrq;
	unsigned int tag, need_change = 0;

	mmc->hsq_depth = HSQ_NORMAL_DEPTH;
	for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
		mrq = hsq->slot[tag].mrq;
		if (mrq && mrq->data &&
		   (mrq->data->blksz * mrq->data->blocks == 4096) &&
		   (mrq->data->flags & MMC_DATA_WRITE) &&
		   (++need_change == 2)) {
			mmc->hsq_depth = HSQ_PERFORMANCE_DEPTH;
			break;
		}
	}
}

static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
{
	struct mmc_host *mmc = hsq->mmc;
	struct hsq_slot *slot;
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&hsq->lock, flags);

	/* Make sure we are not already running a request now */
	if (hsq->mrq || hsq->recovery_halt) {
		spin_unlock_irqrestore(&hsq->lock, flags);
		return;
	}

	/* Make sure there are remain requests need to pump */
	if (!hsq->qcnt || !hsq->enabled) {
		spin_unlock_irqrestore(&hsq->lock, flags);
		return;
	}

	mmc_hsq_modify_threshold(hsq);

	slot = &hsq->slot[hsq->next_tag];
	hsq->mrq = slot->mrq;
	hsq->qcnt--;

	spin_unlock_irqrestore(&hsq->lock, flags);

	if (mmc->ops->request_atomic)
		ret = mmc->ops->request_atomic(mmc, hsq->mrq);
	else
		mmc->ops->request(mmc, hsq->mrq);

	/*
	 * If returning BUSY from request_atomic(), which means the card
	 * may be busy now, and we should change to non-atomic context to
	 * try again for this unusual case, to avoid time-consuming operations
	 * in the atomic context.
	 *
	 * Note: we just give a warning for other error cases, since the host
	 * driver will handle them.
	 */
	if (ret == -EBUSY)
		schedule_work(&hsq->retry_work);
	else
		WARN_ON_ONCE(ret);
}

Annotation

Implementation Notes