static void msm_iommu_reset(void __iomem *base, int ncb) { int ctx; SET_RPUE(base, 0); SET_RPUEIE(base, 0); SET_ESRRESTORE(base, 0); SET_TBE(base, 0); SET_CR(base, 0); SET_SPDMBE(base, 0); SET_TESTBUSCR(base, 0); SET_TLBRSW(base, 0); SET_GLOBAL_TLBIALL(base, 0); SET_RPU_ACR(base, 0); SET_TLBLKCRWE(base, 1); for (ctx = 0; ctx < ncb; ctx++) { SET_BPRCOSH(base, ctx, 0); SET_BPRCISH(base, ctx, 0); SET_BPRCNSH(base, ctx, 0); SET_BPSHCFG(base, ctx, 0); SET_BPMTCFG(base, ctx, 0); SET_ACTLR(base, ctx, 0); SET_SCTLR(base, ctx, 0); SET_FSRRESTORE(base, ctx, 0); SET_TTBR0(base, ctx, 0); SET_TTBR1(base, ctx, 0); SET_TTBCR(base, ctx, 0); SET_BFBCR(base, ctx, 0); SET_PAR(base, ctx, 0); SET_FAR(base, ctx, 0); SET_TLBFLPTER(base, ctx, 0); SET_TLBSLPTER(base, ctx, 0); SET_TLBLKCR(base, ctx, 0); SET_CTX_TLBIALL(base, ctx, 0); SET_TLBIVA(base, ctx, 0); SET_PRRR(base, ctx, 0); SET_NMRR(base, ctx, 0); SET_CONTEXTIDR(base, ctx, 0); } mb(); }
static int msm_iommu_probe(struct platform_device *pdev) { struct resource *r, *r2; struct clk *iommu_clk = NULL; struct clk *iommu_pclk = NULL; struct msm_iommu_drvdata *drvdata; struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data; void __iomem *regs_base; resource_size_t len; int ret, par; if (pdev->id == -1) { msm_iommu_root_dev = pdev; return 0; } drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { ret = -ENOMEM; goto fail; } if (!iommu_dev) { ret = -ENODEV; goto fail; } iommu_pclk = clk_get_sys("msm_iommu", "iface_clk"); if (IS_ERR(iommu_pclk)) { ret = -ENODEV; goto fail; } ret = clk_prepare_enable(iommu_pclk); if (ret) goto fail_enable; iommu_clk = clk_get(&pdev->dev, "core_clk"); if (!IS_ERR(iommu_clk)) { if (clk_get_rate(iommu_clk) == 0) { ret = clk_round_rate(iommu_clk, 1); clk_set_rate(iommu_clk, ret); } ret = clk_prepare_enable(iommu_clk); if (ret) { clk_put(iommu_clk); goto fail_pclk; } } else iommu_clk = NULL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase"); if (!r) { ret = -ENODEV; goto fail_clk; } len = resource_size(r); r2 = request_mem_region(r->start, len, r->name); if (!r2) { pr_err("Could not request memory region: start=%p, len=%d\n", (void *) r->start, len); ret = -EBUSY; goto fail_clk; } regs_base = ioremap(r2->start, len); if (!regs_base) { pr_err("Could not ioremap: start=%p, len=%d\n", (void *) r2->start, len); ret = -EBUSY; goto fail_mem; } msm_iommu_reset(regs_base, iommu_dev->ncb); SET_M(regs_base, 0, 1); SET_PAR(regs_base, 0, 0); SET_V2PCFG(regs_base, 0, 1); SET_V2PPR(regs_base, 0, 0); mb(); par = GET_PAR(regs_base, 0); SET_V2PCFG(regs_base, 0, 0); SET_M(regs_base, 0, 0); mb(); if (!par) { pr_err("%s: Invalid PAR value detected\n", iommu_dev->name); ret = -ENODEV; goto fail_io; } drvdata->pclk = iommu_pclk; drvdata->clk = iommu_clk; drvdata->base = regs_base; drvdata->ncb = iommu_dev->ncb; drvdata->ttbr_split = iommu_dev->ttbr_split; drvdata->name = iommu_dev->name; pr_info("device %s mapped at %p, with %d ctx banks\n", iommu_dev->name, regs_base, iommu_dev->ncb); platform_set_drvdata(pdev, drvdata); if (iommu_clk) clk_disable_unprepare(iommu_clk); clk_disable_unprepare(iommu_pclk); return 0; fail_io: iounmap(regs_base); fail_mem: release_mem_region(r->start, len); fail_clk: if (iommu_clk) { clk_disable_unprepare(iommu_clk); clk_put(iommu_clk); } fail_pclk: clk_disable_unprepare(iommu_pclk); fail_enable: clk_put(iommu_pclk); fail: kfree(drvdata); return ret; }
static long get_hdr(SEXP sc, rsconn_t *c, struct phdr *hdr) { long tl = 0; while (1) { if (rsc_read(c, hdr, sizeof(*hdr)) != sizeof(*hdr)) { c->in_cmd = 0; RS_close(sc); Rf_error("read error - could not obtain response header"); } #if LONG_MAX > 2147483647 tl = hdr->res; tl <<= 32; tl |= hdr->len; #else tl = hdr->len; #endif if (hdr->cmd & CMD_OOB) { SEXP res, ee = R_NilValue; unsigned int *ibuf; PROTECT(res = allocVector(RAWSXP, tl)); if (rsc_read(c, RAW(res), tl) != tl) { c->in_cmd = 0; RS_close(sc); Rf_error("read error in OOB message"); } ibuf = (unsigned int*) RAW(res); /* FIXME: we assume that we get encoded SEXP - we should check ... */ ibuf += 1; res = QAP_decode(&ibuf); /* FIXME: Rserve has a bug(?) that sets CMD_RESP on OOB commands so we clear it for now ... */ hdr->cmd &= ~CMD_RESP; if (IS_OOB_SEND(hdr->cmd) && c->oob_send_cb != R_NilValue) PROTECT(ee = lang3(c->oob_send_cb, ScalarInteger(OOB_USR_CODE(hdr->cmd)), res)); if (IS_OOB_MSG(hdr->cmd) && c->oob_msg_cb != R_NilValue) PROTECT(ee = lang3(c->oob_msg_cb, ScalarInteger(OOB_USR_CODE(hdr->cmd)), res)); #ifdef RC_DEBUG Rprintf(" - OOB %x %s (%d) %d\n", hdr->cmd, IS_OOB_SEND(hdr->cmd) ? "send" : "other", OOB_USR_CODE(hdr->cmd), (int) tl); #endif if (ee != R_NilValue) { res = eval(ee, R_GlobalEnv); if (IS_OOB_MSG(hdr->cmd)) { struct phdr rhdr; long pl = QAP_getStorageSize(res); SEXP outv = allocVector(RAWSXP, pl); int isx = pl > 0x7fffff; unsigned int *oh = (unsigned int*) RAW(outv); unsigned int *ot = QAP_storeSEXP(oh + (isx ? 2 : 1), res, pl); pl = sizeof(int) * (long) (ot - oh); rhdr.cmd = hdr->cmd | CMD_RESP; rhdr.len = pl; rhdr.dof = 0; #ifdef __LP64__ rhdr.res = pl >> 32; #else rhdr.res = 0; #endif oh[0] = SET_PAR(DT_SEXP | (isx ? DT_LARGE : 0), pl - (isx ? 8 : 4)); if (isx) oh[1] = (pl - 8) >> 24; rsc_write(c, &rhdr, sizeof(rhdr)); if (pl) rsc_write(c, RAW(outv), pl); rsc_flush(c); } UNPROTECT(1); } UNPROTECT(1); continue; }
static int msm_iommu_probe(struct platform_device *pdev) { struct resource *r; struct clk *iommu_clk; struct clk *iommu_pclk; struct msm_iommu_drvdata *drvdata; struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data; void __iomem *regs_base; int ret, irq, par; if (pdev->id == -1) { msm_iommu_root_dev = pdev; return 0; } drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { ret = -ENOMEM; goto fail; } if (!iommu_dev) { ret = -ENODEV; goto fail; } iommu_pclk = clk_get(NULL, "smmu_pclk"); if (IS_ERR(iommu_pclk)) { ret = -ENODEV; goto fail; } ret = clk_prepare_enable(iommu_pclk); if (ret) goto fail_enable; iommu_clk = clk_get(&pdev->dev, "iommu_clk"); if (!IS_ERR(iommu_clk)) { if (clk_get_rate(iommu_clk) == 0) clk_set_rate(iommu_clk, 1); ret = clk_prepare_enable(iommu_clk); if (ret) { clk_put(iommu_clk); goto fail_pclk; } } else iommu_clk = NULL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase"); regs_base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(regs_base)) { ret = PTR_ERR(regs_base); goto fail_clk; } irq = platform_get_irq_byname(pdev, "secure_irq"); if (irq < 0) { ret = -ENODEV; goto fail_clk; } msm_iommu_reset(regs_base, iommu_dev->ncb); SET_M(regs_base, 0, 1); SET_PAR(regs_base, 0, 0); SET_V2PCFG(regs_base, 0, 1); SET_V2PPR(regs_base, 0, 0); par = GET_PAR(regs_base, 0); SET_V2PCFG(regs_base, 0, 0); SET_M(regs_base, 0, 0); if (!par) { pr_err("%s: Invalid PAR value detected\n", iommu_dev->name); ret = -ENODEV; goto fail_clk; } ret = request_irq(irq, msm_iommu_fault_handler, 0, "msm_iommu_secure_irpt_handler", drvdata); if (ret) { pr_err("Request IRQ %d failed with ret=%d\n", irq, ret); goto fail_clk; } drvdata->pclk = iommu_pclk; drvdata->clk = iommu_clk; drvdata->base = regs_base; drvdata->irq = irq; drvdata->ncb = iommu_dev->ncb; pr_info("device %s mapped at %p, irq %d with %d ctx banks\n", iommu_dev->name, regs_base, irq, iommu_dev->ncb); platform_set_drvdata(pdev, drvdata); if (iommu_clk) clk_disable(iommu_clk); clk_disable(iommu_pclk); return 0; fail_clk: if (iommu_clk) { clk_disable(iommu_clk); clk_put(iommu_clk); } fail_pclk: clk_disable_unprepare(iommu_pclk); fail_enable: clk_put(iommu_pclk); fail: kfree(drvdata); return ret; }
/* threaded version - can be run ona separate threads, does not use any R API and responds with ERR_unsupportedCmd to OOB commands */ static long get_hdr_mt(rsconn_t *c, struct phdr *hdr) { long tl = 0; while (1) { if (rsc_read(c, hdr, sizeof(*hdr)) != sizeof(*hdr)) { c->in_cmd = 0; closesocket(c->s); c->s = -1; IOerr(c, "read error - could not obtain response header"); } #if LONG_MAX > 2147483647 tl = hdr->res; tl <<= 32; tl |= hdr->len; #else tl = hdr->len; #endif /* OOB is not supported in MT mode */ if (hdr->cmd & CMD_OOB) { struct phdr rhdr; int err = 0; memset(&rhdr, 0, sizeof(rhdr)); /* FIXME: Rserve has a bug(?) that sets CMD_RESP on OOB commands so we clear it for now ... */ hdr->cmd &= ~CMD_RESP; if (IS_OOB_STREAM_READ(hdr->cmd)) { /* the only request we allow is stream read */ if (!c->stream || OOB_USR_CODE(hdr->cmd)) { /* we support only one stream - if present */ rsc_slurp(c, tl); err = ERR_notOpen; } else if (tl > 16) { rsc_slurp(c, tl); err = ERR_inv_par; } else { /* the request size is limited by the send buffer */ unsigned int req_off = 16 /* msg hdr */ + 4 /* par hdr */; unsigned int req_size = c->send_alloc - req_off; if (tl) { unsigned int b[4]; int n = c->recv(c, b, tl); if (n < tl) { c->in_cmd = 0; rsc_abort(c, "Read error in parsing OOB_STREAM_READ parameters"); return -1; } /* FIXME: we need to fix endianness on bigendian machines - but this is true elewhere! */ if (PAR_TYPE(b[0]) != DT_INT || PAR_LEN(b[0]) != sizeof(b[1]) || b[1] == 0) err = ERR_inv_par; else { /* we limit the request size */ if (b[1] < req_size) req_size = b[1]; /* flush the send buffer so it's guaranteed empty */ rsc_flush(c); n = fread(c->send_buf + req_off, 1, req_size, c->stream); if (n < 0) { err = ERR_IOerror; fclose(c->stream); c->stream = 0; } else { unsigned int *sb = (unsigned int*) (c->send_buf); sb[0] = OOB_STREAM_READ | RESP_OK; sb[2] = sb[3] = 0; if (n) { sb[1] = n + 4; sb[4] = SET_PAR(DT_BYTESTREAM, n); c->send_len = req_off + n; } else { sb[1] = 0; c->send_len = 16; /* jsut the header */ } /* we have populated the send buffer by hand, jsut flush it */ rsc_flush(c); } } } } } else { rsc_slurp(c, tl); err = ERR_unsupportedCmd; } if (err) { rhdr.cmd = err | CMD_RESP; rsc_write(c, &rhdr, sizeof(rhdr)); rsc_flush(c); } } else break; } c->in_cmd = 0; return tl; }