18d724823SNeelesh Gupta /* 28d724823SNeelesh Gupta * PowerNV OPAL asynchronous completion interfaces 38d724823SNeelesh Gupta * 486cd6d98SCyril Bur * Copyright 2013-2017 IBM Corp. 58d724823SNeelesh Gupta * 68d724823SNeelesh Gupta * This program is free software; you can redistribute it and/or 78d724823SNeelesh Gupta * modify it under the terms of the GNU General Public License 88d724823SNeelesh Gupta * as published by the Free Software Foundation; either version 98d724823SNeelesh Gupta * 2 of the License, or (at your option) any later version. 108d724823SNeelesh Gupta */ 118d724823SNeelesh Gupta 128d724823SNeelesh Gupta #undef DEBUG 138d724823SNeelesh Gupta 148d724823SNeelesh Gupta #include <linux/kernel.h> 158d724823SNeelesh Gupta #include <linux/init.h> 168d724823SNeelesh Gupta #include <linux/slab.h> 178d724823SNeelesh Gupta #include <linux/sched.h> 188d724823SNeelesh Gupta #include <linux/semaphore.h> 198d724823SNeelesh Gupta #include <linux/spinlock.h> 208d724823SNeelesh Gupta #include <linux/wait.h> 218d724823SNeelesh Gupta #include <linux/gfp.h> 228d724823SNeelesh Gupta #include <linux/of.h> 23b14726c5SMichael Ellerman #include <asm/machdep.h> 248d724823SNeelesh Gupta #include <asm/opal.h> 258d724823SNeelesh Gupta 2686cd6d98SCyril Bur enum opal_async_token_state { 2786cd6d98SCyril Bur ASYNC_TOKEN_UNALLOCATED = 0, 2886cd6d98SCyril Bur ASYNC_TOKEN_ALLOCATED, 299aab2449SCyril Bur ASYNC_TOKEN_DISPATCHED, 309aab2449SCyril Bur ASYNC_TOKEN_ABANDONED, 3186cd6d98SCyril Bur ASYNC_TOKEN_COMPLETED 3286cd6d98SCyril Bur }; 338d724823SNeelesh Gupta 3486cd6d98SCyril Bur struct opal_async_token { 3586cd6d98SCyril Bur enum opal_async_token_state state; 3686cd6d98SCyril Bur struct opal_msg response; 3786cd6d98SCyril Bur }; 3886cd6d98SCyril Bur 398d724823SNeelesh Gupta static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait); 408d724823SNeelesh Gupta static DEFINE_SPINLOCK(opal_async_comp_lock); 418d724823SNeelesh Gupta static struct semaphore opal_async_sem; 428d724823SNeelesh Gupta static unsigned int opal_max_async_tokens; 4386cd6d98SCyril Bur static struct opal_async_token *opal_async_tokens; 448d724823SNeelesh Gupta 4559cf9a1cSCyril Bur static int __opal_async_get_token(void) 468d724823SNeelesh Gupta { 478d724823SNeelesh Gupta unsigned long flags; 4886cd6d98SCyril Bur int i, token = -EBUSY; 498d724823SNeelesh Gupta 508d724823SNeelesh Gupta spin_lock_irqsave(&opal_async_comp_lock, flags); 5186cd6d98SCyril Bur 5286cd6d98SCyril Bur for (i = 0; i < opal_max_async_tokens; i++) { 5386cd6d98SCyril Bur if (opal_async_tokens[i].state == ASYNC_TOKEN_UNALLOCATED) { 5486cd6d98SCyril Bur opal_async_tokens[i].state = ASYNC_TOKEN_ALLOCATED; 5586cd6d98SCyril Bur token = i; 5686cd6d98SCyril Bur break; 5786cd6d98SCyril Bur } 588d724823SNeelesh Gupta } 598d724823SNeelesh Gupta 608d724823SNeelesh Gupta spin_unlock_irqrestore(&opal_async_comp_lock, flags); 618d724823SNeelesh Gupta return token; 628d724823SNeelesh Gupta } 638d724823SNeelesh Gupta 6486cd6d98SCyril Bur /* 6586cd6d98SCyril Bur * Note: If the returned token is used in an opal call and opal returns 669aab2449SCyril Bur * OPAL_ASYNC_COMPLETION you MUST call one of opal_async_wait_response() or 679aab2449SCyril Bur * opal_async_wait_response_interruptible() at least once before calling another 689aab2449SCyril Bur * opal_async_* function 6986cd6d98SCyril Bur */ 708d724823SNeelesh Gupta int opal_async_get_token_interruptible(void) 718d724823SNeelesh Gupta { 728d724823SNeelesh Gupta int token; 738d724823SNeelesh Gupta 748d724823SNeelesh Gupta /* Wait until a token is available */ 758d724823SNeelesh Gupta if (down_interruptible(&opal_async_sem)) 768d724823SNeelesh Gupta return -ERESTARTSYS; 778d724823SNeelesh Gupta 788d724823SNeelesh Gupta token = __opal_async_get_token(); 798d724823SNeelesh Gupta if (token < 0) 808d724823SNeelesh Gupta up(&opal_async_sem); 818d724823SNeelesh Gupta 828d724823SNeelesh Gupta return token; 838d724823SNeelesh Gupta } 8416b1d26eSNeelesh Gupta EXPORT_SYMBOL_GPL(opal_async_get_token_interruptible); 858d724823SNeelesh Gupta 8659cf9a1cSCyril Bur static int __opal_async_release_token(int token) 878d724823SNeelesh Gupta { 888d724823SNeelesh Gupta unsigned long flags; 8986cd6d98SCyril Bur int rc; 908d724823SNeelesh Gupta 918d724823SNeelesh Gupta if (token < 0 || token >= opal_max_async_tokens) { 928d724823SNeelesh Gupta pr_err("%s: Passed token is out of range, token %d\n", 938d724823SNeelesh Gupta __func__, token); 948d724823SNeelesh Gupta return -EINVAL; 958d724823SNeelesh Gupta } 968d724823SNeelesh Gupta 978d724823SNeelesh Gupta spin_lock_irqsave(&opal_async_comp_lock, flags); 9886cd6d98SCyril Bur switch (opal_async_tokens[token].state) { 9986cd6d98SCyril Bur case ASYNC_TOKEN_COMPLETED: 10086cd6d98SCyril Bur case ASYNC_TOKEN_ALLOCATED: 10186cd6d98SCyril Bur opal_async_tokens[token].state = ASYNC_TOKEN_UNALLOCATED; 10286cd6d98SCyril Bur rc = 0; 10386cd6d98SCyril Bur break; 1049aab2449SCyril Bur /* 1059aab2449SCyril Bur * DISPATCHED and ABANDONED tokens must wait for OPAL to respond. 1069aab2449SCyril Bur * Mark a DISPATCHED token as ABANDONED so that the response handling 1079aab2449SCyril Bur * code knows no one cares and that it can free it then. 1089aab2449SCyril Bur */ 1099aab2449SCyril Bur case ASYNC_TOKEN_DISPATCHED: 1109aab2449SCyril Bur opal_async_tokens[token].state = ASYNC_TOKEN_ABANDONED; 1119aab2449SCyril Bur /* Fall through */ 11286cd6d98SCyril Bur default: 11386cd6d98SCyril Bur rc = 1; 11486cd6d98SCyril Bur } 1158d724823SNeelesh Gupta spin_unlock_irqrestore(&opal_async_comp_lock, flags); 1168d724823SNeelesh Gupta 11786cd6d98SCyril Bur return rc; 1188d724823SNeelesh Gupta } 1198d724823SNeelesh Gupta 1208d724823SNeelesh Gupta int opal_async_release_token(int token) 1218d724823SNeelesh Gupta { 1228d724823SNeelesh Gupta int ret; 1238d724823SNeelesh Gupta 1248d724823SNeelesh Gupta ret = __opal_async_release_token(token); 12586cd6d98SCyril Bur if (!ret) 1268d724823SNeelesh Gupta up(&opal_async_sem); 1278d724823SNeelesh Gupta 12886cd6d98SCyril Bur return ret; 1298d724823SNeelesh Gupta } 13016b1d26eSNeelesh Gupta EXPORT_SYMBOL_GPL(opal_async_release_token); 1318d724823SNeelesh Gupta 1328d724823SNeelesh Gupta int opal_async_wait_response(uint64_t token, struct opal_msg *msg) 1338d724823SNeelesh Gupta { 1348d724823SNeelesh Gupta if (token >= opal_max_async_tokens) { 1358d724823SNeelesh Gupta pr_err("%s: Invalid token passed\n", __func__); 1368d724823SNeelesh Gupta return -EINVAL; 1378d724823SNeelesh Gupta } 1388d724823SNeelesh Gupta 1398d724823SNeelesh Gupta if (!msg) { 1408d724823SNeelesh Gupta pr_err("%s: Invalid message pointer passed\n", __func__); 1418d724823SNeelesh Gupta return -EINVAL; 1428d724823SNeelesh Gupta } 1438d724823SNeelesh Gupta 1449aab2449SCyril Bur /* 1459aab2449SCyril Bur * There is no need to mark the token as dispatched, wait_event() 1469aab2449SCyril Bur * will block until the token completes. 1479aab2449SCyril Bur * 1489aab2449SCyril Bur * Wakeup the poller before we wait for events to speed things 149a203658bSBenjamin Herrenschmidt * up on platforms or simulators where the interrupts aren't 150a203658bSBenjamin Herrenschmidt * functional. 151a203658bSBenjamin Herrenschmidt */ 152a203658bSBenjamin Herrenschmidt opal_wake_poller(); 15386cd6d98SCyril Bur wait_event(opal_async_wait, opal_async_tokens[token].state 15486cd6d98SCyril Bur == ASYNC_TOKEN_COMPLETED); 15586cd6d98SCyril Bur memcpy(msg, &opal_async_tokens[token].response, sizeof(*msg)); 1568d724823SNeelesh Gupta 1578d724823SNeelesh Gupta return 0; 1588d724823SNeelesh Gupta } 15916b1d26eSNeelesh Gupta EXPORT_SYMBOL_GPL(opal_async_wait_response); 1608d724823SNeelesh Gupta 1619aab2449SCyril Bur int opal_async_wait_response_interruptible(uint64_t token, struct opal_msg *msg) 1629aab2449SCyril Bur { 1639aab2449SCyril Bur unsigned long flags; 1649aab2449SCyril Bur int ret; 1659aab2449SCyril Bur 1669aab2449SCyril Bur if (token >= opal_max_async_tokens) { 1679aab2449SCyril Bur pr_err("%s: Invalid token passed\n", __func__); 1689aab2449SCyril Bur return -EINVAL; 1699aab2449SCyril Bur } 1709aab2449SCyril Bur 1719aab2449SCyril Bur if (!msg) { 1729aab2449SCyril Bur pr_err("%s: Invalid message pointer passed\n", __func__); 1739aab2449SCyril Bur return -EINVAL; 1749aab2449SCyril Bur } 1759aab2449SCyril Bur 1769aab2449SCyril Bur /* 1779aab2449SCyril Bur * The first time this gets called we mark the token as DISPATCHED 1789aab2449SCyril Bur * so that if wait_event_interruptible() returns not zero and the 1799aab2449SCyril Bur * caller frees the token, we know not to actually free the token 1809aab2449SCyril Bur * until the response comes. 1819aab2449SCyril Bur * 1829aab2449SCyril Bur * Only change if the token is ALLOCATED - it may have been 1839aab2449SCyril Bur * completed even before the caller gets around to calling this 1849aab2449SCyril Bur * the first time. 1859aab2449SCyril Bur * 1869aab2449SCyril Bur * There is also a dirty great comment at the token allocation 1879aab2449SCyril Bur * function that if the opal call returns OPAL_ASYNC_COMPLETION to 1889aab2449SCyril Bur * the caller then the caller *must* call this or the not 1899aab2449SCyril Bur * interruptible version before doing anything else with the 1909aab2449SCyril Bur * token. 1919aab2449SCyril Bur */ 1929aab2449SCyril Bur if (opal_async_tokens[token].state == ASYNC_TOKEN_ALLOCATED) { 1939aab2449SCyril Bur spin_lock_irqsave(&opal_async_comp_lock, flags); 1949aab2449SCyril Bur if (opal_async_tokens[token].state == ASYNC_TOKEN_ALLOCATED) 1959aab2449SCyril Bur opal_async_tokens[token].state = ASYNC_TOKEN_DISPATCHED; 1969aab2449SCyril Bur spin_unlock_irqrestore(&opal_async_comp_lock, flags); 1979aab2449SCyril Bur } 1989aab2449SCyril Bur 1999aab2449SCyril Bur /* 2009aab2449SCyril Bur * Wakeup the poller before we wait for events to speed things 2019aab2449SCyril Bur * up on platforms or simulators where the interrupts aren't 2029aab2449SCyril Bur * functional. 2039aab2449SCyril Bur */ 2049aab2449SCyril Bur opal_wake_poller(); 2059aab2449SCyril Bur ret = wait_event_interruptible(opal_async_wait, 2069aab2449SCyril Bur opal_async_tokens[token].state == 2079aab2449SCyril Bur ASYNC_TOKEN_COMPLETED); 2089aab2449SCyril Bur if (!ret) 2099aab2449SCyril Bur memcpy(msg, &opal_async_tokens[token].response, sizeof(*msg)); 2109aab2449SCyril Bur 2119aab2449SCyril Bur return ret; 2129aab2449SCyril Bur } 2139aab2449SCyril Bur EXPORT_SYMBOL_GPL(opal_async_wait_response_interruptible); 2149aab2449SCyril Bur 21586cd6d98SCyril Bur /* Called from interrupt context */ 2168d724823SNeelesh Gupta static int opal_async_comp_event(struct notifier_block *nb, 2178d724823SNeelesh Gupta unsigned long msg_type, void *msg) 2188d724823SNeelesh Gupta { 2198d724823SNeelesh Gupta struct opal_msg *comp_msg = msg; 2209aab2449SCyril Bur enum opal_async_token_state state; 2218d724823SNeelesh Gupta unsigned long flags; 222bb4398e1SAnton Blanchard uint64_t token; 2238d724823SNeelesh Gupta 2248d724823SNeelesh Gupta if (msg_type != OPAL_MSG_ASYNC_COMP) 2258d724823SNeelesh Gupta return 0; 2268d724823SNeelesh Gupta 227bb4398e1SAnton Blanchard token = be64_to_cpu(comp_msg->params[0]); 2288d724823SNeelesh Gupta spin_lock_irqsave(&opal_async_comp_lock, flags); 2299aab2449SCyril Bur state = opal_async_tokens[token].state; 23086cd6d98SCyril Bur opal_async_tokens[token].state = ASYNC_TOKEN_COMPLETED; 2318d724823SNeelesh Gupta spin_unlock_irqrestore(&opal_async_comp_lock, flags); 2328d724823SNeelesh Gupta 2339aab2449SCyril Bur if (state == ASYNC_TOKEN_ABANDONED) { 2349aab2449SCyril Bur /* Free the token, no one else will */ 2359aab2449SCyril Bur opal_async_release_token(token); 2369aab2449SCyril Bur return 0; 2379aab2449SCyril Bur } 2389aab2449SCyril Bur memcpy(&opal_async_tokens[token].response, comp_msg, sizeof(*comp_msg)); 2398d724823SNeelesh Gupta wake_up(&opal_async_wait); 2408d724823SNeelesh Gupta 2418d724823SNeelesh Gupta return 0; 2428d724823SNeelesh Gupta } 2438d724823SNeelesh Gupta 2448d724823SNeelesh Gupta static struct notifier_block opal_async_comp_nb = { 2458d724823SNeelesh Gupta .notifier_call = opal_async_comp_event, 2468d724823SNeelesh Gupta .next = NULL, 2478d724823SNeelesh Gupta .priority = 0, 2488d724823SNeelesh Gupta }; 2498d724823SNeelesh Gupta 25096e023e7SAlistair Popple int __init opal_async_comp_init(void) 2518d724823SNeelesh Gupta { 2528d724823SNeelesh Gupta struct device_node *opal_node; 2538d724823SNeelesh Gupta const __be32 *async; 2548d724823SNeelesh Gupta int err; 2558d724823SNeelesh Gupta 2568d724823SNeelesh Gupta opal_node = of_find_node_by_path("/ibm,opal"); 2578d724823SNeelesh Gupta if (!opal_node) { 2588d724823SNeelesh Gupta pr_err("%s: Opal node not found\n", __func__); 2598d724823SNeelesh Gupta err = -ENOENT; 2608d724823SNeelesh Gupta goto out; 2618d724823SNeelesh Gupta } 2628d724823SNeelesh Gupta 2638d724823SNeelesh Gupta async = of_get_property(opal_node, "opal-msg-async-num", NULL); 2648d724823SNeelesh Gupta if (!async) { 265b7c670d6SRob Herring pr_err("%s: %pOF has no opal-msg-async-num\n", 266b7c670d6SRob Herring __func__, opal_node); 2678d724823SNeelesh Gupta err = -ENOENT; 2688d724823SNeelesh Gupta goto out_opal_node; 2698d724823SNeelesh Gupta } 2708d724823SNeelesh Gupta 2718d724823SNeelesh Gupta opal_max_async_tokens = be32_to_cpup(async); 27286cd6d98SCyril Bur opal_async_tokens = kcalloc(opal_max_async_tokens, 27386cd6d98SCyril Bur sizeof(*opal_async_tokens), GFP_KERNEL); 27486cd6d98SCyril Bur if (!opal_async_tokens) { 27586cd6d98SCyril Bur err = -ENOMEM; 27686cd6d98SCyril Bur goto out_opal_node; 27786cd6d98SCyril Bur } 2788d724823SNeelesh Gupta 2798d724823SNeelesh Gupta err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP, 2808d724823SNeelesh Gupta &opal_async_comp_nb); 2818d724823SNeelesh Gupta if (err) { 2828d724823SNeelesh Gupta pr_err("%s: Can't register OPAL event notifier (%d)\n", 2838d724823SNeelesh Gupta __func__, err); 28486cd6d98SCyril Bur kfree(opal_async_tokens); 2858d724823SNeelesh Gupta goto out_opal_node; 2868d724823SNeelesh Gupta } 2878d724823SNeelesh Gupta 28859cf9a1cSCyril Bur sema_init(&opal_async_sem, opal_max_async_tokens); 2898d724823SNeelesh Gupta 2908d724823SNeelesh Gupta out_opal_node: 2918d724823SNeelesh Gupta of_node_put(opal_node); 2928d724823SNeelesh Gupta out: 2938d724823SNeelesh Gupta return err; 2948d724823SNeelesh Gupta } 295