drivers/parisc/sba_iommu.c

Source file repositories/reference/linux-study-clean/drivers/parisc/sba_iommu.c

File Facts

System
Linux kernel
Corpus path
drivers/parisc/sba_iommu.c
Extension
.c
Size
58980 bytes
Lines
2092
Domain
Driver Families
Bucket
drivers/parisc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ibase_data_struct {
	struct ioc *ioc;
	int ioc_num;
};

static int setup_ibase_imask_callback(struct device *dev, void *data)
{
	struct parisc_device *lba = to_parisc_device(dev);
	struct ibase_data_struct *ibd = data;
	int rope_num = (lba->hpa.start >> 13) & 0xf;
	if (rope_num >> 3 == ibd->ioc_num)
		lba_set_iregs(lba, ibd->ioc->ibase, ibd->ioc->imask);
	return 0;
}

/* setup Mercury or Elroy IBASE/IMASK registers. */
static void 
setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
{
	struct ibase_data_struct ibase_data = {
		.ioc		= ioc,
		.ioc_num	= ioc_num,
	};

	device_for_each_child(&sba->dev, &ibase_data,
			      setup_ibase_imask_callback);
}

#ifdef SBA_AGP_SUPPORT
static int
sba_ioc_find_quicksilver(struct device *dev, void *data)
{
	int *agp_found = data;
	struct parisc_device *lba = to_parisc_device(dev);

	if (IS_QUICKSILVER(lba))
		*agp_found = 1;
	return 0;
}
#endif

static void
sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
{
	u32 iova_space_mask;
	u32 iova_space_size;
	int iov_order, tcnfg;
#ifdef SBA_AGP_SUPPORT
	int agp_found = 0;
#endif
	/*
	** Firmware programs the base and size of a "safe IOVA space"
	** (one that doesn't overlap memory or LMMIO space) in the
	** IBASE and IMASK registers.
	*/
	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1fffffULL;
	iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;

	if ((ioc->ibase < 0xfed00000UL) && ((ioc->ibase + iova_space_size) > 0xfee00000UL)) {
		printk("WARNING: IOV space overlaps local config and interrupt message, truncating\n");
		iova_space_size /= 2;
	}

	/*
	** iov_order is always based on a 1GB IOVA space since we want to
	** turn on the other half for AGP GART.
	*/
	iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);

	DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
		__func__, ioc->ioc_hpa, iova_space_size >> 20,
		iov_order + PAGE_SHIFT);

	ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL,
						   get_order(ioc->pdir_size));
	if (!ioc->pdir_base)
		panic("Couldn't allocate I/O Page Table\n");

	memset(ioc->pdir_base, 0, ioc->pdir_size);

	DBG_INIT("%s() pdir %p size %x\n",
			__func__, ioc->pdir_base, ioc->pdir_size);

#ifdef SBA_HINT_SUPPORT
	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));

	DBG_INIT("	hint_shift_pdir %x hint_mask_pdir %lx\n",
		ioc->hint_shift_pdir, ioc->hint_mask_pdir);

Annotation

Implementation Notes