/* * find_edac_pci_by_dev() * scans the edac_pci list for a specific 'struct device *' * * return NULL if not found, or return control struct pointer
*/ staticstruct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
{ struct edac_pci_ctl_info *pci; struct list_head *item;
/* * add_edac_pci_to_global_list * Before calling this function, caller must assign a unique value to * edac_dev->pci_idx. * Return: * 0 on success * 1 on failure
*/ staticint add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
{ struct list_head *item, *insert_before; struct edac_pci_ctl_info *rover;
edac_dbg(1, "\n");
insert_before = &edac_pci_list;
/* Determine if already on the list */
rover = find_edac_pci_by_dev(pci->dev); if (unlikely(rover != NULL)) goto fail0;
/* Insert in ascending order by 'pci_idx', so find position */
list_for_each(item, &edac_pci_list) {
rover = list_entry(item, struct edac_pci_ctl_info, link);
if (rover->pci_idx >= pci->pci_idx) { if (unlikely(rover->pci_idx == pci->pci_idx)) goto fail1;
fail1:
edac_printk(KERN_WARNING, EDAC_PCI, "but in low-level driver: attempt to assign\n" "\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
__func__); return 1;
}
/* * del_edac_pci_from_global_list * * remove the PCI control struct from the global list
*/ staticvoid del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
{
list_del_rcu(&pci->link);
/* these are for safe removal of devices from global list while * NMI handlers may be traversing list
*/
synchronize_rcu();
INIT_LIST_HEAD(&pci->link);
}
/* * edac_pci_workq_function() * * periodic function that performs the operation * scheduled by a workq request, for a given PCI control struct
*/ staticvoid edac_pci_workq_function(struct work_struct *work_req)
{ struct delayed_work *d_work = to_delayed_work(work_req); struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work); int msec; unsignedlong delay;
edac_dbg(3, "checking\n");
mutex_lock(&edac_pci_ctls_mutex);
if (pci->op_state != OP_RUNNING_POLL) {
mutex_unlock(&edac_pci_ctls_mutex); return;
}
if (edac_pci_get_check_errors())
pci->edac_check(pci);
/* if we are on a one second period, then use round */
msec = edac_pci_get_poll_msec(); if (msec == 1000)
delay = round_jiffies_relative(msecs_to_jiffies(msec)); else
delay = msecs_to_jiffies(msec);
edac_queue_work(&pci->work, delay);
mutex_unlock(&edac_pci_ctls_mutex);
}
int edac_pci_alloc_index(void)
{ return atomic_inc_return(&pci_indexes) - 1;
}
EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
{
edac_dbg(0, "\n");
/* ensure the control struct is on the global list * if not, then leave
*/
pci = find_edac_pci_by_dev(dev); if (pci == NULL) {
mutex_unlock(&edac_pci_ctls_mutex); return NULL;
}
pci->op_state = OP_OFFLINE;
del_edac_pci_from_global_list(pci);
mutex_unlock(&edac_pci_ctls_mutex);
if (pci->edac_check)
edac_stop_work(&pci->work);
edac_printk(KERN_INFO, EDAC_PCI, "Removed device %d for %s %s: DEV %s\n",
pci->pci_idx, pci->mod_name, pci->ctl_name, edac_dev_name(pci));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.