arch/powerpc/platforms/powernv/opal-async.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/powernv/opal-async.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/powernv/opal-async.c
Extension
.c
Size
7358 bytes
Lines
291
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct opal_async_token {
	enum opal_async_token_state state;
	struct opal_msg response;
};

static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
static DEFINE_SPINLOCK(opal_async_comp_lock);
static struct semaphore opal_async_sem;
static unsigned int opal_max_async_tokens;
static struct opal_async_token *opal_async_tokens;

static int __opal_async_get_token(void)
{
	unsigned long flags;
	int i, token = -EBUSY;

	spin_lock_irqsave(&opal_async_comp_lock, flags);

	for (i = 0; i < opal_max_async_tokens; i++) {
		if (opal_async_tokens[i].state == ASYNC_TOKEN_UNALLOCATED) {
			opal_async_tokens[i].state = ASYNC_TOKEN_ALLOCATED;
			token = i;
			break;
		}
	}

	spin_unlock_irqrestore(&opal_async_comp_lock, flags);
	return token;
}

/*
 * Note: If the returned token is used in an opal call and opal returns
 * OPAL_ASYNC_COMPLETION you MUST call one of opal_async_wait_response() or
 * opal_async_wait_response_interruptible() at least once before calling another
 * opal_async_* function
 */
int opal_async_get_token_interruptible(void)
{
	int token;

	/* Wait until a token is available */
	if (down_interruptible(&opal_async_sem))
		return -ERESTARTSYS;

	token = __opal_async_get_token();
	if (token < 0)
		up(&opal_async_sem);

	return token;
}
EXPORT_SYMBOL_GPL(opal_async_get_token_interruptible);

static int __opal_async_release_token(int token)
{
	unsigned long flags;
	int rc;

	if (token < 0 || token >= opal_max_async_tokens) {
		pr_err("%s: Passed token is out of range, token %d\n",
				__func__, token);
		return -EINVAL;
	}

	spin_lock_irqsave(&opal_async_comp_lock, flags);
	switch (opal_async_tokens[token].state) {
	case ASYNC_TOKEN_COMPLETED:
	case ASYNC_TOKEN_ALLOCATED:
		opal_async_tokens[token].state = ASYNC_TOKEN_UNALLOCATED;
		rc = 0;
		break;
	/*
	 * DISPATCHED and ABANDONED tokens must wait for OPAL to respond.
	 * Mark a DISPATCHED token as ABANDONED so that the response handling
	 * code knows no one cares and that it can free it then.
	 */
	case ASYNC_TOKEN_DISPATCHED:
		opal_async_tokens[token].state = ASYNC_TOKEN_ABANDONED;
		fallthrough;
	default:
		rc = 1;
	}
	spin_unlock_irqrestore(&opal_async_comp_lock, flags);

	return rc;
}

int opal_async_release_token(int token)
{
	int ret;

Annotation

Implementation Notes