pci.c

来自「linux 内核源代码」· C语言 代码 · 共 1,295 行 · 第 1/3 页

C
1,295
字号
/* pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) * Copyright (C) 1998, 1999 Eddie C. Dost   (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek   (jj@ultra.linux.cz) * * OF tree based PCI bus probing taken from the PowerPC port * with minor modifications, see there for credits. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/capability.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/msi.h>#include <linux/irq.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/irq.h>#include <asm/ebus.h>#include <asm/isa.h>#include <asm/prom.h>#include <asm/apb.h>#include "pci_impl.h"#ifndef CONFIG_PCI/* A "nop" PCI implementation. */asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,				  unsigned long off, unsigned long len,				  unsigned char *buf){	return 0;}asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,				   unsigned long off, unsigned long len,				   unsigned char *buf){	return 0;}#else/* List of all PCI controllers found in the system. */struct pci_pbm_info *pci_pbm_root = NULL;/* Each PBM found gets a unique index. */int pci_num_pbms = 0;volatile int pci_poke_in_progress;volatile int pci_poke_cpu = -1;volatile int pci_poke_faulted;static DEFINE_SPINLOCK(pci_poke_lock);void pci_config_read8(u8 *addr, u8 *ret){	unsigned long flags;	u8 byte;	spin_lock_irqsave(&pci_poke_lock, flags);	pci_poke_cpu = smp_processor_id();	pci_poke_in_progress = 1;	pci_poke_faulted = 0;	__asm__ __volatile__("membar #Sync\n\t"			     "lduba [%1] %2, %0\n\t"			     "membar #Sync"			     : "=r" (byte)			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)			     : "memory");	pci_poke_in_progress = 0;	pci_poke_cpu = -1;	if (!pci_poke_faulted)		*ret = byte;	spin_unlock_irqrestore(&pci_poke_lock, flags);}void pci_config_read16(u16 *addr, u16 *ret){	unsigned long flags;	u16 word;	spin_lock_irqsave(&pci_poke_lock, flags);	pci_poke_cpu = smp_processor_id();	pci_poke_in_progress = 1;	pci_poke_faulted = 0;	__asm__ __volatile__("membar #Sync\n\t"			     "lduha [%1] %2, %0\n\t"			     "membar #Sync"			     : "=r" (word)			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)			     : "memory");	pci_poke_in_progress = 0;	pci_poke_cpu = -1;	if (!pci_poke_faulted)		*ret = word;	spin_unlock_irqrestore(&pci_poke_lock, flags);}void pci_config_read32(u32 *addr, u32 *ret){	unsigned long flags;	u32 dword;	spin_lock_irqsave(&pci_poke_lock, flags);	pci_poke_cpu = smp_processor_id();	pci_poke_in_progress = 1;	pci_poke_faulted = 0;	__asm__ __volatile__("membar #Sync\n\t"			     "lduwa [%1] %2, %0\n\t"			     "membar #Sync"			     : "=r" (dword)			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)			     : "memory");	pci_poke_in_progress = 0;	pci_poke_cpu = -1;	if (!pci_poke_faulted)		*ret = dword;	spin_unlock_irqrestore(&pci_poke_lock, flags);}void pci_config_write8(u8 *addr, u8 val){	unsigned long flags;	spin_lock_irqsave(&pci_poke_lock, flags);	pci_poke_cpu = smp_processor_id();	pci_poke_in_progress = 1;	pci_poke_faulted = 0;	__asm__ __volatile__("membar #Sync\n\t"			     "stba %0, [%1] %2\n\t"			     "membar #Sync"			     : /* no outputs */			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)			     : "memory");	pci_poke_in_progress = 0;	pci_poke_cpu = -1;	spin_unlock_irqrestore(&pci_poke_lock, flags);}void pci_config_write16(u16 *addr, u16 val){	unsigned long flags;	spin_lock_irqsave(&pci_poke_lock, flags);	pci_poke_cpu = smp_processor_id();	pci_poke_in_progress = 1;	pci_poke_faulted = 0;	__asm__ __volatile__("membar #Sync\n\t"			     "stha %0, [%1] %2\n\t"			     "membar #Sync"			     : /* no outputs */			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)			     : "memory");	pci_poke_in_progress = 0;	pci_poke_cpu = -1;	spin_unlock_irqrestore(&pci_poke_lock, flags);}void pci_config_write32(u32 *addr, u32 val){	unsigned long flags;	spin_lock_irqsave(&pci_poke_lock, flags);	pci_poke_cpu = smp_processor_id();	pci_poke_in_progress = 1;	pci_poke_faulted = 0;	__asm__ __volatile__("membar #Sync\n\t"			     "stwa %0, [%1] %2\n\t"			     "membar #Sync"			     : /* no outputs */			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)			     : "memory");	pci_poke_in_progress = 0;	pci_poke_cpu = -1;	spin_unlock_irqrestore(&pci_poke_lock, flags);}/* Probe for all PCI controllers in the system. */extern void sabre_init(struct device_node *, const char *);extern void psycho_init(struct device_node *, const char *);extern void schizo_init(struct device_node *, const char *);extern void schizo_plus_init(struct device_node *, const char *);extern void tomatillo_init(struct device_node *, const char *);extern void sun4v_pci_init(struct device_node *, const char *);extern void fire_pci_init(struct device_node *, const char *);static struct {	char *model_name;	void (*init)(struct device_node *, const char *);} pci_controller_table[] __initdata = {	{ "SUNW,sabre", sabre_init },	{ "pci108e,a000", sabre_init },	{ "pci108e,a001", sabre_init },	{ "SUNW,psycho", psycho_init },	{ "pci108e,8000", psycho_init },	{ "SUNW,schizo", schizo_init },	{ "pci108e,8001", schizo_init },	{ "SUNW,schizo+", schizo_plus_init },	{ "pci108e,8002", schizo_plus_init },	{ "SUNW,tomatillo", tomatillo_init },	{ "pci108e,a801", tomatillo_init },	{ "SUNW,sun4v-pci", sun4v_pci_init },	{ "pciex108e,80f0", fire_pci_init },};#define PCI_NUM_CONTROLLER_TYPES	ARRAY_SIZE(pci_controller_table)static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp){	int i;	for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {		if (!strncmp(model_name,			     pci_controller_table[i].model_name,			     namelen)) {			pci_controller_table[i].init(dp, model_name);			return 1;		}	}	return 0;}static int __init pci_is_controller(const char *model_name, int namelen, struct device_node *dp){	int i;	for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {		if (!strncmp(model_name,			     pci_controller_table[i].model_name,			     namelen)) {			return 1;		}	}	return 0;}static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *)){	struct device_node *dp;	int count = 0;	for_each_node_by_name(dp, "pci") {		struct property *prop;		int len;		prop = of_find_property(dp, "model", &len);		if (!prop)			prop = of_find_property(dp, "compatible", &len);		if (prop) {			const char *model = prop->value;			int item_len = 0;			/* Our value may be a multi-valued string in the			 * case of some compatible properties. For sanity,			 * only try the first one.			 */			while (model[item_len] && len) {				len--;				item_len++;			}			if (handler(model, item_len, dp))				count++;		}	}	return count;}/* Is there some PCI controller in the system?  */int __init pcic_present(void){	return pci_controller_scan(pci_is_controller);}/* Find each controller in the system, attach and initialize * software state structure for each and link into the * pci_pbm_root.  Setup the controller enough such * that bus scanning can be done. */static void __init pci_controller_probe(void){	printk("PCI: Probing for controllers.\n");	pci_controller_scan(pci_controller_init);}static int ofpci_verbose;static int __init ofpci_debug(char *str){	int val = 0;	get_option(&str, &val);	if (val)		ofpci_verbose = 1;	return 1;}__setup("ofpci_debug=", ofpci_debug);static unsigned long pci_parse_of_flags(u32 addr0){	unsigned long flags = 0;	if (addr0 & 0x02000000) {		flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;		flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;		flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;		if (addr0 & 0x40000000)			flags |= IORESOURCE_PREFETCH				 | PCI_BASE_ADDRESS_MEM_PREFETCH;	} else if (addr0 & 0x01000000)		flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;	return flags;}/* The of_device layer has translated all of the assigned-address properties * into physical address resources, we only have to figure out the register * mapping. */static void pci_parse_of_addrs(struct of_device *op,			       struct device_node *node,			       struct pci_dev *dev){	struct resource *op_res;	const u32 *addrs;	int proplen;	addrs = of_get_property(node, "assigned-addresses", &proplen);	if (!addrs)		return;	if (ofpci_verbose)		printk("    parse addresses (%d bytes) @ %p\n",		       proplen, addrs);	op_res = &op->resource[0];	for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) {		struct resource *res;		unsigned long flags;		int i;		flags = pci_parse_of_flags(addrs[0]);		if (!flags)			continue;		i = addrs[0] & 0xff;		if (ofpci_verbose)			printk("  start: %lx, end: %lx, i: %x\n",			       op_res->start, op_res->end, i);		if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {			res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];		} else if (i == dev->rom_base_reg) {			res = &dev->resource[PCI_ROM_RESOURCE];			flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;		} else {			printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);			continue;		}		res->start = op_res->start;		res->end = op_res->end;		res->flags = flags;		res->name = pci_name(dev);	}}struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,				  struct device_node *node,				  struct pci_bus *bus, int devfn,				  int host_controller){	struct dev_archdata *sd;	struct pci_dev *dev;	const char *type;	u32 class;	dev = alloc_pci_dev();	if (!dev)		return NULL;	sd = &dev->dev.archdata;	sd->iommu = pbm->iommu;	sd->stc = &pbm->stc;	sd->host_controller = pbm;	sd->prom_node = node;	sd->op = of_find_device_by_node(node);	sd = &sd->op->dev.archdata;	sd->iommu = pbm->iommu;	sd->stc = &pbm->stc;	type = of_get_property(node, "device_type", NULL);	if (type == NULL)		type = "";	if (ofpci_verbose)		printk("    create device, devfn: %x, type: %s\n",		       devfn, type);	dev->bus = bus;	dev->sysdata = node;	dev->dev.parent = bus->bridge;	dev->dev.bus = &pci_bus_type;	dev->devfn = devfn;	dev->multifunction = 0;		/* maybe a lie? */	if (host_controller) {		if (tlb_type != hypervisor) {			pci_read_config_word(dev, PCI_VENDOR_ID,					     &dev->vendor);			pci_read_config_word(dev, PCI_DEVICE_ID,					     &dev->device);		} else {			dev->vendor = PCI_VENDOR_ID_SUN;			dev->device = 0x80f0;		}		dev->cfg_size = 256;		dev->class = PCI_CLASS_BRIDGE_HOST << 8;		sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),			0x00, PCI_SLOT(devfn), PCI_FUNC(devfn));	} else {		dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);		dev->device = of_getintprop_default(node, "device-id", 0xffff);		dev->subsystem_vendor =			of_getintprop_default(node, "subsystem-vendor-id", 0);		dev->subsystem_device =

⌨️ 快捷键说明

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