Пример #1
0
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();
}
Пример #2
0
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;
}
Пример #3
0
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;
	}
Пример #4
0
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;
}
Пример #5
0
/* 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;
}