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

📄 eeh.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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_dn *pdn){	int i;	if (!pdn )		return;		for (i = 0; i < 16; i++)		rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]);}voidrtas_configure_bridge(struct pci_dn *pdn){	int config_addr;	int rc;	/* Use PE configuration address, if present */	config_addr = pdn->eeh_config_addr;	if (pdn->eeh_pe_config_addr)		config_addr = pdn->eeh_pe_config_addr;	rc = rtas_call(ibm_configure_bridge,3,1, NULL,	               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;};static int get_pe_addr (int config_addr,                        struct eeh_early_enable_info *info){	unsigned int rets[3];	int ret;	/* Use latest config-addr token on power6 */	if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {		/* Make sure we have a PE in hand */		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,			config_addr, info->buid_hi, info->buid_lo, 1);		if (ret || (rets[0]==0))			return 0;		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,			config_addr, info->buid_hi, info->buid_lo, 0);		if (ret)			return 0;		return rets[0];	}	/* Use older config-addr token on power5 */	if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {		ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,			config_addr, info->buid_hi, info->buid_lo, 0);		if (ret)			return 0;		return rets[0];	}	return 0;}/* Enable eeh for the given device node. */static void *early_enable_eeh(struct device_node *dn, void *data){	unsigned int rets[3];	struct eeh_early_enable_info *info = data;	int ret;	const char *status = of_get_property(dn, "status", NULL);	const u32 *class_code = of_get_property(dn, "class-code", NULL);	const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);	const u32 *device_id = of_get_property(dn, "device-id", NULL);	const u32 *regs;	int enable;	struct pci_dn *pdn = PCI_DN(dn);	pdn->class_code = 0;	pdn->eeh_mode = 0;	pdn->eeh_check_count = 0;	pdn->eeh_freeze_count = 0;	pdn->eeh_false_positives = 0;	if (status && strncmp(status, "ok", 2) != 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;	}	pdn->class_code = *class_code;	/* 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 = of_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);		enable = 0;		if (ret == 0) {			pdn->eeh_config_addr = regs[0];			/* If the newer, better, ibm,get-config-addr-info is supported, 			 * then use that instead. */			pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info);			/* Some older systems (Power4) allow the			 * ibm,set-eeh-option call to succeed even on nodes			 * where EEH is not supported. Verify support			 * explicitly. */			ret = read_slot_reset_state(pdn, rets);			if ((ret == 0) && (rets[1] == 1))				enable = 1;		}		if (enable) {			eeh_subsystem_enabled = 1;			pdn->eeh_mode |= EEH_MODE_SUPPORTED;#ifdef DEBUG			printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n",			       dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr);#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);	}	eeh_save_bars(pdn);	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");	ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");	ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");	ibm_configure_bridge = rtas_token ("ibm,configure-bridge");	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. */static 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;	/* USB Bus children of PCI devices will not have BUID's */	if (NULL == phb || 0 == phb->buid)		return;	info.buid_hi = BUID_HI(phb->buid);	info.buid_lo = BUID_LO(phb->buid);	early_enable_eeh(dn, &info);}void eeh_add_device_tree_early(struct device_node *dn){	struct device_node *sib;	for (sib = dn->child; sib; sib = sib->sibling)		eeh_add_device_tree_early(sib);	eeh_add_device_early(dn);}EXPORT_SYMBOL_GPL(eeh_add_device_tree_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). */static 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_sysfs_add_device(dev);}void eeh_add_device_tree_late(struct pci_bus *bus){	struct pci_dev *dev;	list_for_each_entry(dev, &bus->devices, bus_list) { 		eeh_add_device_late(dev); 		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 			struct pci_bus *subbus = dev->subordinate; 			if (subbus) 				eeh_add_device_tree_late(subbus); 		}	}}EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);/** * eeh_remove_device - undo EEH setup for the indicated pci device * @dev: pci device to be removed * * This routine should be called when a device is removed from * a running system (e.g. by hotplug or dlpar).  It unregisters * the PCI device from the EEH subsystem.  I/O errors affecting * this device will no longer be detected after this call; thus, * i/o errors affecting this slot may leave this device unusable. */static 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);	eeh_sysfs_remove_device(dev);	dn = pci_device_to_OF_node(dev);	if (PCI_DN(dn)->pcidev) {		PCI_DN(dn)->pcidev = NULL;		pci_dev_put (dev);	}}void eeh_remove_bus_device(struct pci_dev *dev){	struct pci_bus *bus = dev->subordinate;	struct pci_dev *child, *tmp;	eeh_remove_device(dev);	if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {		list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)			 eeh_remove_bus_device(child);	}}EXPORT_SYMBOL_GPL(eeh_remove_bus_device);static int proc_eeh_show(struct seq_file *m, void *v){	if (0 == eeh_subsystem_enabled) {		seq_printf(m, "EEH Subsystem is globally disabled\n");		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_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_slot_resets=%ld\n",				no_device, no_dn, no_cfg_addr, 				ignored_check, total_mmio_ffs, 				false_positives,				slot_resets);	}	return 0;}static int proc_eeh_open(struct inode *inode, struct file *file){	return single_open(file, proc_eeh_show, NULL);}static const 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 (machine_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 + -