From b8ac8cde994023806c976878b8c86c02f74f03e4 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 21 Aug 2017 17:16:07 +1000 Subject: vas: Move core/vas.c -> hw/vas.c It's hardware after all... Signed-off-by: Michael Neuling Signed-off-by: Stewart Smith --- core/Makefile.inc | 1 - core/vas.c | 448 ------------------------------------------------------ 2 files changed, 449 deletions(-) delete mode 100644 core/vas.c (limited to 'core') diff --git a/core/Makefile.inc b/core/Makefile.inc index c343386..f2de2f6 100644 --- a/core/Makefile.inc +++ b/core/Makefile.inc @@ -9,7 +9,6 @@ CORE_OBJS += vpd.o hostservices.o platform.o nvram.o nvram-format.o hmi.o CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o psr.o -CORE_OBJS += vas.o ifeq ($(SKIBOOT_GCOV),1) CORE_OBJS += gcov-profiling.o diff --git a/core/vas.c b/core/vas.c deleted file mode 100644 index 0ac20e7..0000000 --- a/core/vas.c +++ /dev/null @@ -1,448 +0,0 @@ -/* Copyright 2013-2016 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include - -#define vas_err(__fmt,...) prlog(PR_ERR,"VAS: " __fmt, ##__VA_ARGS__) - -#ifdef VAS_VERBOSE_DEBUG -#define vas_vdbg(__x,__fmt,...) prlog(PR_DEBUG,"VAS: " __fmt, ##__VA_ARGS__) -#else -#define vas_vdbg(__x,__fmt,...) do { } while (0) -#endif - -static int vas_initialized; - -struct vas { - uint32_t chip_id; - uint32_t vas_id; - uint64_t xscom_base; - uint64_t wcbs; - uint32_t vas_irq; -}; - -static inline void get_hvwc_mmio_bar(int chipid, uint64_t *start, uint64_t *len) -{ - phys_map_get(chipid, VAS_HYP_WIN, 0, start, len); -} - -static inline void get_uwc_mmio_bar(int chipid, uint64_t *start, uint64_t *len) -{ - phys_map_get(chipid, VAS_USER_WIN, 0, start, len); -} - -static inline uint64_t compute_vas_scom_addr(struct vas *vas, uint64_t reg) -{ - return vas->xscom_base + reg; -} - -static int vas_scom_write(struct proc_chip *chip, uint64_t reg, uint64_t val) -{ - int rc; - uint64_t addr; - - addr = compute_vas_scom_addr(chip->vas, reg); - - rc = xscom_write(chip->id, addr, val); - if (rc != OPAL_SUCCESS) { - vas_err("Error writing 0x%llx to 0x%llx, rc %d\n", val, addr, - rc); - } - - return rc; -} - -/* Interface for NX - make sure VAS is fully initialized first */ -__attrconst inline uint64_t vas_get_hvwc_mmio_bar(const int chipid) -{ - uint64_t addr; - - if (!vas_initialized) - return 0ULL; - - get_hvwc_mmio_bar(chipid, &addr, NULL); - - return addr; -} - -/* Interface for NX - make sure VAS is fully initialized first */ -__attrconst uint64_t vas_get_wcbs_bar(int chipid) -{ - struct proc_chip *chip; - - if (!vas_initialized) - return 0ULL; - - chip = get_chip(chipid); - if (!chip) - return 0ULL; - - return chip->vas->wcbs; -} - -static int init_north_ctl(struct proc_chip *chip) -{ - uint64_t val = 0ULL; - - val = SETFIELD(VAS_64K_MODE_MASK, val, true); - val = SETFIELD(VAS_ACCEPT_PASTE_MASK, val, true); - val = SETFIELD(VAS_ENABLE_WC_MMIO_BAR, val, true); - val = SETFIELD(VAS_ENABLE_UWC_MMIO_BAR, val, true); - val = SETFIELD(VAS_ENABLE_RMA_MMIO_BAR, val, true); - - return vas_scom_write(chip, VAS_MISC_N_CTL, val); -} - -static inline int reset_north_ctl(struct proc_chip *chip) -{ - return vas_scom_write(chip, VAS_MISC_N_CTL, 0ULL); -} - -static void reset_fir(struct proc_chip *chip) -{ - vas_scom_write(chip, VAS_FIR0, 0x0000000000000000ULL); - /* From VAS workbook */ - vas_scom_write(chip, VAS_FIR_MASK, 0x000001000001ffffULL); - vas_scom_write(chip, VAS_FIR_ACTION0, 0xf800fdfc0001ffffull); - vas_scom_write(chip, VAS_FIR_ACTION1, 0xf8fffefffffc8000ull); -} - -#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_WINID_START_BIT 32 -#define RMA_LSMP_WINID_NUM_BITS 16 - -/* - * Initialize RMA BAR on this chip to correspond to its node/chip id. - * This will cause VAS to accept paste commands to targeted for this chip. - * Initialize RMA Base Address Mask Register (BAMR) to its default value. - */ -static int init_rma(struct proc_chip *chip) -{ - int rc; - uint64_t val; - - val = 0ULL; - val = SETFIELD(RMA_LSMP_64K_SYS_ID, val, 1); - val = SETFIELD(RMA_LSMP_64K_NODE_ID, val, P9_GCID2NODEID(chip->id)); - val = SETFIELD(RMA_LSMP_64K_CHIP_ID, val, P9_GCID2CHIPID(chip->id)); - - rc = vas_scom_write(chip, VAS_RMA_BAR, val); - if (rc) - return rc; - - val = SETFIELD(VAS_RMA_BAMR_ADDR_MASK, 0ULL, 0xFFFC0000000ULL); - - return vas_scom_write(chip, VAS_RMA_BAMR, val); -} - -/* - * get_paste_bar(): - * - * Compute and return the "paste base address region" for @chipid. This - * BAR contains the "paste" addreses for all windows on the chip. Linux - * uses this paste BAR to compute the hardware paste address of a (send) - * window using: - * - * paste_addr = base + (winid << shift) - * - * where winid is the window index and shift is computed as: - * - * start = RMA_LSMP_WINID_START_BIT; - * nbits = RMA_LSMP_WINID_NUM_BITS; - * shift = 63 - (start + nbits - 1); - * - * See also get_paste_bitfield() below, which is used to export the 'start' - * and 'nbits' to Linux through the DT. - * - * Each chip supports VAS_WINDOWS_PER_CHIP (64K on Power9) windows. To - * provide proper isolation, the paste address for each window is on a - * separate page. Thus with a page size of 64K, the length of the paste - * BAR for a chip is VAS_WINDOWS_PER_CHIP times 64K (or 4GB for Power9). - * - * The start/base of the paste BAR is computed using the tables 1.1 through - * 1.4 in Section 1.3.3.1 (Send Message w/Paste Commands (cl_rma_w)) of VAS - * P9 Workbook. - * - * 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 v v - * Node Chip Window id 4 - * - * Thus the paste address for window id 4 is 0x00080000_00040400 and - * the _base_ paste address for Node 0 Chip 0 is 0x00080000_00000000. - */ -#define VAS_PASTE_BAR_LEN (1ULL << 32) /* 4GB - see above */ - -static inline void get_paste_bar(int chipid, uint64_t *start, uint64_t *len) -{ - uint64_t val; - - val = 0ULL; - val = SETFIELD(RMA_LSMP_64K_SYS_ID, val, 1); - val = SETFIELD(RMA_LSMP_64K_NODE_ID, val, P9_GCID2NODEID(chipid)); - val = SETFIELD(RMA_LSMP_64K_CHIP_ID, val, P9_GCID2CHIPID(chipid)); - - *start = val; - *len = VAS_PASTE_BAR_LEN; -} - -/* - * get_paste_bitfield(): - * - * As explained in the function header for get_paste_bar(), the window - * id is encoded in bits 32:47 of the paste address. Export this bitfield - * to Linux via the device tree as a reg property (with start bit and - * number of bits). - */ -static inline void get_paste_bitfield(uint64_t *start, uint64_t *n_bits) -{ - *start = (uint64_t)RMA_LSMP_WINID_START_BIT; - *n_bits = (uint64_t)RMA_LSMP_WINID_NUM_BITS; -} - -/* - * Window Context MMIO (WCM) Region for each chip is assigned in the P9 - * MMIO MAP spreadsheet. Write this value to the SCOM address associated - * with WCM_BAR. - */ -static int init_wcm(struct proc_chip *chip) -{ - uint64_t wcmbar; - - get_hvwc_mmio_bar(chip->id, &wcmbar, NULL); - - /* - * Write the entire WCMBAR address to the SCOM address. VAS will - * extract bits that it thinks are relevant i.e bits 8..38 - */ - return vas_scom_write(chip, VAS_WCM_BAR, wcmbar); -} - -/* - * OS/User Window Context MMIO (UWCM) Region for each is assigned in the - * P9 MMIO MAP spreadsheet. Write this value to the SCOM address associated - * with UWCM_BAR. - */ -static int init_uwcm(struct proc_chip *chip) -{ - uint64_t uwcmbar; - - get_uwc_mmio_bar(chip->id, &uwcmbar, NULL); - - /* - * Write the entire UWCMBAR address to the SCOM address. VAS will - * extract bits that it thinks are relevant i.e bits 8..35. - */ - return vas_scom_write(chip, VAS_UWCM_BAR, uwcmbar); -} - -static inline void free_wcbs(struct proc_chip *chip) -{ - if (chip->vas->wcbs) { - free((void *)chip->vas->wcbs); - chip->vas->wcbs = 0ULL; - } -} - -/* - * VAS needs a backing store for the 64K window contexts on a chip. - * (64K times 512 = 8MB). This region needs to be contiguous, so - * allocate during early boot. Then write the allocated address to - * the SCOM address for the Backing store BAR. - */ -static int alloc_init_wcbs(struct proc_chip *chip) -{ - int rc; - uint64_t wcbs; - size_t size; - - /* align to the backing store size */ - size = (size_t)VAS_WCBS_SIZE; - wcbs = (uint64_t)local_alloc(chip->id, size, size); - if (!wcbs) { - vas_err("Unable to allocate memory for backing store\n"); - return -ENOMEM; - } - memset((void *)wcbs, 0ULL, size); - - /* - * Write entire WCBS_BAR address to the SCOM address. VAS will extract - * relevant bits. - */ - rc = vas_scom_write(chip, VAS_WCBS_BAR, wcbs); - if (rc != OPAL_SUCCESS) - goto out; - - chip->vas->wcbs = wcbs; - return OPAL_SUCCESS; - -out: - free((void *)wcbs); - return rc; -} - -static struct vas *alloc_vas(uint32_t chip_id, uint32_t vas_id, uint64_t base) -{ - struct vas *vas; - - vas = zalloc(sizeof(struct vas)); - assert(vas); - - vas->chip_id = chip_id; - vas->vas_id = vas_id; - vas->xscom_base = base; - - return vas; -} - -static void create_mm_dt_node(struct proc_chip *chip) -{ - struct dt_node *dn; - struct vas *vas; - uint64_t hvwc_start, hvwc_len; - uint64_t uwc_start, uwc_len; - uint64_t pbar_start, pbar_len; - uint64_t pbf_start, pbf_nbits; - - vas = chip->vas; - get_hvwc_mmio_bar(chip->id, &hvwc_start, &hvwc_len); - get_uwc_mmio_bar(chip->id, &uwc_start, &uwc_len); - get_paste_bar(chip->id, &pbar_start, &pbar_len); - get_paste_bitfield(&pbf_start, &pbf_nbits); - - dn = dt_new_addr(dt_root, "vas", hvwc_start); - - dt_add_property_strings(dn, "compatible", "ibm,power9-vas", - "ibm,vas"); - - dt_add_property_u64s(dn, "reg", hvwc_start, hvwc_len, - uwc_start, uwc_len, - pbar_start, pbar_len, - pbf_start, pbf_nbits); - - dt_add_property(dn, "ibm,vas-id", &vas->vas_id, sizeof(vas->vas_id)); -} - -/* - * Disable one VAS instance. - * - * Free memory and ensure chip does not accept paste instructions. - */ -static void disable_vas_inst(struct dt_node *np) -{ - struct proc_chip *chip; - - chip = get_chip(dt_get_chip_id(np)); - - if (!chip->vas) - return; - - free_wcbs(chip); - - reset_north_ctl(chip); -} - -/* - * Initialize one VAS instance - */ -static int init_vas_inst(struct dt_node *np) -{ - uint32_t vas_id; - uint64_t xscom_base; - struct proc_chip *chip; - - chip = get_chip(dt_get_chip_id(np)); - vas_id = dt_prop_get_u32(np, "ibm,vas-id"); - xscom_base = dt_get_address(np, 0, NULL); - - chip->vas = alloc_vas(chip->id, vas_id, xscom_base); - - if (alloc_init_wcbs(chip)) - return -1; - - reset_fir(chip); - - if (init_wcm(chip) || init_uwcm(chip) || init_north_ctl(chip) || - init_rma(chip)) - return -1; - - create_mm_dt_node(chip); - - prlog(PR_NOTICE, "VAS: Initialized chip %d\n", chip->id); - return 0; - -} - -void vas_init() -{ - struct dt_node *np; - - if (proc_gen != proc_gen_p9) - return; - - dt_for_each_compatible(dt_root, np, "ibm,power9-vas-x") { - if (init_vas_inst(np)) - goto out; - } - - vas_initialized = 1; - return; - -out: - dt_for_each_compatible(dt_root, np, "ibm,power9-vas-x") - disable_vas_inst(np); - - vas_err("Disabled (failed initialization)\n"); - return; -} -- cgit v1.1