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 + -
显示快捷键?