Define some helper functions to access the MMIO regions. We use these in a follow-on patches to read/write VAS hardware registers. These helpers are also used to later issue 'paste' instructions to submit requests to the NX hardware engines.
Signed-off-by: Sukadev Bhattiprolu <suka...@linux.vnet.ibm.com> --- drivers/misc/vas/vas-window.c | 182 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c index 468f3bf..2c220a3 100644 --- a/drivers/misc/vas/vas-window.c +++ b/drivers/misc/vas/vas-window.c @@ -9,9 +9,191 @@ #include <linux/types.h> #include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/io.h> #include <asm/vas.h> #include "vas-internal.h" +/* + * Using the node, chip and window id for the send winow identified by + * @window, compute and return the Power Bus address to which a sender + * could issue a paste instruction for this window. + * + * Refer to Tables 1.1 through 1.4 in Section 1.3.3.1 (Send Message w/Paste + * Commands (cl_rma_w)) of VAS P9 Workbook for the PowerBus Address usage + * in VAS. + * + * With 64K mode and Large SMP Mode the bits are used as follows: + * + * Bits Values Comments + * -------------------------------------- + * 0:7 0b 0000_0000 Reserved + * 8:12 0b 0000_1 System id/Foreign Index 0:4 + * 13:14 0b 00 Foreign Index 5:6 + * + * 15:18 0 throuh 15 Node id (0 through 15) + * 19:21 0 through 7 Chip id (0 throuh 7) + * 22:23 0b 00 Unused, Foreign index 7:8 + * + * 24:31 0b 0000_0000 RPN 0:7, Reserved + * 32:47 0 through 64K Send Window Id + * 48:51 0b 0000 Spare + * + * 52 0b 0 Reserved + * 53 0b 1 Report Enable (Set to 1 for NX). + * 54 0b 0 Reserved + * + * 55:56 0b 00 Snoop Bus + * 57:63 0b 0000_000 Reserved + * + * Except for a few bits, the small SMP mode computation is similar. + * + * TODO: Detect and compute address for small SMP mode. + * + * Example: For Node 0, Chip 0, Window id 4, Report Enable 1: + * + * Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 + * 00000000 00001000 00000000 00000000 00000000 00000100 00000100 00000000 + * | | | + * +-------+-------+ v + * | Report Enable + * v + * Window id 4 + * + * Thus, the paste address is 0x00080000_00040400. + */ +#define RMA_LSMP_64K_SYS_ID PPC_BITMASK(8, 12) +#define RMA_LSMP_64K_NODE_ID PPC_BITMASK(15, 18) +#define RMA_LSMP_64K_CHIP_ID PPC_BITMASK(19, 21) +#define RMA_LSMP_64K_TX_WIN_ID PPC_BITMASK(32, 47) +#define RMA_LSMP_REPORT_ENABLE PPC_BIT(53) + +uint64_t compute_paste_address(struct vas_window *window, int *size) +{ + int node, chip, winid; + uint64_t val = 0ULL; + + node = window->vinst->node; + chip = window->vinst->chip; + winid = window->winid; + + *size = PAGE_SIZE; + + val = SET_FIELD(RMA_LSMP_64K_SYS_ID, val, 1); + val = SET_FIELD(RMA_LSMP_64K_NODE_ID, val, node); + val = SET_FIELD(RMA_LSMP_64K_CHIP_ID, val, chip); + val = SET_FIELD(RMA_LSMP_64K_TX_WIN_ID, val, winid); + val = SET_FIELD(RMA_LSMP_REPORT_ENABLE, val, 1); + pr_debug("%swin #%d: Paste address 0x%llx\n", + window->txwin ? "Tx" : "Rx", winid, val); + return val; +} + +static void get_hvwc_mmio_bar(struct vas_window *window, + uint64_t *start, int *len) +{ + uint64_t pbaddr; + int instance; + + instance = window->vinst->node * 8 + window->vinst->chip; + pbaddr = VAS_HVWC_MMIO_BAR_BASE + instance * VAS_HVWC_MMIO_BAR_SIZE; + + *start = pbaddr + window->winid * VAS_HVWC_SIZE; + *len = VAS_HVWC_SIZE; +} + +static void get_uwc_mmio_bar(struct vas_window *window, + uint64_t *start, int *len) +{ + uint64_t pbaddr; + int instance; + + instance = window->vinst->node * 8 + window->vinst->chip; + pbaddr = VAS_UWC_MMIO_BAR_BASE + instance * VAS_UWC_MMIO_BAR_SIZE; + + *start = pbaddr + window->winid * VAS_UWC_SIZE; + *len = VAS_UWC_SIZE; +} + +static void *map_mmio_region(char *name, uint64_t start, int len) +{ + void *map; + + if (!request_mem_region(start, len, name)) { + pr_devel("%s(): request_mem_region(0x%llx, %d) failed\n", + __func__, start, len); + return NULL; + } + + map = __ioremap(start, len, pgprot_val(pgprot_cached(__pgprot(0)))); + if (!map) { + pr_devel("%s(): ioremap(0x%llx, %d) failed\n", __func__, start, + len); + return NULL; + } + + return map; +} + +/* + * Unmap the MMIO regions for a window. + */ +void unmap_wc_mmio_bars(struct vas_window *window) +{ + int len; + uint64_t busaddr_start; + + if (window->paste_kaddr) { + iounmap(window->paste_kaddr); + busaddr_start = compute_paste_address(window, &len); + pr_debug("Releasing pbaddr region [0x%llx, %d]\n", + busaddr_start, len); + release_mem_region((phys_addr_t)busaddr_start, len); + } + + if (window->hvwc_map) { + iounmap(window->hvwc_map); + get_hvwc_mmio_bar(window, &busaddr_start, &len); + release_mem_region((phys_addr_t)busaddr_start, len); + } + + if (window->uwc_map) { + iounmap(window->uwc_map); + get_uwc_mmio_bar(window, &busaddr_start, &len); + release_mem_region((phys_addr_t)busaddr_start, len); + } +} + +/* + * Find the Hypervisor Window Context (HVWC) MMIO Base Address Region and the + * OS/User Window Context (UWC) MMIO Base Address Region for the given window. + * Map these bus addresses and save the mapped kernel addresses in @window. + */ +int map_wc_mmio_bars(struct vas_window *window) +{ + int len; + uint64_t start; + + window->hvwc_map = window->uwc_map = NULL; + + get_hvwc_mmio_bar(window, &start, &len); + window->hvwc_map = map_mmio_region("HVWCM_Window", start, len); + + pr_debug("Win #%d: Map hvwc 0x%p -> [0x%llx,%d]\n", window->winid, + window->hvwc_map, start, len); + + get_uwc_mmio_bar(window, &start, &len); + window->uwc_map = map_mmio_region("UWCM_Window", start, len); + + pr_debug("Win #%d: Map uvwc 0x%p -> [0x%llx,%d]\n", window->winid, + window->uwc_map, start, len); + + if (!window->hvwc_map || !window->uwc_map) + return -1; + + return 0; +} + /* stub for now */ int vas_window_reset(struct vas_instance *vinst, int winid) { -- 1.8.3.1