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

📄 isa-bridge.c

📁 linux 内核源代码
💻 C
字号:
/* * Routines for tracking a legacy ISA bridge * * Copyrigh 2007 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. * * Some bits and pieces moved over from pci_64.c * * Copyrigh 2003 Anton Blanchard <anton@au.ibm.com>, IBM Corp. * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. */#define DEBUG#include <linux/kernel.h>#include <linux/pci.h>#include <linux/string.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/notifier.h>#include <asm/processor.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/pci-bridge.h>#include <asm/machdep.h>#include <asm/ppc-pci.h>#include <asm/firmware.h>unsigned long isa_io_base;	/* NULL if no ISA bus */EXPORT_SYMBOL(isa_io_base);/* Cached ISA bridge dev. */static struct device_node *isa_bridge_devnode;struct pci_dev *isa_bridge_pcidev;EXPORT_SYMBOL_GPL(isa_bridge_pcidev);#define ISA_SPACE_MASK 0x1#define ISA_SPACE_IO 0x1static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,						unsigned long phb_io_base_phys){	/* We should get some saner parsing here and remove these structs */	struct pci_address {		u32 a_hi;		u32 a_mid;		u32 a_lo;	};	struct isa_address {		u32 a_hi;		u32 a_lo;	};	struct isa_range {		struct isa_address isa_addr;		struct pci_address pci_addr;		unsigned int size;	};	const struct isa_range *range;	unsigned long pci_addr;	unsigned int isa_addr;	unsigned int size;	int rlen = 0;	range = of_get_property(isa_node, "ranges", &rlen);	if (range == NULL || (rlen < sizeof(struct isa_range)))		goto inval_range;	/* From "ISA Binding to 1275"	 * The ranges property is laid out as an array of elements,	 * each of which comprises:	 *   cells 0 - 1:	an ISA address	 *   cells 2 - 4:	a PCI address	 *			(size depending on dev->n_addr_cells)	 *   cell 5:		the size of the range	 */	if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) {		range++;		rlen -= sizeof(struct isa_range);		if (rlen < sizeof(struct isa_range))			goto inval_range;	}	if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO)		goto inval_range;	isa_addr = range->isa_addr.a_lo;	pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |		range->pci_addr.a_lo;	/* Assume these are both zero. Note: We could fix that and	 * do a proper parsing instead ... oh well, that will do for	 * now as nobody uses fancy mappings for ISA bridges	 */	if ((pci_addr != 0) || (isa_addr != 0)) {		printk(KERN_ERR "unexpected isa to pci mapping: %s\n",		       __FUNCTION__);		return;	}	/* Align size and make sure it's cropped to 64K */	size = PAGE_ALIGN(range->size);	if (size > 0x10000)		size = 0x10000;	printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"	       "mapping 64k\n");	__ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,		     size, _PAGE_NO_CACHE|_PAGE_GUARDED);	return;inval_range:	printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"	       "mapping 64k\n");	__ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,		     0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED);}/** * isa_bridge_find_early - Find and map the ISA IO space early before *                         main PCI discovery. This is optionally called by *                         the arch code when adding PCI PHBs to get early *                         access to ISA IO ports */void __init isa_bridge_find_early(struct pci_controller *hose){	struct device_node *np, *parent = NULL, *tmp;	/* If we already have an ISA bridge, bail off */	if (isa_bridge_devnode != NULL)		return;	/* For each "isa" node in the system. Note : we do a search by	 * type and not by name. It might be better to do by name but that's	 * what the code used to do and I don't want to break too much at	 * once. We can look into changing that separately	 */	for_each_node_by_type(np, "isa") {		/* Look for our hose being a parent */		for (parent = of_get_parent(np); parent;) {			if (parent == hose->arch_data) {				of_node_put(parent);				break;			}			tmp = parent;			parent = of_get_parent(parent);			of_node_put(tmp);		}		if (parent != NULL)			break;	}	if (np == NULL)		return;	isa_bridge_devnode = np;	/* Now parse the "ranges" property and setup the ISA mapping */	pci_process_ISA_OF_ranges(np, hose->io_base_phys);	/* Set the global ISA io base to indicate we have an ISA bridge */	isa_io_base = ISA_IO_BASE;	pr_debug("ISA bridge (early) is %s\n", np->full_name);}/** * isa_bridge_find_late - Find and map the ISA IO space upon discovery of *                        a new ISA bridge */static void __devinit isa_bridge_find_late(struct pci_dev *pdev,					   struct device_node *devnode){	struct pci_controller *hose = pci_bus_to_host(pdev->bus);	/* Store ISA device node and PCI device */	isa_bridge_devnode = of_node_get(devnode);	isa_bridge_pcidev = pdev;	/* Now parse the "ranges" property and setup the ISA mapping */	pci_process_ISA_OF_ranges(devnode, hose->io_base_phys);	/* Set the global ISA io base to indicate we have an ISA bridge */	isa_io_base = ISA_IO_BASE;	pr_debug("ISA bridge (late) is %s on %s\n",		 devnode->full_name, pci_name(pdev));}/** * isa_bridge_remove - Remove/unmap an ISA bridge */static void isa_bridge_remove(void){	pr_debug("ISA bridge removed !\n");	/* Clear the global ISA io base to indicate that we have no more	 * ISA bridge. Note that drivers don't quite handle that, though	 * we should probably do something about it. But do we ever really	 * have ISA bridges being removed on machines using legacy devices ?	 */	isa_io_base = ISA_IO_BASE;	/* Clear references to the bridge */	of_node_put(isa_bridge_devnode);	isa_bridge_devnode = NULL;	isa_bridge_pcidev = NULL;	/* Unmap the ISA area */	__iounmap_at((void *)ISA_IO_BASE, 0x10000);}/** * isa_bridge_notify - Get notified of PCI devices addition/removal */static int __devinit isa_bridge_notify(struct notifier_block *nb,				       unsigned long action, void *data){	struct device *dev = data;	struct pci_dev *pdev = to_pci_dev(dev);	struct device_node *devnode = pci_device_to_OF_node(pdev);	switch(action) {	case BUS_NOTIFY_ADD_DEVICE:		/* Check if we have an early ISA device, without PCI dev */		if (isa_bridge_devnode && isa_bridge_devnode == devnode &&		    !isa_bridge_pcidev) {			pr_debug("ISA bridge PCI attached: %s\n",				 pci_name(pdev));			isa_bridge_pcidev = pdev;		}		/* Check if we have no ISA device, and this happens to be one,		 * register it as such if it has an OF device		 */		if (!isa_bridge_devnode && devnode && devnode->type &&		    !strcmp(devnode->type, "isa"))			isa_bridge_find_late(pdev, devnode);		return 0;	case BUS_NOTIFY_DEL_DEVICE:		/* Check if this our existing ISA device */		if (pdev == isa_bridge_pcidev ||		    (devnode && devnode == isa_bridge_devnode))			isa_bridge_remove();		return 0;	}	return 0;}static struct notifier_block isa_bridge_notifier = {	.notifier_call = isa_bridge_notify};/** * isa_bridge_init - register to be notified of ISA bridge addition/removal * */static int __init isa_bridge_init(void){	if (firmware_has_feature(FW_FEATURE_ISERIES))		return 0;	bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);	return 0;}arch_initcall(isa_bridge_init);

⌨️ 快捷键说明

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