static void __init sbus_iommu_init()

in kernel/sbus.c [540:662]


static void __init sbus_iommu_init(struct platform_device *op)
{
	const struct linux_prom64_registers *pr;
	struct device_node *dp = op->dev.of_node;
	struct iommu *iommu;
	struct strbuf *strbuf;
	unsigned long regs, reg_base;
	int i, portid;
	u64 control;

	pr = of_get_property(dp, "reg", NULL);
	if (!pr) {
		prom_printf("sbus_iommu_init: Cannot map SYSIO "
			    "control registers.\n");
		prom_halt();
	}
	regs = pr->phys_addr;

	iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
	strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC);
	if (!iommu || !strbuf)
		goto fatal_memory_error;

	op->dev.archdata.iommu = iommu;
	op->dev.archdata.stc = strbuf;
	op->dev.archdata.numa_node = NUMA_NO_NODE;

	reg_base = regs + SYSIO_IOMMUREG_BASE;
	iommu->iommu_control = reg_base + IOMMU_CONTROL;
	iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE;
	iommu->iommu_flush = reg_base + IOMMU_FLUSH;
	iommu->iommu_tags = iommu->iommu_control +
		(IOMMU_TAGDIAG - IOMMU_CONTROL);

	reg_base = regs + SYSIO_STRBUFREG_BASE;
	strbuf->strbuf_control = reg_base + STRBUF_CONTROL;
	strbuf->strbuf_pflush = reg_base + STRBUF_PFLUSH;
	strbuf->strbuf_fsync = reg_base + STRBUF_FSYNC;

	strbuf->strbuf_enabled = 1;

	strbuf->strbuf_flushflag = (volatile unsigned long *)
		((((unsigned long)&strbuf->__flushflag_buf[0])
		  + 63UL)
		 & ~63UL);
	strbuf->strbuf_flushflag_pa = (unsigned long)
		__pa(strbuf->strbuf_flushflag);

	/* The SYSIO SBUS control register is used for dummy reads
	 * in order to ensure write completion.
	 */
	iommu->write_complete_reg = regs + 0x2000UL;

	portid = of_getintprop_default(op->dev.of_node, "portid", -1);
	printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
	       portid, regs);

	/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
	if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1))
		goto fatal_memory_error;

	control = upa_readq(iommu->iommu_control);
	control = ((7UL << 16UL)	|
		   (0UL << 2UL)		|
		   (1UL << 1UL)		|
		   (1UL << 0UL));
	upa_writeq(control, iommu->iommu_control);

	/* Clean out any cruft in the IOMMU using
	 * diagnostic accesses.
	 */
	for (i = 0; i < 16; i++) {
		unsigned long dram, tag;

		dram = iommu->iommu_control + (IOMMU_DRAMDIAG - IOMMU_CONTROL);
		tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);

		dram += (unsigned long)i * 8UL;
		tag += (unsigned long)i * 8UL;
		upa_writeq(0, dram);
		upa_writeq(0, tag);
	}
	upa_readq(iommu->write_complete_reg);

	/* Give the TSB to SYSIO. */
	upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);

	/* Setup streaming buffer, DE=1 SB_EN=1 */
	control = (1UL << 1UL) | (1UL << 0UL);
	upa_writeq(control, strbuf->strbuf_control);

	/* Clear out the tags using diagnostics. */
	for (i = 0; i < 16; i++) {
		unsigned long ptag, ltag;

		ptag = strbuf->strbuf_control +
			(STRBUF_PTAGDIAG - STRBUF_CONTROL);
		ltag = strbuf->strbuf_control +
			(STRBUF_LTAGDIAG - STRBUF_CONTROL);
		ptag += (unsigned long)i * 8UL;
		ltag += (unsigned long)i * 8UL;

		upa_writeq(0UL, ptag);
		upa_writeq(0UL, ltag);
	}

	/* Enable DVMA arbitration for all devices/slots. */
	control = upa_readq(iommu->write_complete_reg);
	control |= 0x3fUL;
	upa_writeq(control, iommu->write_complete_reg);

	/* Now some Xfire specific grot... */
	if (this_is_starfire)
		starfire_hookup(portid);

	sysio_register_error_handlers(op);
	return;

fatal_memory_error:
	kfree(iommu);
	kfree(strbuf);
	prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
}