/* Copyright 2015 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 #include #include static int nx_cfg_umac_tx_wc(u32 gcid, u64 xcfg) { int rc = 0; u64 cfg; cfg = vas_get_wcbs_bar(gcid); if (!cfg) { prerror("NX%d: ERROR finding WC Backing store BAR\n", gcid); return -ENOMEM; } /* * NOTE: Write the entire bar address to SCOM. VAS/NX will extract * the relevant (NX_P9_UMAC_TX_WINDOW_CONTEXT_ADDR) bits. * IOW, _don't_ just write the bit field like: * * cfg = SETFIELD(NX_P9_UMAC_TX_WINDOW_CONTEXT_ADDR, 0ULL, cfg); */ rc = xscom_write(gcid, xcfg, cfg); if (rc) prerror("NX%d: ERROR: UMAC SEND WC BAR, %d\n", gcid, rc); else prlog(PR_DEBUG, "NX%d: UMAC SEND WC BAR, 0x%016lx, " "xcfg 0x%llx\n", gcid, (unsigned long)cfg, xcfg); return rc; } static int nx_cfg_dma_vas_mmio(u32 gcid, u64 xcfg) { int rc = 0; u64 cfg; cfg = vas_get_hvwc_mmio_bar(gcid); /* * NOTE: Write the entire bar address to SCOM. VAS/NX will extract * the relevant (NX_P9_UMAC_VAS_MMIO_ADDR) bits. IOW, _don't_ * just write the bit field like: * * cfg = SETFIELD(NX_P9_DMA_VAS_MMIO_ADDR, 0ULL, cfg); */ rc = xscom_write(gcid, xcfg, cfg); if (rc) prerror("NX%d: ERROR: DMA VAS MMIO BAR, %d\n", gcid, rc); else prlog(PR_DEBUG, "NX%d: DMA VAS MMIO BAR, 0x%016lx, xcfg 0x%llx\n", gcid, (unsigned long)cfg, xcfg); return rc; } static int nx_cfg_umac_vas_mmio(u32 gcid, u64 xcfg) { int rc = 0; u64 cfg; cfg = vas_get_hvwc_mmio_bar(gcid); /* * NOTE: Write the entire bar address to SCOM. VAS/NX will extract * the relevant (NX_P9_UMAC_VAS_MMIO_ADDR) bits. IOW, _don't_ * just write the bit field like: * * cfg = SETFIELD(NX_P9_UMAC_VAS_MMIO_ADDR, 0ULL, cfg); */ rc = xscom_write(gcid, xcfg, cfg); if (rc) prerror("NX%d: ERROR: UMAC VAS MMIO BAR, %d\n", gcid, rc); else prlog(PR_DEBUG, "NX%d: UMAC VAS MMIO BAR, 0x%016lx, " "xcfg 0x%llx\n", gcid, (unsigned long)cfg, xcfg); return rc; } static int nx_cfg_umac_status_ctrl(u32 gcid, u64 xcfg) { u64 uctrl; int rc; #define CRB_ENABLE 1 rc = xscom_read(gcid, xcfg, &uctrl); if (rc) return rc; uctrl = SETFIELD(NX_P9_UMAC_STATUS_CTRL_CRB_ENABLE, uctrl, CRB_ENABLE); rc = xscom_write(gcid, xcfg, uctrl); if (rc) prerror("NX%d: ERROR: Setting UMAC Status Control failure %d\n", gcid, rc); else prlog(PR_DEBUG, "NX%d: Setting UMAC Status Control 0x%016lx\n", gcid, (unsigned long)uctrl); return rc; } int nx_cfg_rx_fifo(struct dt_node *node, const char *compat, const char *priority, u32 gcid, u32 pid, u32 tid, u64 umac_bar, u64 umac_notify) { u64 cfg; int rc, size; uint64_t fifo; u32 lpid = 0xfff; /* All 1's for 12 bits in UMAC notify match reg */ #define MATCH_ENABLE 1 fifo = (uint64_t) local_alloc(gcid, RX_FIFO_SIZE, RX_FIFO_SIZE); assert(fifo); /* * When configuring the address of the Rx FIFO into the Receive FIFO * BAR, we should _NOT_ shift the address into bits 8:53. Instead we * should copy the address as is and VAS/NX will extract relevant bits. */ /* * Section 5.21 of P9 NX Workbook Version 2.42 shows Receive FIFO BAR * 54:56 represents FIFO size * 000 = 1KB, 8 CRBs * 001 = 2KB, 16 CRBs * 010 = 4KB, 32 CRBs * 011 = 8KB, 64 CRBs * 100 = 16KB, 128 CRBs * 101 = 32KB, 256 CRBs * 110 = 111 reserved */ size = RX_FIFO_SIZE / 1024; cfg = SETFIELD(NX_P9_RX_FIFO_BAR_SIZE, fifo, ilog2(size)); rc = xscom_write(gcid, umac_bar, cfg); if (rc) { prerror("NX%d: ERROR: Setting UMAC FIFO bar failure %d\n", gcid, rc); return rc; } else prlog(PR_DEBUG, "NX%d: Setting UMAC FIFO bar 0x%016lx\n", gcid, (unsigned long)cfg); rc = xscom_read(gcid, umac_notify, &cfg); if (rc) return rc; /* * VAS issues asb_notify with the unique ID to identify the target * co-processor/engine. Logical partition ID (lpid), process ID (pid), * and thread ID (tid) combination is used to define the unique ID * in the system. Export these values in device-tree such that the * driver configure RxFIFO with VAS. Set these values in RxFIFO notify * match register for each engine which compares the ID with each * request. * To define unique indentification, 0xfff (1's for 12 bits), * co-processor type, and counter within coprocessor type are used * for lpid, pid, and tid respectively. */ cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_LPID, cfg, lpid); cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_PID, cfg, pid); cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_TID, cfg, tid); cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_MATCH_ENABLE, cfg, MATCH_ENABLE); rc = xscom_write(gcid, umac_notify, cfg); if (rc) { prerror("NX%d: ERROR: Setting UMAC notify match failure %d\n", gcid, rc); return rc; } else prlog(PR_DEBUG, "NX%d: Setting UMAC notify match 0x%016lx\n", gcid, (unsigned long)cfg); dt_add_property_string(node, "compatible", compat); dt_add_property_string(node, "priority", priority); dt_add_property_u64(node, "rx-fifo-address", fifo); dt_add_property_cells(node, "rx-fifo-size", RX_FIFO_SIZE); dt_add_property_cells(node, "lpid", lpid); dt_add_property_cells(node, "pid", pid); dt_add_property_cells(node, "tid", tid); return 0; } static int nx_init_fifo_ctrl(u32 gcid, u64 fifo_ctrl) { u64 cfg; int rc = 0; rc = xscom_read(gcid, fifo_ctrl, &cfg); if (rc) return rc; cfg = SETFIELD(NX_P9_RX_FIFO_CTRL_READ_OFFSET, cfg, 0); cfg = SETFIELD(NX_P9_RX_FIFO_CTRL_QUEUED, cfg, 0); rc = xscom_write(gcid, fifo_ctrl, cfg); return rc; } static int opal_nx_coproc_init(u32 gcid, u32 ct) { struct proc_chip *chip; u64 fifo, fifo_hi; u32 nx_base; int rc; if (proc_gen < proc_gen_p9) return OPAL_UNSUPPORTED; chip = get_chip(gcid); if (!chip) return OPAL_PARAMETER; nx_base = chip->nx_base; if (!nx_base) return OPAL_PARAMETER; switch (ct) { case NX_CT_842: fifo_hi = nx_base + NX_P9_842_HIGH_PRI_RX_FIFO_CTRL; fifo = nx_base + NX_P9_842_NORMAL_PRI_RX_FIFO_CTRL; break; case NX_CT_GZIP: fifo_hi = nx_base + NX_P9_GZIP_HIGH_PRI_RX_FIFO_CTRL; fifo = nx_base + NX_P9_GZIP_NORMAL_PRI_RX_FIFO_CTRL; break; default: prlog(PR_EMERG, "OPAL: Unknown NX coprocessor type\n"); return OPAL_PARAMETER; } rc = nx_init_fifo_ctrl(gcid, fifo_hi); if (!rc) rc = nx_init_fifo_ctrl(gcid, fifo); return rc; } opal_call(OPAL_NX_COPROC_INIT, opal_nx_coproc_init, 2); void nx_create_compress_node(struct dt_node *node) { u32 gcid, pb_base; struct proc_chip *chip; int rc; gcid = dt_get_chip_id(node); pb_base = dt_get_address(node, 0, NULL); chip = get_chip(gcid); chip->nx_base = pb_base; prlog(PR_INFO, "NX%d: 842 at 0x%x\n", gcid, pb_base); if (dt_node_is_compatible(node, "ibm,power9-nx")) { u64 cfg_mmio, cfg_txwc, cfg_uctrl, cfg_dma; prlog(PR_DEBUG, "Found ibm,power9-nx\n"); cfg_mmio = pb_base + NX_P9_UMAC_VAS_MMIO_BAR; cfg_dma = pb_base + NX_P9_DMA_VAS_MMIO_BAR; cfg_txwc = pb_base + NX_P9_UMAC_TX_WINDOW_CONTEXT_BAR; cfg_uctrl = pb_base + NX_P9_UMAC_STATUS_CTRL; rc = nx_cfg_umac_vas_mmio(gcid, cfg_mmio); if (rc) return; rc = nx_cfg_dma_vas_mmio(gcid, cfg_dma); if (rc) return; rc = nx_cfg_umac_tx_wc(gcid, cfg_txwc); if (rc) return; rc = nx_cfg_umac_status_ctrl(gcid, cfg_uctrl); if (rc) return; p9_nx_enable_842(node, gcid, pb_base); p9_nx_enable_gzip(node, gcid, pb_base); } else nx_enable_842(node, gcid, pb_base); }