cregit-Linux how code gets into the kernel

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

/*
 * PowerNV OPAL asynchronous completion interfaces
 *
 * Copyright 2013 IBM Corp.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */


#undef DEBUG

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/gfp.h>
#include <linux/of.h>
#include <asm/machdep.h>
#include <asm/opal.h>


#define N_ASYNC_COMPLETIONS	64

static DECLARE_BITMAP(opal_async_complete_map, N_ASYNC_COMPLETIONS) = {~0UL};
static DECLARE_BITMAP(opal_async_token_map, N_ASYNC_COMPLETIONS);
static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
static DEFINE_SPINLOCK(opal_async_comp_lock);

static struct semaphore opal_async_sem;

static struct opal_msg *opal_async_responses;

static unsigned int opal_max_async_tokens;


int __opal_async_get_token(void) { unsigned long flags; int token; spin_lock_irqsave(&opal_async_comp_lock, flags); token = find_first_bit(opal_async_complete_map, opal_max_async_tokens); if (token >= opal_max_async_tokens) { token = -EBUSY; goto out; } if (__test_and_set_bit(token, opal_async_token_map)) { token = -EBUSY; goto out; } __clear_bit(token, opal_async_complete_map); out: spin_unlock_irqrestore(&opal_async_comp_lock, flags); return token; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta86100.00%1100.00%
Total86100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta43100.00%1100.00%
Total43100.00%1100.00%

EXPORT_SYMBOL_GPL(opal_async_get_token_interruptible);
int __opal_async_release_token(int token) { unsigned long flags; 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); __set_bit(token, opal_async_complete_map); __clear_bit(token, opal_async_token_map); spin_unlock_irqrestore(&opal_async_comp_lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta70100.00%1100.00%
Total70100.00%1100.00%


int opal_async_release_token(int token) { int ret; ret = __opal_async_release_token(token); if (ret) return ret; up(&opal_async_sem); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta34100.00%1100.00%
Total34100.00%1100.00%

EXPORT_SYMBOL_GPL(opal_async_release_token);
int opal_async_wait_response(uint64_t token, struct opal_msg *msg) { if (token >= opal_max_async_tokens) { pr_err("%s: Invalid token passed\n", __func__); return -EINVAL; } if (!msg) { pr_err("%s: Invalid message pointer passed\n", __func__); return -EINVAL; } /* Wakeup the poller before we wait for events to speed things * up on platforms or simulators where the interrupts aren't * functional. */ opal_wake_poller(); wait_event(opal_async_wait, test_bit(token, opal_async_complete_map)); memcpy(msg, &opal_async_responses[token], sizeof(*msg)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta8295.35%150.00%
Benjamin Herrenschmidt44.65%150.00%
Total86100.00%2100.00%

EXPORT_SYMBOL_GPL(opal_async_wait_response);
static int opal_async_comp_event(struct notifier_block *nb, unsigned long msg_type, void *msg) { struct opal_msg *comp_msg = msg; unsigned long flags; uint64_t token; if (msg_type != OPAL_MSG_ASYNC_COMP) return 0; token = be64_to_cpu(comp_msg->params[0]); memcpy(&opal_async_responses[token], comp_msg, sizeof(*comp_msg)); spin_lock_irqsave(&opal_async_comp_lock, flags); __set_bit(token, opal_async_complete_map); spin_unlock_irqrestore(&opal_async_comp_lock, flags); wake_up(&opal_async_wait); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta8885.44%150.00%
Anton Blanchard1514.56%150.00%
Total103100.00%2100.00%

static struct notifier_block opal_async_comp_nb = { .notifier_call = opal_async_comp_event, .next = NULL, .priority = 0, };
int __init opal_async_comp_init(void) { struct device_node *opal_node; const __be32 *async; int err; opal_node = of_find_node_by_path("/ibm,opal"); if (!opal_node) { pr_err("%s: Opal node not found\n", __func__); err = -ENOENT; goto out; } async = of_get_property(opal_node, "opal-msg-async-num", NULL); if (!async) { pr_err("%s: %pOF has no opal-msg-async-num\n", __func__, opal_node); err = -ENOENT; goto out_opal_node; } opal_max_async_tokens = be32_to_cpup(async); if (opal_max_async_tokens > N_ASYNC_COMPLETIONS) opal_max_async_tokens = N_ASYNC_COMPLETIONS; err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP, &opal_async_comp_nb); if (err) { pr_err("%s: Can't register OPAL event notifier (%d)\n", __func__, err); goto out_opal_node; } opal_async_responses = kzalloc( sizeof(*opal_async_responses) * opal_max_async_tokens, GFP_KERNEL); if (!opal_async_responses) { pr_err("%s: Out of memory, failed to do asynchronous " "completion init\n", __func__); err = -ENOMEM; goto out_opal_node; } /* Initialize to 1 less than the maximum tokens available, as we may * require to pop one during emergency through synchronous call to * __opal_async_get_token() */ sema_init(&opal_async_sem, opal_max_async_tokens - 1); out_opal_node: of_node_put(opal_node); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta19099.48%150.00%
Rob Herring10.52%150.00%
Total191100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Neelesh Gupta71796.89%233.33%
Anton Blanchard152.03%116.67%
Benjamin Herrenschmidt40.54%116.67%
Michael Ellerman30.41%116.67%
Rob Herring10.14%116.67%
Total740100.00%6100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.