blob: ccd4799c472794e297e7e6fd29f69eea8c6d35fb [file] [log] [blame]
/* 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 <skiboot.h>
#include <chip.h>
#include <xscom.h>
#include <io.h>
#include <cpu.h>
#include <nx.h>
#include <vas.h>
#include <opal.h>
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;
printf("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);
}