forked from Minki/linux
powerpc/powernv/vas: Define vas_rx_win_open() interface
Define the vas_rx_win_open() interface. This interface is intended to be used by the Nest Accelerator (NX) driver(s) to setup receive windows for one or more NX engines (which implement compression & encryption algorithms in the hardware). Follow-on patches will provide an interface to close the window and to open a send window that kernel subsystems can use to access the NX engines. The interface to open a receive window is expected to be invoked for each instance of VAS in the system. Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
bbfe59f8a7
commit
62c4eda4fa
@ -50,4 +50,49 @@ enum vas_cop_type {
|
||||
VAS_COP_TYPE_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Receive window attributes specified by the (in-kernel) owner of window.
|
||||
*/
|
||||
struct vas_rx_win_attr {
|
||||
void *rx_fifo;
|
||||
int rx_fifo_size;
|
||||
int wcreds_max;
|
||||
|
||||
bool pin_win;
|
||||
bool rej_no_credit;
|
||||
bool tx_wcred_mode;
|
||||
bool rx_wcred_mode;
|
||||
bool tx_win_ord_mode;
|
||||
bool rx_win_ord_mode;
|
||||
bool data_stamp;
|
||||
bool nx_win;
|
||||
bool fault_win;
|
||||
bool user_win;
|
||||
bool notify_disable;
|
||||
bool intr_disable;
|
||||
bool notify_early;
|
||||
|
||||
int lnotify_lpid;
|
||||
int lnotify_pid;
|
||||
int lnotify_tid;
|
||||
u32 pswid;
|
||||
|
||||
int tc_mode;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper to initialize receive window attributes to defaults for an
|
||||
* NX window.
|
||||
*/
|
||||
void vas_init_rx_win_attr(struct vas_rx_win_attr *rxattr, enum vas_cop_type cop);
|
||||
|
||||
/*
|
||||
* Open a VAS receive window for the instance of VAS identified by @vasid
|
||||
* Use @attr to initialize the attributes of the window.
|
||||
*
|
||||
* Return a handle to the window or ERR_PTR() on error.
|
||||
*/
|
||||
struct vas_window *vas_rx_win_open(int vasid, enum vas_cop_type cop,
|
||||
struct vas_rx_win_attr *attr);
|
||||
|
||||
#endif /* __ASM_POWERPC_VAS_H */
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/cred.h>
|
||||
|
||||
#include "vas.h"
|
||||
|
||||
@ -531,7 +533,7 @@ void vas_window_free(struct vas_window *window)
|
||||
vas_release_window_id(&vinst->ida, winid);
|
||||
}
|
||||
|
||||
struct vas_window *vas_window_alloc(struct vas_instance *vinst)
|
||||
static struct vas_window *vas_window_alloc(struct vas_instance *vinst)
|
||||
{
|
||||
int winid;
|
||||
struct vas_window *window;
|
||||
@ -558,6 +560,285 @@ out_free:
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the VAS receive window associated with NX engine identified
|
||||
* by @cop and if applicable, @pswid.
|
||||
*
|
||||
* See also function header of set_vinst_win().
|
||||
*/
|
||||
struct vas_window *get_vinst_rxwin(struct vas_instance *vinst,
|
||||
enum vas_cop_type cop, u32 pswid)
|
||||
{
|
||||
struct vas_window *rxwin;
|
||||
|
||||
mutex_lock(&vinst->mutex);
|
||||
|
||||
if (cop == VAS_COP_TYPE_842 || cop == VAS_COP_TYPE_842_HIPRI)
|
||||
rxwin = vinst->rxwin[cop] ?: ERR_PTR(-EINVAL);
|
||||
else
|
||||
rxwin = ERR_PTR(-EINVAL);
|
||||
|
||||
if (!IS_ERR(rxwin))
|
||||
atomic_inc(&rxwin->num_txwins);
|
||||
|
||||
mutex_unlock(&vinst->mutex);
|
||||
|
||||
return rxwin;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have two tables of windows in a VAS instance. The first one,
|
||||
* ->windows[], contains all the windows in the instance and allows
|
||||
* looking up a window by its id. It is used to look up send windows
|
||||
* during fault handling and receive windows when pairing user space
|
||||
* send/receive windows.
|
||||
*
|
||||
* The second table, ->rxwin[], contains receive windows that are
|
||||
* associated with NX engines. This table has VAS_COP_TYPE_MAX
|
||||
* entries and is used to look up a receive window by its
|
||||
* coprocessor type.
|
||||
*
|
||||
* Here, we save @window in the ->windows[] table. If it is a receive
|
||||
* window, we also save the window in the ->rxwin[] table.
|
||||
*/
|
||||
static void set_vinst_win(struct vas_instance *vinst,
|
||||
struct vas_window *window)
|
||||
{
|
||||
int id = window->winid;
|
||||
|
||||
mutex_lock(&vinst->mutex);
|
||||
|
||||
/*
|
||||
* There should only be one receive window for a coprocessor type
|
||||
* unless its a user (FTW) window.
|
||||
*/
|
||||
if (!window->user_win && !window->tx_win) {
|
||||
WARN_ON_ONCE(vinst->rxwin[window->cop]);
|
||||
vinst->rxwin[window->cop] = window;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(vinst->windows[id] != NULL);
|
||||
vinst->windows[id] = window;
|
||||
|
||||
mutex_unlock(&vinst->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear this window from the table(s) of windows for this VAS instance.
|
||||
* See also function header of set_vinst_win().
|
||||
*/
|
||||
void clear_vinst_win(struct vas_window *window)
|
||||
{
|
||||
int id = window->winid;
|
||||
struct vas_instance *vinst = window->vinst;
|
||||
|
||||
mutex_lock(&vinst->mutex);
|
||||
|
||||
if (!window->user_win && !window->tx_win) {
|
||||
WARN_ON_ONCE(!vinst->rxwin[window->cop]);
|
||||
vinst->rxwin[window->cop] = NULL;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(vinst->windows[id] != window);
|
||||
vinst->windows[id] = NULL;
|
||||
|
||||
mutex_unlock(&vinst->mutex);
|
||||
}
|
||||
|
||||
static void init_winctx_for_rxwin(struct vas_window *rxwin,
|
||||
struct vas_rx_win_attr *rxattr,
|
||||
struct vas_winctx *winctx)
|
||||
{
|
||||
/*
|
||||
* We first zero (memset()) all fields and only set non-zero fields.
|
||||
* Following fields are 0/false but maybe deserve a comment:
|
||||
*
|
||||
* ->notify_os_intr_reg In powerNV, send intrs to HV
|
||||
* ->notify_disable False for NX windows
|
||||
* ->intr_disable False for Fault Windows
|
||||
* ->xtra_write False for NX windows
|
||||
* ->notify_early NA for NX windows
|
||||
* ->rsvd_txbuf_count NA for Rx windows
|
||||
* ->lpid, ->pid, ->tid NA for Rx windows
|
||||
*/
|
||||
|
||||
memset(winctx, 0, sizeof(struct vas_winctx));
|
||||
|
||||
winctx->rx_fifo = rxattr->rx_fifo;
|
||||
winctx->rx_fifo_size = rxattr->rx_fifo_size;
|
||||
winctx->wcreds_max = rxattr->wcreds_max ?: VAS_WCREDS_DEFAULT;
|
||||
winctx->pin_win = rxattr->pin_win;
|
||||
|
||||
winctx->nx_win = rxattr->nx_win;
|
||||
winctx->fault_win = rxattr->fault_win;
|
||||
winctx->rx_word_mode = rxattr->rx_win_ord_mode;
|
||||
winctx->tx_word_mode = rxattr->tx_win_ord_mode;
|
||||
winctx->rx_wcred_mode = rxattr->rx_wcred_mode;
|
||||
winctx->tx_wcred_mode = rxattr->tx_wcred_mode;
|
||||
|
||||
if (winctx->nx_win) {
|
||||
winctx->data_stamp = true;
|
||||
winctx->intr_disable = true;
|
||||
winctx->pin_win = true;
|
||||
|
||||
WARN_ON_ONCE(winctx->fault_win);
|
||||
WARN_ON_ONCE(!winctx->rx_word_mode);
|
||||
WARN_ON_ONCE(!winctx->tx_word_mode);
|
||||
WARN_ON_ONCE(winctx->notify_after_count);
|
||||
} else if (winctx->fault_win) {
|
||||
winctx->notify_disable = true;
|
||||
} else if (winctx->user_win) {
|
||||
/*
|
||||
* Section 1.8.1 Low Latency Core-Core Wake up of
|
||||
* the VAS workbook:
|
||||
*
|
||||
* - disable credit checks ([tr]x_wcred_mode = false)
|
||||
* - disable FIFO writes
|
||||
* - enable ASB_Notify, disable interrupt
|
||||
*/
|
||||
winctx->fifo_disable = true;
|
||||
winctx->intr_disable = true;
|
||||
winctx->rx_fifo = NULL;
|
||||
}
|
||||
|
||||
winctx->lnotify_lpid = rxattr->lnotify_lpid;
|
||||
winctx->lnotify_pid = rxattr->lnotify_pid;
|
||||
winctx->lnotify_tid = rxattr->lnotify_tid;
|
||||
winctx->pswid = rxattr->pswid;
|
||||
winctx->dma_type = VAS_DMA_TYPE_INJECT;
|
||||
winctx->tc_mode = rxattr->tc_mode;
|
||||
|
||||
winctx->min_scope = VAS_SCOPE_LOCAL;
|
||||
winctx->max_scope = VAS_SCOPE_VECTORED_GROUP;
|
||||
}
|
||||
|
||||
static bool rx_win_args_valid(enum vas_cop_type cop,
|
||||
struct vas_rx_win_attr *attr)
|
||||
{
|
||||
dump_rx_win_attr(attr);
|
||||
|
||||
if (cop >= VAS_COP_TYPE_MAX)
|
||||
return false;
|
||||
|
||||
if (cop != VAS_COP_TYPE_FTW &&
|
||||
attr->rx_fifo_size < VAS_RX_FIFO_SIZE_MIN)
|
||||
return false;
|
||||
|
||||
if (attr->rx_fifo_size > VAS_RX_FIFO_SIZE_MAX)
|
||||
return false;
|
||||
|
||||
if (attr->nx_win) {
|
||||
/* cannot be fault or user window if it is nx */
|
||||
if (attr->fault_win || attr->user_win)
|
||||
return false;
|
||||
/*
|
||||
* Section 3.1.4.32: NX Windows must not disable notification,
|
||||
* and must not enable interrupts or early notification.
|
||||
*/
|
||||
if (attr->notify_disable || !attr->intr_disable ||
|
||||
attr->notify_early)
|
||||
return false;
|
||||
} else if (attr->fault_win) {
|
||||
/* cannot be both fault and user window */
|
||||
if (attr->user_win)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Section 3.1.4.32: Fault windows must disable notification
|
||||
* but not interrupts.
|
||||
*/
|
||||
if (!attr->notify_disable || attr->intr_disable)
|
||||
return false;
|
||||
|
||||
} else if (attr->user_win) {
|
||||
/*
|
||||
* User receive windows are only for fast-thread-wakeup
|
||||
* (FTW). They don't need a FIFO and must disable interrupts
|
||||
*/
|
||||
if (attr->rx_fifo || attr->rx_fifo_size || !attr->intr_disable)
|
||||
return false;
|
||||
} else {
|
||||
/* Rx window must be one of NX or Fault or User window. */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vas_init_rx_win_attr(struct vas_rx_win_attr *rxattr, enum vas_cop_type cop)
|
||||
{
|
||||
memset(rxattr, 0, sizeof(*rxattr));
|
||||
|
||||
if (cop == VAS_COP_TYPE_842 || cop == VAS_COP_TYPE_842_HIPRI) {
|
||||
rxattr->pin_win = true;
|
||||
rxattr->nx_win = true;
|
||||
rxattr->fault_win = false;
|
||||
rxattr->intr_disable = true;
|
||||
rxattr->rx_wcred_mode = true;
|
||||
rxattr->tx_wcred_mode = true;
|
||||
rxattr->rx_win_ord_mode = true;
|
||||
rxattr->tx_win_ord_mode = true;
|
||||
} else if (cop == VAS_COP_TYPE_FAULT) {
|
||||
rxattr->pin_win = true;
|
||||
rxattr->fault_win = true;
|
||||
rxattr->notify_disable = true;
|
||||
rxattr->rx_wcred_mode = true;
|
||||
rxattr->tx_wcred_mode = true;
|
||||
rxattr->rx_win_ord_mode = true;
|
||||
rxattr->tx_win_ord_mode = true;
|
||||
} else if (cop == VAS_COP_TYPE_FTW) {
|
||||
rxattr->user_win = true;
|
||||
rxattr->intr_disable = true;
|
||||
|
||||
/*
|
||||
* As noted in the VAS Workbook we disable credit checks.
|
||||
* If we enable credit checks in the future, we must also
|
||||
* implement a mechanism to return the user credits or new
|
||||
* paste operations will fail.
|
||||
*/
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vas_init_rx_win_attr);
|
||||
|
||||
struct vas_window *vas_rx_win_open(int vasid, enum vas_cop_type cop,
|
||||
struct vas_rx_win_attr *rxattr)
|
||||
{
|
||||
struct vas_window *rxwin;
|
||||
struct vas_winctx winctx;
|
||||
struct vas_instance *vinst;
|
||||
|
||||
if (!rx_win_args_valid(cop, rxattr))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
vinst = find_vas_instance(vasid);
|
||||
if (!vinst) {
|
||||
pr_devel("vasid %d not found!\n", vasid);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
pr_devel("Found instance %d\n", vasid);
|
||||
|
||||
rxwin = vas_window_alloc(vinst);
|
||||
if (IS_ERR(rxwin)) {
|
||||
pr_devel("Unable to allocate memory for Rx window\n");
|
||||
return rxwin;
|
||||
}
|
||||
|
||||
rxwin->tx_win = false;
|
||||
rxwin->nx_win = rxattr->nx_win;
|
||||
rxwin->user_win = rxattr->user_win;
|
||||
rxwin->cop = cop;
|
||||
if (rxattr->user_win)
|
||||
rxwin->pid = task_pid_vnr(current);
|
||||
|
||||
init_winctx_for_rxwin(rxwin, rxattr, &winctx);
|
||||
init_winctx_regs(rxwin, &winctx);
|
||||
|
||||
set_vinst_win(vinst, rxwin);
|
||||
|
||||
return rxwin;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vas_rx_win_open);
|
||||
|
||||
/* stub for now */
|
||||
int vas_win_close(struct vas_window *window)
|
||||
{
|
||||
|
@ -289,6 +289,9 @@ enum vas_notify_after_count {
|
||||
/*
|
||||
* One per instance of VAS. Each instance will have a separate set of
|
||||
* receive windows, one per coprocessor type.
|
||||
*
|
||||
* See also function header of set_vinst_win() for details on ->windows[]
|
||||
* and ->rxwin[] tables.
|
||||
*/
|
||||
struct vas_instance {
|
||||
int vas_id;
|
||||
@ -393,6 +396,16 @@ extern struct vas_instance *find_vas_instance(int vasid);
|
||||
#define VREG(r) VREG_SFX(r, _OFFSET)
|
||||
|
||||
#ifdef vas_debug
|
||||
static inline void dump_rx_win_attr(struct vas_rx_win_attr *attr)
|
||||
{
|
||||
pr_err("VAS: fault %d, notify %d, intr %d early %d\n",
|
||||
attr->fault_win, attr->notify_disable,
|
||||
attr->intr_disable, attr->notify_early);
|
||||
|
||||
pr_err("VAS: rx_fifo_size %d, max value %d\n",
|
||||
attr->rx_fifo_size, VAS_RX_FIFO_SIZE_MAX);
|
||||
}
|
||||
|
||||
static inline void vas_log_write(struct vas_window *win, char *name,
|
||||
void *regptr, u64 val)
|
||||
{
|
||||
@ -405,6 +418,7 @@ static inline void vas_log_write(struct vas_window *win, char *name,
|
||||
#else /* vas_debug */
|
||||
|
||||
#define vas_log_write(win, name, reg, val)
|
||||
#define dump_rx_win_attr(attr)
|
||||
|
||||
#endif /* vas_debug */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user