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

📄 eeh.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/** * __restore_bars - Restore the Base Address Registers * Loads the PCI configuration space base address registers, * the expansion ROM base address, the latency timer, and etc. * from the saved values in the device node. */static inline void __restore_bars (struct pci_dn *pdn){	int i;	if (NULL==pdn->phb) return;	for (i=4; i<10; i++) {		rtas_write_config(pdn, i*4, 4, pdn->config_space[i]);	}	/* 12 == Expansion ROM Address */	rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]);#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)])	rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1,	            SAVED_BYTE(PCI_CACHE_LINE_SIZE));	rtas_write_config (pdn, PCI_LATENCY_TIMER, 1,	            SAVED_BYTE(PCI_LATENCY_TIMER));	/* max latency, min grant, interrupt pin and line */	rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]);}/** * eeh_restore_bars - restore the PCI config space info * * This routine performs a recursive walk to the children * of this device as well. */void eeh_restore_bars(struct pci_dn *pdn){	struct device_node *dn;	if (!pdn) 		return;		if (! pdn->eeh_is_bridge)		__restore_bars (pdn);	dn = pdn->node->child;	while (dn) {		eeh_restore_bars (PCI_DN(dn));		dn = dn->sibling;	}}/** * eeh_save_bars - save device bars * * Save the values of the device bars. Unlike the restore * routine, this routine is *not* recursive. This is because * PCI devices are added individuallly; but, for the restore, * an entire slot is reset at a time. */static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn){	int i;	if (!pdev || !pdn )		return;		for (i = 0; i < 16; i++)		pci_read_config_dword(pdev, i * 4, &pdn->config_space[i]);	if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE)		pdn->eeh_is_bridge = 1;}voidrtas_configure_bridge(struct pci_dn *pdn){	int token = rtas_token ("ibm,configure-bridge");	int rc;	if (token == RTAS_UNKNOWN_SERVICE)		return;	rc = rtas_call(token,3,1, NULL,	               pdn->eeh_config_addr,	               BUID_HI(pdn->phb->buid),	               BUID_LO(pdn->phb->buid));	if (rc) {		printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",		        rc, pdn->node->full_name);	}}/* ------------------------------------------------------------- *//* The code below deals with enabling EEH for devices during  the * early boot sequence.  EEH must be enabled before any PCI probing * can be done. */#define EEH_ENABLE 1struct eeh_early_enable_info {	unsigned int buid_hi;	unsigned int buid_lo;};/* Enable eeh for the given device node. */static void *early_enable_eeh(struct device_node *dn, void *data){	struct eeh_early_enable_info *info = data;	int ret;	char *status = get_property(dn, "status", NULL);	u32 *class_code = (u32 *)get_property(dn, "class-code", NULL);	u32 *vendor_id = (u32 *)get_property(dn, "vendor-id", NULL);	u32 *device_id = (u32 *)get_property(dn, "device-id", NULL);	u32 *regs;	int enable;	struct pci_dn *pdn = PCI_DN(dn);	pdn->eeh_mode = 0;	pdn->eeh_check_count = 0;	pdn->eeh_freeze_count = 0;	if (status && strcmp(status, "ok") != 0)		return NULL;	/* ignore devices with bad status */	/* Ignore bad nodes. */	if (!class_code || !vendor_id || !device_id)		return NULL;	/* There is nothing to check on PCI to ISA bridges */	if (dn->type && !strcmp(dn->type, "isa")) {		pdn->eeh_mode |= EEH_MODE_NOCHECK;		return NULL;	}	/*	 * Now decide if we are going to "Disable" EEH checking	 * for this device.  We still run with the EEH hardware active,	 * but we won't be checking for ff's.  This means a driver	 * could return bad data (very bad!), an interrupt handler could	 * hang waiting on status bits that won't change, etc.	 * But there are a few cases like display devices that make sense.	 */	enable = 1;	/* i.e. we will do checking */	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)		enable = 0;	if (!enable)		pdn->eeh_mode |= EEH_MODE_NOCHECK;	/* Ok... see if this device supports EEH.  Some do, some don't,	 * and the only way to find out is to check each and every one. */	regs = (u32 *)get_property(dn, "reg", NULL);	if (regs) {		/* First register entry is addr (00BBSS00)  */		/* Try to enable eeh */		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,		                regs[0], info->buid_hi, info->buid_lo,		                EEH_ENABLE);		if (ret == 0) {			eeh_subsystem_enabled = 1;			pdn->eeh_mode |= EEH_MODE_SUPPORTED;			pdn->eeh_config_addr = regs[0];#ifdef DEBUG			printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name);#endif		} else {			/* This device doesn't support EEH, but it may have an			 * EEH parent, in which case we mark it as supported. */			if (dn->parent && PCI_DN(dn->parent)			    && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {				/* Parent supports EEH. */				pdn->eeh_mode |= EEH_MODE_SUPPORTED;				pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr;				return NULL;			}		}	} else {		printk(KERN_WARNING "EEH: %s: unable to get reg property.\n",		       dn->full_name);	}	return NULL;}/* * Initialize EEH by trying to enable it for all of the adapters in the system. * As a side effect we can determine here if eeh is supported at all. * Note that we leave EEH on so failed config cycles won't cause a machine * check.  If a user turns off EEH for a particular adapter they are really * telling Linux to ignore errors.  Some hardware (e.g. POWER5) won't * grant access to a slot if EEH isn't enabled, and so we always enable * EEH for all slots/all devices. * * The eeh-force-off option disables EEH checking globally, for all slots. * Even if force-off is set, the EEH hardware is still enabled, so that * newer systems can boot. */void __init eeh_init(void){	struct device_node *phb, *np;	struct eeh_early_enable_info info;	spin_lock_init(&confirm_error_lock);	spin_lock_init(&slot_errbuf_lock);	np = of_find_node_by_path("/rtas");	if (np == NULL)		return;	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");	ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2");	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");	ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)		return;	eeh_error_buf_size = rtas_token("rtas-error-log-max");	if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {		eeh_error_buf_size = 1024;	}	if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {		printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated "		      "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX);		eeh_error_buf_size = RTAS_ERROR_LOG_MAX;	}	/* Enable EEH for all adapters.  Note that eeh requires buid's */	for (phb = of_find_node_by_name(NULL, "pci"); phb;	     phb = of_find_node_by_name(phb, "pci")) {		unsigned long buid;		buid = get_phb_buid(phb);		if (buid == 0 || PCI_DN(phb) == NULL)			continue;		info.buid_lo = BUID_LO(buid);		info.buid_hi = BUID_HI(buid);		traverse_pci_devices(phb, early_enable_eeh, &info);	}	if (eeh_subsystem_enabled)		printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");	else		printk(KERN_WARNING "EEH: No capable adapters found\n");}/** * eeh_add_device_early - enable EEH for the indicated device_node * @dn: device node for which to set up EEH * * This routine must be used to perform EEH initialization for PCI * devices that were added after system boot (e.g. hotplug, dlpar). * This routine must be called before any i/o is performed to the * adapter (inluding any config-space i/o). * Whether this actually enables EEH or not for this device depends * on the CEC architecture, type of the device, on earlier boot * command-line arguments & etc. */void eeh_add_device_early(struct device_node *dn){	struct pci_controller *phb;	struct eeh_early_enable_info info;	if (!dn || !PCI_DN(dn))		return;	phb = PCI_DN(dn)->phb;	if (NULL == phb || 0 == phb->buid) {		printk(KERN_WARNING "EEH: Expected buid but found none for %s\n",		       dn->full_name);		dump_stack();		return;	}	info.buid_hi = BUID_HI(phb->buid);	info.buid_lo = BUID_LO(phb->buid);	early_enable_eeh(dn, &info);}EXPORT_SYMBOL_GPL(eeh_add_device_early);/** * eeh_add_device_late - perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH * * This routine must be used to complete EEH initialization for PCI * devices that were added after system boot (e.g. hotplug, dlpar). */void eeh_add_device_late(struct pci_dev *dev){	struct device_node *dn;	struct pci_dn *pdn;	if (!dev || !eeh_subsystem_enabled)		return;#ifdef DEBUG	printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev));#endif	pci_dev_get (dev);	dn = pci_device_to_OF_node(dev);	pdn = PCI_DN(dn);	pdn->pcidev = dev;	pci_addr_cache_insert_device (dev);	eeh_save_bars(dev, pdn);}EXPORT_SYMBOL_GPL(eeh_add_device_late);/** * eeh_remove_device - undo EEH setup for the indicated pci device * @dev: pci device to be removed * * This routine should be when a device is removed from a running * system (e.g. by hotplug or dlpar). */void eeh_remove_device(struct pci_dev *dev){	struct device_node *dn;	if (!dev || !eeh_subsystem_enabled)		return;	/* Unregister the device with the EEH/PCI address search system */#ifdef DEBUG	printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev));#endif	pci_addr_cache_remove_device(dev);	dn = pci_device_to_OF_node(dev);	PCI_DN(dn)->pcidev = NULL;	pci_dev_put (dev);}EXPORT_SYMBOL_GPL(eeh_remove_device);static int proc_eeh_show(struct seq_file *m, void *v){	unsigned int cpu;	unsigned long ffs = 0, positives = 0, failures = 0;	unsigned long resets = 0;	unsigned long no_dev = 0, no_dn = 0, no_cfg = 0, no_check = 0;	for_each_cpu(cpu) {		ffs += per_cpu(total_mmio_ffs, cpu);		positives += per_cpu(false_positives, cpu);		failures += per_cpu(ignored_failures, cpu);		resets += per_cpu(slot_resets, cpu);		no_dev += per_cpu(no_device, cpu);		no_dn += per_cpu(no_dn, cpu);		no_cfg += per_cpu(no_cfg_addr, cpu);		no_check += per_cpu(ignored_check, cpu);	}	if (0 == eeh_subsystem_enabled) {		seq_printf(m, "EEH Subsystem is globally disabled\n");		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs);	} else {		seq_printf(m, "EEH Subsystem is enabled\n");		seq_printf(m,				"no device=%ld\n"				"no device node=%ld\n"				"no config address=%ld\n"				"check not wanted=%ld\n"				"eeh_total_mmio_ffs=%ld\n"				"eeh_false_positives=%ld\n"				"eeh_ignored_failures=%ld\n"				"eeh_slot_resets=%ld\n",				no_dev, no_dn, no_cfg, no_check,				ffs, positives, failures, resets);	}	return 0;}static int proc_eeh_open(struct inode *inode, struct file *file){	return single_open(file, proc_eeh_show, NULL);}static struct file_operations proc_eeh_operations = {	.open      = proc_eeh_open,	.read      = seq_read,	.llseek    = seq_lseek,	.release   = single_release,};static int __init eeh_init_proc(void){	struct proc_dir_entry *e;	if (platform_is_pseries()) {		e = create_proc_entry("ppc64/eeh", 0, NULL);		if (e)			e->proc_fops = &proc_eeh_operations;	}	return 0;}__initcall(eeh_init_proc);

⌨️ 快捷键说明

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