/* no cpu hotplug on powernv, so this list never changes after init */ static LIST_HEAD(nx_coprocs); staticunsignedint nx842_ct; /* used in icswx function */
/* *Usingsamevaluesasinskibootorcoprocessortyperepresenting *inNXworkbook.
*/ #define NX_CT_GZIP (2) /* on P9 and later */ #define NX_CT_842 (3)
/* *setup_ddl-SetupDDLfrombuffer * *Returns: *0SuccessfullysetupDDL
*/ staticint setup_ddl(struct data_descriptor_entry *dde, struct data_descriptor_entry *ddl, unsignedchar *buf, unsignedint len, bool in)
{ unsignedlong pa = nx842_get_pa(buf); int i, ret, total_len = len;
if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) {
pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n",
in ? "input" : "output", pa, DDE_BUFFER_ALIGN); return -EINVAL;
}
/* only need to check last mult; since buffer must be *DDE_BUFFER_ALIGNaligned,andthatisamultipleof *DDE_BUFFER_SIZE_MULT,andpre-lastpageDDEbuffers *areguaranteedamultipleofDDE_BUFFER_SIZE_MULT.
*/ if (len % DDE_BUFFER_LAST_MULT) {
pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n",
in ? "input" : "output", len, DDE_BUFFER_LAST_MULT); if (in) return -EINVAL;
len = round_down(len, DDE_BUFFER_LAST_MULT);
}
/* use a single direct DDE */ if (len <= LEN_ON_PAGE(pa)) {
ret = setup_direct_dde(dde, pa, len);
WARN_ON(ret < len); return0;
}
/* use the DDL */ for (i = 0; i < DDL_LEN_MAX && len > 0; i++) {
ret = setup_direct_dde(&ddl[i], pa, len);
buf += ret;
len -= ret;
pa = nx842_get_pa(buf);
}
if (len > 0) {
pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n",
total_len, in ? "input" : "output", len); if (in) return -EMSGSIZE;
total_len -= len;
}
setup_indirect_dde(dde, ddl, i, total_len);
while (!(READ_ONCE(csb->flags) & CSB_V)) {
cpu_relax();
now = ktime_get(); if (ktime_after(now, timeout)) break;
}
/* hw has updated csb and output buffer */
barrier();
/* check CSB flags */ if (!(csb->flags & CSB_V)) {
CSB_ERR(csb, "CSB still not valid after %ld us, giving up",
(long)ktime_us_delta(now, start)); return -ETIMEDOUT;
} if (csb->flags & CSB_F) {
CSB_ERR(csb, "Invalid CSB format"); return -EPROTO;
} if (csb->flags & CSB_CH) {
CSB_ERR(csb, "Invalid CSB chaining state"); return -EPROTO;
}
/* verify CSB completion sequence is 0 */ if (csb->cs) {
CSB_ERR(csb, "Invalid CSB completion sequence"); return -EPROTO;
}
/* check CSB Completion Code */ switch (csb->cc) { /* no error */ case CSB_CC_SUCCESS: break; case CSB_CC_TPBC_GT_SPBC: /* not an error, but the compressed data is *largerthantheuncompresseddata:(
*/ break;
/* input data errors */ case CSB_CC_OPERAND_OVERLAP: /* input and output buffers overlap */
CSB_ERR(csb, "Operand Overlap error"); return -EINVAL; case CSB_CC_INVALID_OPERAND:
CSB_ERR(csb, "Invalid operand"); return -EINVAL; case CSB_CC_NOSPC: /* output buffer too small */ return -ENOSPC; case CSB_CC_ABORT:
CSB_ERR(csb, "Function aborted"); return -EINTR; case CSB_CC_CRC_MISMATCH:
CSB_ERR(csb, "CRC mismatch"); return -EINVAL; case CSB_CC_TEMPL_INVALID:
CSB_ERR(csb, "Compressed data template invalid"); return -EINVAL; case CSB_CC_TEMPL_OVERFLOW:
CSB_ERR(csb, "Compressed data template shows data past end"); return -EINVAL; case CSB_CC_EXCEED_BYTE_COUNT: /* P9 or later */ /* *DDEbytecountexceedsthelimitspecifiedinMaximum *bytecountregister.
*/
CSB_ERR(csb, "DDE byte count exceeds the limit"); return -EINVAL;
/* these should not happen */ case CSB_CC_INVALID_ALIGN: /* setup_ddl should have detected this */
CSB_ERR_ADDR(csb, "Invalid alignment"); return -EINVAL; case CSB_CC_DATA_LENGTH: /* setup_ddl should have detected this */
CSB_ERR(csb, "Invalid data length"); return -EINVAL; case CSB_CC_WR_TRANSLATION: case CSB_CC_TRANSLATION: case CSB_CC_TRANSLATION_DUP1: case CSB_CC_TRANSLATION_DUP2: case CSB_CC_TRANSLATION_DUP3: case CSB_CC_TRANSLATION_DUP4: case CSB_CC_TRANSLATION_DUP5: case CSB_CC_TRANSLATION_DUP6: /* should not happen, we use physical addrs */
CSB_ERR_ADDR(csb, "Translation error"); return -EPROTO; case CSB_CC_WR_PROTECTION: case CSB_CC_PROTECTION: case CSB_CC_PROTECTION_DUP1: case CSB_CC_PROTECTION_DUP2: case CSB_CC_PROTECTION_DUP3: case CSB_CC_PROTECTION_DUP4: case CSB_CC_PROTECTION_DUP5: case CSB_CC_PROTECTION_DUP6: /* should not happen, we use physical addrs */
CSB_ERR_ADDR(csb, "Protection error"); return -EPROTO; case CSB_CC_PRIVILEGE: /* shouldn't happen, we're in HYP mode */
CSB_ERR(csb, "Insufficient Privilege error"); return -EPROTO; case CSB_CC_EXCESSIVE_DDE: /* shouldn't happen, setup_ddl doesn't use many dde's */
CSB_ERR(csb, "Too many DDEs in DDL"); return -EINVAL; case CSB_CC_TRANSPORT: case CSB_CC_INVALID_CRB: /* P9 or later */ /* shouldn't happen, we setup CRB correctly */
CSB_ERR(csb, "Invalid CRB"); return -EINVAL; case CSB_CC_INVALID_DDE: /* P9 or later */ /* *shouldn'thappen,setup_direct/indirect_ddecreates *DDEright
*/
CSB_ERR(csb, "Invalid DDE"); return -EINVAL; case CSB_CC_SEGMENTED_DDL: /* shouldn't happen, setup_ddl creates DDL right */
CSB_ERR(csb, "Segmented DDL error"); return -EINVAL; case CSB_CC_DDE_OVERFLOW: /* shouldn't happen, setup_ddl creates DDL right */
CSB_ERR(csb, "DDE overflow error"); return -EINVAL; case CSB_CC_SESSION: /* should not happen with ICSWX */
CSB_ERR(csb, "Session violation error"); return -EPROTO; case CSB_CC_CHAIN: /* should not happen, we don't use chained CRBs */
CSB_ERR(csb, "Chained CRB error"); return -EPROTO; case CSB_CC_SEQUENCE: /* should not happen, we don't use chained CRBs */
CSB_ERR(csb, "CRB sequence number error"); return -EPROTO; case CSB_CC_UNKNOWN_CODE:
CSB_ERR(csb, "Unknown subfunction code"); return -EPROTO;
/* hardware errors */ case CSB_CC_RD_EXTERNAL: case CSB_CC_RD_EXTERNAL_DUP1: case CSB_CC_RD_EXTERNAL_DUP2: case CSB_CC_RD_EXTERNAL_DUP3:
CSB_ERR_ADDR(csb, "Read error outside coprocessor"); return -EPROTO; case CSB_CC_WR_EXTERNAL:
CSB_ERR_ADDR(csb, "Write error outside coprocessor"); return -EPROTO; case CSB_CC_INTERNAL:
CSB_ERR(csb, "Internal error in coprocessor"); return -EPROTO; case CSB_CC_PROVISION:
CSB_ERR(csb, "Storage provision error"); return -EPROTO; case CSB_CC_HW:
CSB_ERR(csb, "Correctable hardware error"); return -EPROTO; case CSB_CC_HW_EXPIRED_TIMER: /* P9 or later */
CSB_ERR(csb, "Job did not finish within allowed time"); return -EPROTO;
default:
CSB_ERR(csb, "Invalid CC %d", csb->cc); return -EPROTO;
}
/* check Completion Extension state */ if (csb->ce & CSB_CE_TERMINATION) {
CSB_ERR(csb, "CSB request was terminated"); return -EPROTO;
} if (csb->ce & CSB_CE_INCOMPLETE) {
CSB_ERR(csb, "CSB request not complete"); return -EPROTO;
} if (!(csb->ce & CSB_CE_TPBC)) {
CSB_ERR(csb, "TPBC not provided, unknown target length"); return -EPROTO;
}
/* *NX842coprocessorsets3rdbitinCRregisterwithXER[S0]. *XER[S0]istheintegersummaryoverflowbitwhichisnothing *todoNX.Sincethisbitcanbesetwithotherreturnvalues, *maskthisbit.
*/
ret &= ~ICSWX_XERS0;
switch (ret) { case ICSWX_INITIATED:
ret = wait_for_csb(wmem, csb); break; case ICSWX_BUSY:
pr_debug_ratelimited("842 Coprocessor busy\n");
ret = -EBUSY; break; case ICSWX_REJECTED:
pr_err_ratelimited("ICSWX rejected\n");
ret = -EPROTO; break;
}
/* *Kernelrequestswillbehighpriority.Soopensend *windowsonlyforhighpriorityRxFIFOentries.
*/
vas_init_tx_win_attr(&txattr, coproc->ct);
txattr.lpid = 0; /* lpid is 0 for kernel requests */
/* *OpenaVASsendwindowwhichisusedtosendrequesttoNX.
*/
txwin = vas_tx_win_open(coproc->vas.id, coproc->ct, &txattr); if (IS_ERR(txwin))
pr_err("ibm,nx-842: Can not open TX window: %ld\n",
PTR_ERR(txwin));
list_for_each_entry_safe(coproc, n, &nx_coprocs, list) { /* *KernelrequestsuseonlyhighpriorityFIFOs.So *opensendwindowsfortheseFIFOs. *GZIPisnotsupportedinkernelrightnow.
*/
if (coproc->ct != VAS_COP_TYPE_842_HIPRI) continue;
if (coproc->chip_id == chip_id) {
txwin = nx_alloc_txwin(coproc); if (IS_ERR(txwin)) return PTR_ERR(txwin);
per_cpu(cpu_txwin, i) = txwin; break;
}
}
if (!per_cpu(cpu_txwin, i)) { /* shouldn't happen, Each chip will have NX engine */
pr_err("NX engine is not available for CPU %d\n", i); return -EINVAL;
}
}
staticint __init nx_coproc_init(int chip_id, int ct_842, int ct_gzip)
{ int ret = 0;
if (opal_check_token(OPAL_NX_COPROC_INIT)) {
ret = opal_nx_coproc_init(chip_id, ct_842);
if (!ret)
ret = opal_nx_coproc_init(chip_id, ct_gzip);
if (ret) {
ret = opal_error_code(ret);
pr_err("Failed to initialize NX for chip(%d): %d\n",
chip_id, ret);
}
} else
pr_warn("Firmware doesn't support NX initialization\n");
return ret;
}
staticint __init find_nx_device_tree(struct device_node *dn, int chip_id, int vasid, int type, char *devname, int *ct)
{ int ret = 0;
if (of_device_is_compatible(dn, devname)) {
ret = vas_cfg_coproc_info(dn, chip_id, vasid, type, ct); if (ret)
of_node_put(dn);
}
return ret;
}
staticint __init nx_powernv_probe_vas(struct device_node *pn)
{ int chip_id, vasid, ret = 0; int ct_842 = 0, ct_gzip = 0; struct device_node *dn;
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.