edac_pci_sysfs.c

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

C
764
字号
	}	/* Instanstiate the pci object */	/* FIXME: maybe new sysdev_create_subdir() */	err = kobject_register(&edac_pci_top_main_kobj);	if (err) {		debugf1("Failed to register '.../edac/pci'\n");		goto kobject_register_fail;	}	/* At this point, to 'release' the top level kobject	 * for EDAC PCI, then edac_pci_main_kobj_teardown()	 * must be used, for resources to be cleaned up properly	 */	debugf1("Registered '.../edac/pci' kobject\n");	return 0;	/* Error unwind statck */kobject_register_fail:	module_put(THIS_MODULE);decrement_count_fail:	/* if are on this error exit, nothing to tear down */	atomic_dec(&edac_pci_sysfs_refcount);	return err;}/* * edac_pci_main_kobj_teardown() * *	if no longer linked (needed) remove the top level EDAC PCI *	kobject with its controls and attributes */static void edac_pci_main_kobj_teardown(void){	debugf0("%s()\n", __func__);	/* Decrement the count and only if no more controller instances	 * are connected perform the unregisteration of the top level	 * main kobj	 */	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {		debugf0("%s() called kobject_unregister on main kobj\n",			__func__);		kobject_unregister(&edac_pci_top_main_kobj);	}}/* * * edac_pci_create_sysfs * *	Create the controls/attributes for the specified EDAC PCI device */int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci){	int err;	struct kobject *edac_kobj = &pci->kobj;	debugf0("%s() idx=%d\n", __func__, pci->pci_idx);	/* create the top main EDAC PCI kobject, IF needed */	err = edac_pci_main_kobj_setup();	if (err)		return err;	/* Create this instance's kobject under the MAIN kobject */	err = edac_pci_create_instance_kobj(pci, pci->pci_idx);	if (err)		goto unregister_cleanup;	err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);	if (err) {		debugf0("%s() sysfs_create_link() returned err= %d\n",			__func__, err);		goto symlink_fail;	}	return 0;	/* Error unwind stack */symlink_fail:	edac_pci_unregister_sysfs_instance_kobj(pci);unregister_cleanup:	edac_pci_main_kobj_teardown();	return err;}/* * edac_pci_remove_sysfs * *	remove the controls and attributes for this EDAC PCI device */void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci){	debugf0("%s() index=%d\n", __func__, pci->pci_idx);	/* Remove the symlink */	sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);	/* remove this PCI instance's sysfs entries */	edac_pci_unregister_sysfs_instance_kobj(pci);	/* Call the main unregister function, which will determine	 * if this 'pci' is the last instance.	 * If it is, the main kobject will be unregistered as a result	 */	debugf0("%s() calling edac_pci_main_kobj_teardown()\n", __func__);	edac_pci_main_kobj_teardown();}/************************ PCI error handling *************************/static u16 get_pci_parity_status(struct pci_dev *dev, int secondary){	int where;	u16 status;	where = secondary ? PCI_SEC_STATUS : PCI_STATUS;	pci_read_config_word(dev, where, &status);	/* If we get back 0xFFFF then we must suspect that the card has been	 * pulled but the Linux PCI layer has not yet finished cleaning up.	 * We don't want to report on such devices	 */	if (status == 0xFFFF) {		u32 sanity;		pci_read_config_dword(dev, 0, &sanity);		if (sanity == 0xFFFFFFFF)			return 0;	}	status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |		PCI_STATUS_PARITY;	if (status)		/* reset only the bits we are interested in */		pci_write_config_word(dev, where, status);	return status;}/* Clear any PCI parity errors logged by this device. */static void edac_pci_dev_parity_clear(struct pci_dev *dev){	u8 header_type;	debugf0("%s()\n", __func__);	get_pci_parity_status(dev, 0);	/* read the device TYPE, looking for bridges */	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)		get_pci_parity_status(dev, 1);}/* *  PCI Parity polling * *	Fucntion to retrieve the current parity status *	and decode it * */static void edac_pci_dev_parity_test(struct pci_dev *dev){	unsigned long flags;	u16 status;	u8 header_type;	/* stop any interrupts until we can acquire the status */	local_irq_save(flags);	/* read the STATUS register on this device */	status = get_pci_parity_status(dev, 0);	/* read the device TYPE, looking for bridges */	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);	local_irq_restore(flags);	debugf4("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);	/* check the status reg for errors */	if (status) {		if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {			edac_printk(KERN_CRIT, EDAC_PCI,				"Signaled System Error on %s\n",				pci_name(dev));			atomic_inc(&pci_nonparity_count);		}		if (status & (PCI_STATUS_PARITY)) {			edac_printk(KERN_CRIT, EDAC_PCI,				"Master Data Parity Error on %s\n",				pci_name(dev));			atomic_inc(&pci_parity_count);		}		if (status & (PCI_STATUS_DETECTED_PARITY)) {			edac_printk(KERN_CRIT, EDAC_PCI,				"Detected Parity Error on %s\n",				pci_name(dev));			atomic_inc(&pci_parity_count);		}	}	debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {		/* On bridges, need to examine secondary status register  */		status = get_pci_parity_status(dev, 1);		debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);		/* check the secondary status reg for errors */		if (status) {			if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "					"Signaled System Error on %s\n",					pci_name(dev));				atomic_inc(&pci_nonparity_count);			}			if (status & (PCI_STATUS_PARITY)) {				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "					"Master Data Parity Error on "					"%s\n", pci_name(dev));				atomic_inc(&pci_parity_count);			}			if (status & (PCI_STATUS_DETECTED_PARITY)) {				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "					"Detected Parity Error on %s\n",					pci_name(dev));				atomic_inc(&pci_parity_count);			}		}	}}/* reduce some complexity in definition of the iterator */typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);/* * pci_dev parity list iterator *	Scan the PCI device list for one pass, looking for SERRORs *	Master Parity ERRORS or Parity ERRORs on primary or secondary devices */static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn){	struct pci_dev *dev = NULL;	/* request for kernel access to the next PCI device, if any,	 * and while we are looking at it have its reference count	 * bumped until we are done with it	 */	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {		fn(dev);	}}/* * edac_pci_do_parity_check * *	performs the actual PCI parity check operation */void edac_pci_do_parity_check(void){	int before_count;	debugf3("%s()\n", __func__);	/* if policy has PCI check off, leave now */	if (!check_pci_errors)		return;	before_count = atomic_read(&pci_parity_count);	/* scan all PCI devices looking for a Parity Error on devices and	 * bridges.	 * The iterator calls pci_get_device() which might sleep, thus	 * we cannot disable interrupts in this scan.	 */	edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);	/* Only if operator has selected panic on PCI Error */	if (edac_pci_get_panic_on_pe()) {		/* If the count is different 'after' from 'before' */		if (before_count != atomic_read(&pci_parity_count))			panic("EDAC: PCI Parity Error");	}}/* * edac_pci_clear_parity_errors * *	function to perform an iteration over the PCI devices *	and clearn their current status */void edac_pci_clear_parity_errors(void){	/* Clear any PCI bus parity errors that devices initially have logged	 * in their registers.	 */	edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);}/* * edac_pci_handle_pe * *	Called to handle a PARITY ERROR event */void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg){	/* global PE counter incremented by edac_pci_do_parity_check() */	atomic_inc(&pci->counters.pe_count);	if (edac_pci_get_log_pe())		edac_pci_printk(pci, KERN_WARNING,				"Parity Error ctl: %s %d: %s\n",				pci->ctl_name, pci->pci_idx, msg);	/*	 * poke all PCI devices and see which one is the troublemaker	 * panic() is called if set	 */	edac_pci_do_parity_check();}EXPORT_SYMBOL_GPL(edac_pci_handle_pe);/* * edac_pci_handle_npe * *	Called to handle a NON-PARITY ERROR event */void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg){	/* global NPE counter incremented by edac_pci_do_parity_check() */	atomic_inc(&pci->counters.npe_count);	if (edac_pci_get_log_npe())		edac_pci_printk(pci, KERN_WARNING,				"Non-Parity Error ctl: %s %d: %s\n",				pci->ctl_name, pci->pci_idx, msg);	/*	 * poke all PCI devices and see which one is the troublemaker	 * panic() is called if set	 */	edac_pci_do_parity_check();}EXPORT_SYMBOL_GPL(edac_pci_handle_npe);/* * Define the PCI parameter to the module */module_param(check_pci_errors, int, 0644);MODULE_PARM_DESC(check_pci_errors,		 "Check for PCI bus parity errors: 0=off 1=on");module_param(edac_pci_panic_on_pe, int, 0644);MODULE_PARM_DESC(edac_pci_panic_on_pe,		 "Panic on PCI Bus Parity error: 0=off 1=on");#endif				/* CONFIG_PCI */

⌨️ 快捷键说明

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