⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iommu.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
 * * ToDo: properly interpret the ibm,dma-window property.  The definition is: *	logical-bus-number	(1 word) *	phys-address		(#address-cells words) *	size			(#cell-size words) * * Currently we hard code these sizes (more or less). */static void iommu_table_setparms_lpar(struct pci_controller *phb,				      struct device_node *dn,				      struct iommu_table *tbl,				      unsigned int *dma_window){	tbl->it_busno  = PCI_DN(dn)->bussubno;	/* TODO: Parse field size properties properly. */	tbl->it_size   = (((unsigned long)dma_window[4] << 32) |			   (unsigned long)dma_window[5]) >> PAGE_SHIFT;	tbl->it_offset = (((unsigned long)dma_window[2] << 32) |			   (unsigned long)dma_window[3]) >> PAGE_SHIFT;	tbl->it_base   = 0;	tbl->it_index  = dma_window[0];	tbl->it_blocksize  = 16;	tbl->it_type = TCE_PCI;}static void iommu_bus_setup_pSeries(struct pci_bus *bus){	struct device_node *dn;	struct iommu_table *tbl;	struct device_node *isa_dn, *isa_dn_orig;	struct device_node *tmp;	struct pci_dn *pci;	int children;	DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);	dn = pci_bus_to_OF_node(bus);	pci = PCI_DN(dn);	if (bus->self) {		/* This is not a root bus, any setup will be done for the		 * device-side of the bridge in iommu_dev_setup_pSeries().		 */		return;	}	/* Check if the ISA bus on the system is under	 * this PHB.	 */	isa_dn = isa_dn_orig = of_find_node_by_type(NULL, "isa");	while (isa_dn && isa_dn != dn)		isa_dn = isa_dn->parent;	if (isa_dn_orig)		of_node_put(isa_dn_orig);	/* Count number of direct PCI children of the PHB.	 * All PCI device nodes have class-code property, so it's	 * an easy way to find them.	 */	for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling)		if (get_property(tmp, "class-code", NULL))			children++;	DBG("Children: %d\n", children);	/* Calculate amount of DMA window per slot. Each window must be	 * a power of two (due to pci_alloc_consistent requirements).	 *	 * Keep 256MB aside for PHBs with ISA.	 */	if (!isa_dn) {		/* No ISA/IDE - just set window size and return */		pci->phb->dma_window_size = 0x80000000ul; /* To be divided */		while (pci->phb->dma_window_size * children > 0x80000000ul)			pci->phb->dma_window_size >>= 1;		DBG("No ISA/IDE, window size is 0x%lx\n",			pci->phb->dma_window_size);		pci->phb->dma_window_base_cur = 0;		return;	}	/* If we have ISA, then we probably have an IDE	 * controller too. Allocate a 128MB table but	 * skip the first 128MB to avoid stepping on ISA	 * space.	 */	pci->phb->dma_window_size = 0x8000000ul;	pci->phb->dma_window_base_cur = 0x8000000ul;	tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);	iommu_table_setparms(pci->phb, dn, tbl);	pci->iommu_table = iommu_init_table(tbl);	/* Divide the rest (1.75GB) among the children */	pci->phb->dma_window_size = 0x80000000ul;	while (pci->phb->dma_window_size * children > 0x70000000ul)		pci->phb->dma_window_size >>= 1;	DBG("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size);}static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus){	struct iommu_table *tbl;	struct device_node *dn, *pdn;	struct pci_dn *ppci;	unsigned int *dma_window = NULL;	DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);	dn = pci_bus_to_OF_node(bus);	/* Find nearest ibm,dma-window, walking up the device tree */	for (pdn = dn; pdn != NULL; pdn = pdn->parent) {		dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);		if (dma_window != NULL)			break;	}	if (dma_window == NULL) {		DBG("iommu_bus_setup_pSeriesLP: bus %s seems to have no ibm,dma-window property\n", dn->full_name);		return;	}	ppci = pdn->data;	if (!ppci->iommu_table) {		/* Bussubno hasn't been copied yet.		 * Do it now because iommu_table_setparms_lpar needs it.		 */		ppci->bussubno = bus->number;		tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),						    GFP_KERNEL);			iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);		ppci->iommu_table = iommu_init_table(tbl);	}	if (pdn != dn)		PCI_DN(dn)->iommu_table = ppci->iommu_table;}static void iommu_dev_setup_pSeries(struct pci_dev *dev){	struct device_node *dn, *mydn;	struct iommu_table *tbl;	DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, pci_name(dev));	mydn = dn = pci_device_to_OF_node(dev);	/* If we're the direct child of a root bus, then we need to allocate	 * an iommu table ourselves. The bus setup code should have setup	 * the window sizes already.	 */	if (!dev->bus->self) {		DBG(" --> first child, no bridge. Allocating iommu table.\n");		tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);		iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl);		PCI_DN(mydn)->iommu_table = iommu_init_table(tbl);		return;	}	/* If this device is further down the bus tree, search upwards until	 * an already allocated iommu table is found and use that.	 */	while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL)		dn = dn->parent;	if (dn && dn->data) {		PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;	} else {		DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev));	}}static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node){	int err = NOTIFY_OK;	struct device_node *np = node;	struct pci_dn *pci = np->data;	switch (action) {	case PSERIES_RECONFIG_REMOVE:		if (pci && pci->iommu_table &&		    get_property(np, "ibm,dma-window", NULL))			iommu_free_table(np);		break;	default:		err = NOTIFY_DONE;		break;	}	return err;}static struct notifier_block iommu_reconfig_nb = {	.notifier_call = iommu_reconfig_notifier,};static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev){	struct device_node *pdn, *dn;	struct iommu_table *tbl;	int *dma_window = NULL;	struct pci_dn *pci;	DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev));	/* dev setup for LPAR is a little tricky, since the device tree might	 * contain the dma-window properties per-device and not neccesarily	 * for the bus. So we need to search upwards in the tree until we	 * either hit a dma-window property, OR find a parent with a table	 * already allocated.	 */	dn = pci_device_to_OF_node(dev);	for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table;	     pdn = pdn->parent) {		dma_window = (unsigned int *)			get_property(pdn, "ibm,dma-window", NULL);		if (dma_window)			break;	}	/* Check for parent == NULL so we don't try to setup the empty EADS	 * slots on POWER4 machines.	 */	if (dma_window == NULL || pdn->parent == NULL) {		DBG("No dma window for device, linking to parent\n");		PCI_DN(dn)->iommu_table = PCI_DN(pdn)->iommu_table;		return;	} else {		DBG("Found DMA window, allocating table\n");	}	pci = pdn->data;	if (!pci->iommu_table) {		/* iommu_table_setparms_lpar needs bussubno. */		pci->bussubno = pci->phb->bus->number;		tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),						    GFP_KERNEL);		iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);		pci->iommu_table = iommu_init_table(tbl);	}	if (pdn != dn)		PCI_DN(dn)->iommu_table = pci->iommu_table;}static void iommu_bus_setup_null(struct pci_bus *b) { }static void iommu_dev_setup_null(struct pci_dev *d) { }/* These are called very early. */void iommu_init_early_pSeries(void){	if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) {		/* Direct I/O, IOMMU off */		ppc_md.iommu_dev_setup = iommu_dev_setup_null;		ppc_md.iommu_bus_setup = iommu_bus_setup_null;		pci_direct_iommu_init();		return;	}	if (platform_is_lpar()) {		if (firmware_has_feature(FW_FEATURE_MULTITCE)) {			ppc_md.tce_build = tce_buildmulti_pSeriesLP;			ppc_md.tce_free	 = tce_freemulti_pSeriesLP;		} else {			ppc_md.tce_build = tce_build_pSeriesLP;			ppc_md.tce_free	 = tce_free_pSeriesLP;		}		ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;		ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;	} else {		ppc_md.tce_build = tce_build_pSeries;		ppc_md.tce_free  = tce_free_pSeries;		ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;		ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;	}	pSeries_reconfig_notifier_register(&iommu_reconfig_nb);	pci_iommu_init();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -