@@ -69,6 +69,54 @@ struct vas_win_task {
struct mm_struct *mm; /* Linux process mm_struct */
};
+/*
+ * In-kernel state a VAS window. One per window.
+ * powerVM: Used only for Tx windows.
+ * powerNV: Used for both Tx and Rx windows.
+ */
+struct vas_window {
+ u32 winid;
+ u32 wcreds_max; /* Window credits */
+ enum vas_cop_type cop;
+ struct vas_win_task task;
+ char *dbgname;
+ struct dentry *dbgdir;
+ union {
+ /* powerNV specific data */
+ struct {
+ void *vinst; /* points to VAS instance */
+ bool tx_win; /* True if send window */
+ bool nx_win; /* True if NX window */
+ bool user_win; /* True if user space window */
+ void *hvwc_map; /* HV window context */
+ void *uwc_map; /* OS/User window context */
+
+ /* Fields applicable only to send windows */
+ void *paste_kaddr;
+ char *paste_addr_name;
+ struct vas_window *rxwin;
+
+ atomic_t num_txwins; /* Only for receive windows */
+ } pnv;
+ struct {
+ u64 win_addr; /* Physical paste address */
+ u8 win_type; /* QoS or Default window */
+ u8 status;
+ u32 complete_irq; /* Completion interrupt */
+ u32 fault_irq; /* Fault interrupt */
+ u64 domain[6]; /* Associativity domain Ids */
+ /* this window is allocated */
+ u64 util;
+
+ /* List of windows opened which is used for LPM */
+ struct list_head win_list;
+ u64 flags;
+ char *name;
+ int fault_virq;
+ } lpar;
+ };
+};
+
static inline void vas_drop_reference_task(struct vas_win_task *task)
{
/* Drop references to pid and mm */
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <asm/vas.h>
#include "vas.h"
static struct dentry *vas_debugfs;
@@ -33,11 +34,11 @@ static int info_show(struct seq_file *s, void *private)
mutex_lock(&vas_mutex);
/* ensure window is not unmapped */
- if (!window->hvwc_map)
+ if (!window->pnv.hvwc_map)
goto unlock;
seq_printf(s, "Type: %s, %s\n", cop_to_str(window->cop),
- window->tx_win ? "Send" : "Receive");
+ window->pnv.tx_win ? "Send" : "Receive");
seq_printf(s, "Pid : %d\n", vas_window_pid(window));
unlock:
@@ -60,7 +61,7 @@ static int hvwc_show(struct seq_file *s, void *private)
mutex_lock(&vas_mutex);
/* ensure window is not unmapped */
- if (!window->hvwc_map)
+ if (!window->pnv.hvwc_map)
goto unlock;
print_reg(s, window, VREG(LPID));
@@ -115,9 +116,10 @@ void vas_window_free_dbgdir(struct vas_window *window)
void vas_window_init_dbgdir(struct vas_window *window)
{
+ struct vas_instance *vinst = window->pnv.vinst;
struct dentry *d;
- if (!window->vinst->dbgdir)
+ if (!vinst->dbgdir)
return;
window->dbgname = kzalloc(16, GFP_KERNEL);
@@ -126,7 +128,7 @@ void vas_window_init_dbgdir(struct vas_window *window)
snprintf(window->dbgname, 16, "w%d", window->winid);
- d = debugfs_create_dir(window->dbgname, window->vinst->dbgdir);
+ d = debugfs_create_dir(window->dbgname, vinst->dbgdir);
window->dbgdir = d;
debugfs_create_file("info", 0444, d, window, &info_fops);
@@ -152,10 +152,10 @@ irqreturn_t vas_fault_thread_fn(int irq, void *data)
/*
* NX sees faults only with user space windows.
*/
- if (window->user_win)
+ if (window->pnv.user_win)
vas_update_csb(crb, &window->task);
else
- WARN_ON_ONCE(!window->user_win);
+ WARN_ON_ONCE(!window->pnv.user_win);
/*
* Return credit for send window after processing
@@ -95,9 +95,11 @@ TRACE_EVENT( vas_paste_crb,
TP_fast_assign(
__entry->pid = tsk->pid;
- __entry->vasid = win->vinst->vas_id;
+ __entry->vasid =
+ ((struct vas_instance *)win->pnv.vinst)->vas_id;
__entry->winid = win->winid;
- __entry->paste_kaddr = (unsigned long)win->paste_kaddr
+ __entry->paste_kaddr =
+ (unsigned long)win->pnv.paste_kaddr;
),
TP_printk("pid=%d, vasid=%d, winid=%d, paste_kaddr=0x%016lx\n",
@@ -32,9 +32,10 @@ void vas_win_paste_addr(struct vas_window *window, u64 *addr, int *len)
{
int winid;
u64 base, shift;
+ struct vas_instance *vinst = window->pnv.vinst;
- base = window->vinst->paste_base_addr;
- shift = window->vinst->paste_win_id_shift;
+ base = vinst->paste_base_addr;
+ shift = vinst->paste_win_id_shift;
winid = window->winid;
*addr = base + (winid << shift);
@@ -47,9 +48,10 @@ void vas_win_paste_addr(struct vas_window *window, u64 *addr, int *len)
static inline void get_hvwc_mmio_bar(struct vas_window *window,
u64 *start, int *len)
{
+ struct vas_instance *vinst = window->pnv.vinst;
u64 pbaddr;
- pbaddr = window->vinst->hvwc_bar_start;
+ pbaddr = vinst->hvwc_bar_start;
*start = pbaddr + window->winid * VAS_HVWC_SIZE;
*len = VAS_HVWC_SIZE;
}
@@ -57,9 +59,10 @@ static inline void get_hvwc_mmio_bar(struct vas_window *window,
static inline void get_uwc_mmio_bar(struct vas_window *window,
u64 *start, int *len)
{
+ struct vas_instance *vinst = window->pnv.vinst;
u64 pbaddr;
- pbaddr = window->vinst->uwc_bar_start;
+ pbaddr = vinst->uwc_bar_start;
*start = pbaddr + window->winid * VAS_UWC_SIZE;
*len = VAS_UWC_SIZE;
}
@@ -75,13 +78,14 @@ static void *map_paste_region(struct vas_window *txwin)
void *map;
char *name;
u64 start;
+ struct vas_instance *vinst = txwin->pnv.vinst;
- name = kasprintf(GFP_KERNEL, "window-v%d-w%d", txwin->vinst->vas_id,
+ name = kasprintf(GFP_KERNEL, "window-v%d-w%d", vinst->vas_id,
txwin->winid);
if (!name)
goto free_name;
- txwin->paste_addr_name = name;
+ txwin->pnv.paste_addr_name = name;
vas_win_paste_addr(txwin, &start, &len);
if (!request_mem_region(start, len, name)) {
@@ -139,12 +143,12 @@ static void unmap_paste_region(struct vas_window *window)
int len;
u64 busaddr_start;
- if (window->paste_kaddr) {
+ if (window->pnv.paste_kaddr) {
vas_win_paste_addr(window, &busaddr_start, &len);
- unmap_region(window->paste_kaddr, busaddr_start, len);
- window->paste_kaddr = NULL;
- kfree(window->paste_addr_name);
- window->paste_addr_name = NULL;
+ unmap_region(window->pnv.paste_kaddr, busaddr_start, len);
+ window->pnv.paste_kaddr = NULL;
+ kfree(window->pnv.paste_addr_name);
+ window->pnv.paste_addr_name = NULL;
}
}
@@ -164,11 +168,11 @@ static void unmap_winctx_mmio_bars(struct vas_window *window)
mutex_lock(&vas_mutex);
- hvwc_map = window->hvwc_map;
- window->hvwc_map = NULL;
+ hvwc_map = window->pnv.hvwc_map;
+ window->pnv.hvwc_map = NULL;
- uwc_map = window->uwc_map;
- window->uwc_map = NULL;
+ uwc_map = window->pnv.uwc_map;
+ window->pnv.uwc_map = NULL;
mutex_unlock(&vas_mutex);
@@ -194,12 +198,12 @@ static int map_winctx_mmio_bars(struct vas_window *window)
u64 start;
get_hvwc_mmio_bar(window, &start, &len);
- window->hvwc_map = map_mmio_region("HVWCM_Window", start, len);
+ window->pnv.hvwc_map = map_mmio_region("HVWCM_Window", start, len);
get_uwc_mmio_bar(window, &start, &len);
- window->uwc_map = map_mmio_region("UWCM_Window", start, len);
+ window->pnv.uwc_map = map_mmio_region("UWCM_Window", start, len);
- if (!window->hvwc_map || !window->uwc_map) {
+ if (!window->pnv.hvwc_map || !window->pnv.uwc_map) {
unmap_winctx_mmio_bars(window);
return -1;
}
@@ -524,7 +528,7 @@ static int vas_assign_window_id(struct ida *ida)
static void vas_window_free(struct vas_window *window)
{
int winid = window->winid;
- struct vas_instance *vinst = window->vinst;
+ struct vas_instance *vinst = window->pnv.vinst;
unmap_winctx_mmio_bars(window);
@@ -548,7 +552,7 @@ static struct vas_window *vas_window_alloc(struct vas_instance *vinst)
if (!window)
goto out_free;
- window->vinst = vinst;
+ window->pnv.vinst = vinst;
window->winid = winid;
if (map_winctx_mmio_bars(window))
@@ -567,9 +571,9 @@ static struct vas_window *vas_window_alloc(struct vas_instance *vinst)
static void put_rx_win(struct vas_window *rxwin)
{
/* Better not be a send window! */
- WARN_ON_ONCE(rxwin->tx_win);
+ WARN_ON_ONCE(rxwin->pnv.tx_win);
- atomic_dec(&rxwin->num_txwins);
+ atomic_dec(&rxwin->pnv.num_txwins);
}
/*
@@ -592,7 +596,7 @@ static struct vas_window *get_user_rxwin(struct vas_instance *vinst, u32 pswid)
rxwin = vinst->windows[winid];
- if (!rxwin || rxwin->tx_win || rxwin->cop != VAS_COP_TYPE_FTW)
+ if (!rxwin || rxwin->pnv.tx_win || rxwin->cop != VAS_COP_TYPE_FTW)
return ERR_PTR(-EINVAL);
return rxwin;
@@ -617,7 +621,7 @@ static struct vas_window *get_vinst_rxwin(struct vas_instance *vinst,
rxwin = vinst->rxwin[cop] ?: ERR_PTR(-EINVAL);
if (!IS_ERR(rxwin))
- atomic_inc(&rxwin->num_txwins);
+ atomic_inc(&rxwin->pnv.num_txwins);
mutex_unlock(&vinst->mutex);
@@ -650,7 +654,7 @@ static void set_vinst_win(struct vas_instance *vinst,
* There should only be one receive window for a coprocessor type
* unless its a user (FTW) window.
*/
- if (!window->user_win && !window->tx_win) {
+ if (!window->pnv.user_win && !window->pnv.tx_win) {
WARN_ON_ONCE(vinst->rxwin[window->cop]);
vinst->rxwin[window->cop] = window;
}
@@ -668,11 +672,11 @@ static void set_vinst_win(struct vas_instance *vinst,
static void clear_vinst_win(struct vas_window *window)
{
int id = window->winid;
- struct vas_instance *vinst = window->vinst;
+ struct vas_instance *vinst = window->pnv.vinst;
mutex_lock(&vinst->mutex);
- if (!window->user_win && !window->tx_win) {
+ if (!window->pnv.user_win && !window->pnv.tx_win) {
WARN_ON_ONCE(!vinst->rxwin[window->cop]);
vinst->rxwin[window->cop] = NULL;
}
@@ -687,6 +691,8 @@ static void init_winctx_for_rxwin(struct vas_window *rxwin,
struct vas_rx_win_attr *rxattr,
struct vas_winctx *winctx)
{
+ struct vas_instance *vinst;
+
/*
* We first zero (memset()) all fields and only set non-zero fields.
* Following fields are 0/false but maybe deserve a comment:
@@ -751,8 +757,9 @@ static void init_winctx_for_rxwin(struct vas_window *rxwin,
winctx->min_scope = VAS_SCOPE_LOCAL;
winctx->max_scope = VAS_SCOPE_VECTORED_GROUP;
- if (rxwin->vinst->virq)
- winctx->irq_port = rxwin->vinst->irq_port;
+ vinst = rxwin->pnv.vinst;
+ if (vinst->virq)
+ winctx->irq_port = vinst->irq_port;
}
static bool rx_win_args_valid(enum vas_cop_type cop,
@@ -875,9 +882,9 @@ struct vas_window *vas_rx_win_open(int vasid, enum vas_cop_type cop,
return rxwin;
}
- rxwin->tx_win = false;
- rxwin->nx_win = rxattr->nx_win;
- rxwin->user_win = rxattr->user_win;
+ rxwin->pnv.tx_win = false;
+ rxwin->pnv.nx_win = rxattr->nx_win;
+ rxwin->pnv.user_win = rxattr->user_win;
rxwin->cop = cop;
rxwin->wcreds_max = rxattr->wcreds_max;
@@ -911,6 +918,8 @@ static void init_winctx_for_txwin(struct vas_window *txwin,
struct vas_tx_win_attr *txattr,
struct vas_winctx *winctx)
{
+ struct vas_instance *vinst = txwin->pnv.vinst;
+
/*
* We first zero all fields and only set non-zero ones. Following
* are some fields set to 0/false for the stated reason:
@@ -931,7 +940,7 @@ static void init_winctx_for_txwin(struct vas_window *txwin,
winctx->wcreds_max = txwin->wcreds_max;
winctx->user_win = txattr->user_win;
- winctx->nx_win = txwin->rxwin->nx_win;
+ winctx->nx_win = txwin->pnv.rxwin->pnv.nx_win;
winctx->pin_win = txattr->pin_win;
winctx->rej_no_credit = txattr->rej_no_credit;
winctx->rsvd_txbuf_enable = txattr->rsvd_txbuf_enable;
@@ -948,23 +957,23 @@ static void init_winctx_for_txwin(struct vas_window *txwin,
winctx->lpid = txattr->lpid;
winctx->pidr = txattr->pidr;
- winctx->rx_win_id = txwin->rxwin->winid;
+ winctx->rx_win_id = txwin->pnv.rxwin->winid;
/*
* IRQ and fault window setup is successful. Set fault window
* for the send window so that ready to handle faults.
*/
- if (txwin->vinst->virq)
- winctx->fault_win_id = txwin->vinst->fault_win->winid;
+ if (vinst->virq)
+ winctx->fault_win_id = vinst->fault_win->winid;
winctx->dma_type = VAS_DMA_TYPE_INJECT;
winctx->tc_mode = txattr->tc_mode;
winctx->min_scope = VAS_SCOPE_LOCAL;
winctx->max_scope = VAS_SCOPE_VECTORED_GROUP;
- if (txwin->vinst->virq)
- winctx->irq_port = txwin->vinst->irq_port;
+ if (vinst->virq)
+ winctx->irq_port = vinst->irq_port;
winctx->pswid = txattr->pswid ? txattr->pswid :
- encode_pswid(txwin->vinst->vas_id, txwin->winid);
+ encode_pswid(vinst->vas_id, txwin->winid);
}
static bool tx_win_args_valid(enum vas_cop_type cop,
@@ -1032,10 +1041,10 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
}
txwin->cop = cop;
- txwin->tx_win = 1;
- txwin->rxwin = rxwin;
- txwin->nx_win = txwin->rxwin->nx_win;
- txwin->user_win = attr->user_win;
+ txwin->pnv.tx_win = 1;
+ txwin->pnv.rxwin = rxwin;
+ txwin->pnv.nx_win = txwin->pnv.rxwin->pnv.nx_win;
+ txwin->pnv.user_win = attr->user_win;
txwin->wcreds_max = attr->wcreds_max ?: VAS_WCREDS_DEFAULT;
init_winctx_for_txwin(txwin, attr, &winctx);
@@ -1050,10 +1059,10 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
* NOTE: If kernel ever resubmits a user CRB after handling a page
* fault, we will need to map this into kernel as well.
*/
- if (!txwin->user_win) {
- txwin->paste_kaddr = map_paste_region(txwin);
- if (IS_ERR(txwin->paste_kaddr)) {
- rc = PTR_ERR(txwin->paste_kaddr);
+ if (!txwin->pnv.user_win) {
+ txwin->pnv.paste_kaddr = map_paste_region(txwin);
+ if (IS_ERR(txwin->pnv.paste_kaddr)) {
+ rc = PTR_ERR(txwin->pnv.paste_kaddr);
goto free_window;
}
} else {
@@ -1105,9 +1114,9 @@ int vas_paste_crb(struct vas_window *txwin, int offset, bool re)
* report-enable flag is set for NX windows. Ensure software
* complies too.
*/
- WARN_ON_ONCE(txwin->nx_win && !re);
+ WARN_ON_ONCE(txwin->pnv.nx_win && !re);
- addr = txwin->paste_kaddr;
+ addr = txwin->pnv.paste_kaddr;
if (re) {
/*
* Set the REPORT_ENABLE bit (equivalent to writing
@@ -1154,7 +1163,7 @@ static void poll_window_credits(struct vas_window *window)
int count = 0;
val = read_hvwc_reg(window, VREG(WINCTL));
- if (window->tx_win)
+ if (window->pnv.tx_win)
mode = GET_FIELD(VAS_WINCTL_TX_WCRED_MODE, val);
else
mode = GET_FIELD(VAS_WINCTL_RX_WCRED_MODE, val);
@@ -1162,7 +1171,7 @@ static void poll_window_credits(struct vas_window *window)
if (!mode)
return;
retry:
- if (window->tx_win) {
+ if (window->pnv.tx_win) {
val = read_hvwc_reg(window, VREG(TX_WCRED));
creds = GET_FIELD(VAS_TX_WCRED, val);
} else {
@@ -1278,7 +1287,7 @@ int vas_win_close(struct vas_window *window)
if (!window)
return 0;
- if (!window->tx_win && atomic_read(&window->num_txwins) != 0) {
+ if (!window->pnv.tx_win && atomic_read(&window->pnv.num_txwins) != 0) {
pr_devel("Attempting to close an active Rx window!\n");
WARN_ON_ONCE(1);
return -EBUSY;
@@ -1297,11 +1306,11 @@ int vas_win_close(struct vas_window *window)
poll_window_castout(window);
/* if send window, drop reference to matching receive window */
- if (window->tx_win) {
- if (window->user_win)
+ if (window->pnv.tx_win) {
+ if (window->pnv.user_win)
vas_drop_reference_task(&window->task);
- put_rx_win(window->rxwin);
+ put_rx_win(window->pnv.rxwin);
}
vas_window_free(window);
@@ -1385,12 +1394,12 @@ struct vas_window *vas_pswid_to_window(struct vas_instance *vinst,
* since their CRBs are ignored (not queued on FIFO or processed
* by NX).
*/
- if (!window->tx_win || !window->user_win || !window->nx_win ||
- window->cop == VAS_COP_TYPE_FAULT ||
- window->cop == VAS_COP_TYPE_FTW) {
+ if (!window->pnv.tx_win || !window->pnv.user_win ||
+ !window->pnv.nx_win || window->cop == VAS_COP_TYPE_FAULT ||
+ window->cop == VAS_COP_TYPE_FTW) {
pr_err("PSWID decode: id %d, tx %d, user %d, nx %d, cop %d\n",
- winid, window->tx_win, window->user_win,
- window->nx_win, window->cop);
+ winid, window->pnv.tx_win, window->pnv.user_win,
+ window->pnv.nx_win, window->cop);
WARN_ON(1);
}
@@ -345,34 +345,6 @@ struct vas_instance {
struct dentry *dbgdir;
};
-/*
- * In-kernel state a VAS window. One per window.
- */
-struct vas_window {
- /* Fields common to send and receive windows */
- struct vas_instance *vinst;
- int winid;
- bool tx_win; /* True if send window */
- bool nx_win; /* True if NX window */
- bool user_win; /* True if user space window */
- void *hvwc_map; /* HV window context */
- void *uwc_map; /* OS/User window context */
- int wcreds_max; /* Window credits */
-
- struct vas_win_task task;
- char *dbgname;
- struct dentry *dbgdir;
-
- /* Fields applicable only to send windows */
- void *paste_kaddr;
- char *paste_addr_name;
- struct vas_window *rxwin;
-
- /* Feilds applicable only to receive windows */
- enum vas_cop_type cop;
- atomic_t num_txwins;
-};
-
/*
* Container for the hardware state of a window. One per-window.
*
@@ -449,8 +421,8 @@ static inline void vas_log_write(struct vas_window *win, char *name,
{
if (val)
pr_debug("%swin #%d: %s reg %p, val 0x%016llx\n",
- win->tx_win ? "Tx" : "Rx", win->winid, name,
- regptr, val);
+ win->pnv.tx_win ? "Tx" : "Rx", win->winid,
+ name, regptr, val);
}
static inline void write_uwc_reg(struct vas_window *win, char *name,
@@ -458,7 +430,7 @@ static inline void write_uwc_reg(struct vas_window *win, char *name,
{
void *regptr;
- regptr = win->uwc_map + reg;
+ regptr = win->pnv.uwc_map + reg;
vas_log_write(win, name, regptr, val);
out_be64(regptr, val);
@@ -469,7 +441,7 @@ static inline void write_hvwc_reg(struct vas_window *win, char *name,
{
void *regptr;
- regptr = win->hvwc_map + reg;
+ regptr = win->pnv.hvwc_map + reg;
vas_log_write(win, name, regptr, val);
out_be64(regptr, val);
@@ -478,7 +450,7 @@ static inline void write_hvwc_reg(struct vas_window *win, char *name,
static inline u64 read_hvwc_reg(struct vas_window *win,
char *name __maybe_unused, s32 reg)
{
- return in_be64(win->hvwc_map+reg);
+ return in_be64(win->pnv.hvwc_map + reg);
}
/*
Same vas_window struct is used on powerNV and pseries. So this patch changes in struct vas_window to support both platforms and also the corresponding modifications in powerNV vas code. On powerNV vas_window is used for both TX and RX windows, whereas only for TX windows on powerVM. So some elements are specific to these platforms. Signed-off-by: Haren Myneni <haren@linux.ibm.com> --- arch/powerpc/include/asm/vas.h | 48 ++++++++ arch/powerpc/platforms/powernv/vas-debug.c | 12 +- arch/powerpc/platforms/powernv/vas-fault.c | 4 +- arch/powerpc/platforms/powernv/vas-trace.h | 6 +- arch/powerpc/platforms/powernv/vas-window.c | 129 +++++++++++--------- arch/powerpc/platforms/powernv/vas.h | 38 +----- 6 files changed, 135 insertions(+), 102 deletions(-)