/* * Overview of Virtual Accelerator Switchboard (VAS). * * VAS is a hardware "switchboard" that allows senders and receivers to * exchange messages with _minimal_ kernel involvment. The receivers are * typically NX coprocessor engines that perform compression or encryption * in hardware, but receivers can also be other software threads. * * Senders are user/kernel threads that submit compression/encryption or * other requests to the receivers. Senders must format their messages as * Coprocessor Request Blocks (CRB)s and submit them using the "copy" and * "paste" instructions which were introduced in Power9. * * A Power node can have (upto?) 8 Power chips. There is one instance of * VAS in each Power9 chip. Each instance of VAS has 64K windows or ports, * Senders and receivers must each connect to a separate window before they * can exchange messages through the switchboard. * * Each window is described by two types of window contexts: * * Hypervisor Window Context (HVWC) of size VAS_HVWC_SIZE bytes * * OS/User Window Context (UWC) of size VAS_UWC_SIZE bytes. * * A window context can be viewed as a set of 64-bit registers. The settings * in these registers configure/control/determine the behavior of the VAS * hardware when messages are sent/received through the window. The registers * in the HVWC are configured by the kernel while the registers in the UWC can * be configured by the kernel or by the user space application that is using * the window. * * The HVWCs for all windows on a specific instance of VAS are in a contiguous * range of hardware addresses or Base address region (BAR) referred to as the * HVWC BAR for the instance. Similarly the UWCs for all windows on an instance * are referred to as the UWC BAR for the instance. * * The two BARs for each instance are defined Power9 MMIO Ranges spreadsheet * and available to the kernel in the VAS node's "reg" property in the device * tree: * * /proc/device-tree/vasm@.../reg * * (see vas_probe() for details on the reg property). * * The kernel maps the HVWC and UWC BAR regions into the kernel address * space (hvwc_map and uwc_map). The kernel can then access the window * contexts of a specific window using: * * hvwc = hvwc_map + winid * VAS_HVWC_SIZE. * uwc = uwc_map + winid * VAS_UWC_SIZE. * * where winid is the window index (0..64K). * * As mentioned, a window context is used to "configure" a window. Besides * this configuration address, each _send_ window also has a unique hardware * "paste" address that is used to submit requests/CRBs (see vas_paste_crb()). * * The hardware paste address for a window is computed using the "paste * base address" and "paste win id shift" reg properties in the VAS device * tree node using: * * paste_addr = paste_base + ((winid << paste_win_id_shift)) * * (again, see vas_probe() for ->paste_base_addr and ->paste_win_id_shift). * * The kernel maps this hardware address into the sender's address space * after which they can use the 'paste' instruction (new in Power9) to * send a message (submit a request aka CRB) to the coprocessor. * * NOTE: In the initial version, senders can only in-kernel drivers/threads. * Support for user space threads will be added in follow-on patches. * * TODO: Do we need to map the UWC into user address space so they can return * credits? Its NA for NX but may be needed for other receive windows. *
*/
/* * VAS Window Context Register Offsets and bitmasks. * See Section 3.1.4 of VAS Work book
*/ #define VAS_LPID_OFFSET 0x010 #define VAS_LPID PPC_BITMASK(0, 11)
/* * Local Notification Control Register controls what happens in _response_ * to a paste command and hence applies only to receive windows.
*/ #define VAS_LNOTIFY_CTL_OFFSET 0x138 #define VAS_NOTIFY_DISABLE PPC_BIT(0) #define VAS_INTR_DISABLE PPC_BIT(1) #define VAS_NOTIFY_EARLY PPC_BIT(2) #define VAS_NOTIFY_OSU_INTR PPC_BIT(3)
/* * VREG(x): * Expand a register's short name (eg: LPID) into two parameters: * - the register's short name in string form ("LPID"), and * - the name of the macro (eg: VAS_LPID_OFFSET), defining the * register's offset in the window context
*/ #define VREG_SFX(n, s) __stringify(n), VAS_##n##s #define VREG(r) VREG_SFX(r, _OFFSET)
/* * Local Notify Scope Control Register. (Receive windows only).
*/ enum vas_notify_scope {
VAS_SCOPE_LOCAL,
VAS_SCOPE_GROUP,
VAS_SCOPE_VECTORED_GROUP,
VAS_SCOPE_UNUSED,
};
/* * Local DMA Cache Control Register (Receive windows only).
*/ enum vas_dma_type {
VAS_DMA_TYPE_INJECT,
VAS_DMA_TYPE_WRITE,
};
/* * Local Notify Scope Control Register. (Receive windows only). * Not applicable to NX receive windows.
*/ enum vas_notify_after_count {
VAS_NOTIFY_AFTER_256 = 0,
VAS_NOTIFY_NONE,
VAS_NOTIFY_AFTER_2
};
/* * NX can generate an interrupt for multiple faults and expects kernel * to process all of them. So read all valid CRB entries until find the * invalid one. So use pswid which is pasted by NX and ccw[0] (reserved * bit in BE) to check valid CRB. CCW[0] will not be touched by user * space. Application gets CRB formt error if it updates this bit. * * Invalidate FIFO during allocation and process all entries from last * successful read until finds invalid pswid and ccw[0] values. * After reading each CRB entry from fault FIFO, the kernel invalidate * it by updating pswid with FIFO_INVALID_ENTRY and CCW[0] with * CCW0_INVALID.
*/ #define FIFO_INVALID_ENTRY 0xffffffff #define CCW0_INVALID 1
/* * 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; struct ida ida; struct list_head node; struct platform_device *pdev;
u64 irq_port; int virq; int fault_crbs; int fault_fifo_size; int fifo_in_progress; /* To wake up thread or return IRQ_HANDLED */
spinlock_t fault_lock; /* Protects fifo_in_progress update */ void *fault_fifo; struct pnv_vas_window *fault_win; /* Fault window */
/* * In-kernel state a VAS window on PowerNV. One per window.
*/ struct pnv_vas_window { struct vas_window vas_win; /* Fields common to send and receive windows */ struct vas_instance *vinst; 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 pnv_vas_window *rxwin;
/* Fields applicable only to receive windows */
atomic_t num_txwins;
};
/* * Container for the hardware state of a window. One per-window. * * A VAS Window context is a 512-byte area in the hardware that contains * a set of 64-bit registers. Individual bit-fields in these registers * determine the configuration/operation of the hardware. struct vas_winctx * is a container for the register fields in the window context.
*/ struct vas_winctx {
u64 rx_fifo; int rx_fifo_size; int wcreds_max; int rsvd_txbuf_count;
int lpid; int pidr; /* value from SPRN_PID, not linux pid */ int lnotify_lpid; int lnotify_pid; int lnotify_tid;
u32 pswid; int rx_win_id; int fault_win_id; int tc_mode;
/* * Encode/decode the Partition Send Window ID (PSWID) for a window in * a way that we can uniquely identify any window in the system. i.e. * we should be able to locate the 'struct vas_window' given the PSWID. * * Bits Usage * 0:7 VAS id (8 bits) * 8:15 Unused, 0 (3 bits) * 16:31 Window id (16 bits)
*/ staticinline u32 encode_pswid(int vasid, int winid)
{ return ((u32)winid | (vasid << (31 - 7)));
}
staticinlinevoid decode_pswid(u32 pswid, int *vasid, int *winid)
{ if (vasid)
*vasid = pswid >> (31 - 7) & 0xFF;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.