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 kenrel 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 <suka...@linux.vnet.ibm.com> --- arch/powerpc/include/asm/vas.h | 39 +++++++++ drivers/misc/vas/vas-internal.h | 11 +++ drivers/misc/vas/vas-window.c | 182 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h index fef9e87..b6362e9 100644 --- a/arch/powerpc/include/asm/vas.h +++ b/arch/powerpc/include/asm/vas.h @@ -38,6 +38,45 @@ enum vas_thresh_ctl { }; /* + * 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 notify_disable; + bool intr_disable; + bool notify_early; + + int lnotify_lpid; + int lnotify_pid; + int lnotify_tid; + int pswid; + + enum vas_thresh_ctl tc_mode; +}; + +/* + * 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); + + +/* * Get/Set bit fields */ #define GET_FIELD(m, v) (((v) & (m)) >> MASK_LSH(m)) diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h index 0a396ea..139d12a 100644 --- a/drivers/misc/vas/vas-internal.h +++ b/drivers/misc/vas/vas-internal.h @@ -396,6 +396,16 @@ extern struct vas_instance *find_vas_instance(int vasid); #define VREG(r) VREG_SFX(r, _OFFSET) #ifndef 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, uint64_t val) { @@ -408,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 */ diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c index 3ea698a..a640d59 100644 --- a/drivers/misc/vas/vas-window.c +++ b/drivers/misc/vas/vas-window.c @@ -529,3 +529,185 @@ int vas_window_reset(struct vas_instance *vinst, int winid) return 0; } + +static void put_rx_win(struct vas_window *rxwin) +{ + /* Better not be a send window! */ + WARN_ON_ONCE(rxwin->tx_win); + + atomic_dec(&rxwin->num_txwins); +} + +struct vas_window *get_vinstance_rxwin(struct vas_instance *vinst, + enum vas_cop_type cop) +{ + struct vas_window *rxwin; + + mutex_lock(&vinst->mutex); + + rxwin = vinst->rxwin[cop]; + if (rxwin) + atomic_inc(&rxwin->num_txwins); + + mutex_unlock(&vinst->mutex); + + return rxwin; +} + +static void set_vinstance_rxwin(struct vas_instance *vinst, + enum vas_cop_type cop, struct vas_window *window) +{ + mutex_lock(&vinst->mutex); + + /* + * There should only be one receive window for a coprocessor type. + */ + WARN_ON_ONCE(vinst->rxwin[cop]); + vinst->rxwin[cop] = window; + + 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: + * + * ->user_win No support for user Rx windows yet + * ->notify_os_intr_reg In powerNV, send intrs to HV + * ->notify_disable False for NX 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 = true; + winctx->tx_word_mode = true; + + winctx->fault_win_id = fault_winid; + + 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); + } + + /* TODO: Are irq ports required for NX receive windows? */ + winctx->irq_port = rxwin->irq_port; + + 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 (attr->rx_fifo_size > VAS_RX_FIFO_SIZE_MAX) + return false; + + if (attr->nx_win) { + /* cannot be both fault and nx */ + if (attr->fault_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) { + /* + * Section 3.1.4.32: Fault windows must disable notification + * but not interrupts. + */ + if (!attr->notify_disable || attr->intr_disable) + return false; + } else { + /* Rx window must be either NX or Fault window for now. */ + return false; + } + + return true; +} + +struct vas_window *vas_rx_win_open(int vasid, enum vas_cop_type cop, + struct vas_rx_win_attr *rxattr) +{ + int rc, winid; + struct vas_instance *vinst; + struct vas_window *rxwin; + struct vas_winctx winctx; + + if (!vas_initialized) + return ERR_PTR(-EAGAIN); + + if (!rx_win_args_valid(cop, rxattr)) + return ERR_PTR(-EINVAL); + + vinst = find_vas_instance(vasid); + if (!vinst) { + pr_devel("VAS: vasid %d not found!\n", vasid); + return ERR_PTR(-EINVAL); + } + pr_devel("VAS: Found instance %d\n", vasid); + + winid = vas_assign_window_id(&vinst->ida); + if (winid < 0) + return ERR_PTR(winid); + + rc = -ENOMEM; + rxwin = vas_window_alloc(vinst, winid); + if (!rxwin) { + pr_devel("VAS: Unable to allocate memory for Rx window\n"); + goto release_winid; + } + + rxwin->tx_win = false; + rxwin->cop = cop; + + init_winctx_for_rxwin(rxwin, rxattr, &winctx); + rxwin->nx_win = winctx.nx_win; + init_winctx_regs(rxwin, &winctx); + + set_vinstance_rxwin(vinst, cop, rxwin); + + if (winctx.fault_win) + fault_winid = winid; + + return rxwin; + +release_winid: + vas_release_window_id(&vinst->ida, rxwin->winid); + return ERR_PTR(rc); +} -- 2.7.4