Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 61688
b: refs/heads/master
c: 81d87cb
h: refs/heads/master
v: v3
  • Loading branch information
Dave Jiang authored and Linus Torvalds committed Jul 19, 2007
1 parent 31afcd0 commit cc696b5
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 98 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 535c6a53035d8911f6b90455550c5fde0da7b866
refs/heads/master: 81d87cb13e367bb804bf44889ae0de7369705d6c
14 changes: 14 additions & 0 deletions trunk/drivers/edac/edac_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,15 @@ struct mem_ctl_info {
/* edac sysfs device control */
struct kobject edac_mci_kobj;
struct completion kobj_complete;

/* work struct for this MC */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
struct delayed_work work;
#else
struct work_struct work;
#endif
/* the internal state of this controller instance */
int op_state;
};

/*
Expand Down Expand Up @@ -573,6 +582,9 @@ struct edac_device_ctl_info {
};

/* To get from the instance's wq to the beginning of the ctl structure */
#define to_edac_mem_ctl_work(w) \
container_of(w, struct mem_ctl_info, work)

#define to_edac_device_ctl_work(w) \
container_of(w,struct edac_device_ctl_info,work)

Expand All @@ -584,6 +596,8 @@ static inline void edac_device_calc_delay(
edac_dev->delay = edac_dev->poll_msec * HZ / 1000;
}

#define edac_calc_delay(dev) dev->delay = dev->poll_msec * HZ / 1000;

/*
* The alloc() and free() functions for the 'edac_device' control info
* structure. A MC driver will allocate one of these for each edac_device
Expand Down
36 changes: 20 additions & 16 deletions trunk/drivers/edac/edac_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,17 +332,17 @@ EXPORT_SYMBOL(edac_device_find);


/*
* edac_workq_function
* edac_device_workq_function
* performs the operation scheduled by a workq request
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
static void edac_workq_function(struct work_struct *work_req)
static void edac_device_workq_function(struct work_struct *work_req)
{
struct delayed_work *d_work = (struct delayed_work*) work_req;
struct edac_device_ctl_info *edac_dev =
to_edac_device_ctl_work(d_work);
#else
static void edac_workq_function(void *ptr)
static void edac_device_workq_function(void *ptr)
{
struct edac_device_ctl_info *edac_dev =
(struct edac_device_ctl_info *) ptr;
Expand All @@ -364,30 +364,31 @@ static void edac_workq_function(void *ptr)
}

/*
* edac_workq_setup
* edac_device_workq_setup
* initialize a workq item for this edac_device instance
* passing in the new delay period in msec
*/
void edac_workq_setup(struct edac_device_ctl_info *edac_dev, unsigned msec)
void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
unsigned msec)
{
debugf0("%s()\n", __func__);

edac_dev->poll_msec = msec;
edac_device_calc_delay(edac_dev); /* Calc delay jiffies */
edac_calc_delay(edac_dev); /* Calc delay jiffies */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
INIT_DELAYED_WORK(&edac_dev->work,edac_workq_function);
INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
#else
INIT_WORK(&edac_dev->work,edac_workq_function,edac_dev);
INIT_WORK(&edac_dev->work, edac_device_workq_function, edac_dev);
#endif
queue_delayed_work(edac_workqueue,&edac_dev->work, edac_dev->delay);
queue_delayed_work(edac_workqueue, &edac_dev->work, edac_dev->delay);
}

/*
* edac_workq_teardown
* edac_device_workq_teardown
* stop the workq processing on this edac_dev
*/
void edac_workq_teardown(struct edac_device_ctl_info *edac_dev)
void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
{
int status;

Expand All @@ -409,10 +410,10 @@ void edac_device_reset_delay_period(
lock_device_list();

/* cancel the current workq request */
edac_workq_teardown(edac_dev);
edac_device_workq_teardown(edac_dev);

/* restart the workq request, with new delay value */
edac_workq_setup(edac_dev, value);
edac_device_workq_setup(edac_dev, value);

unlock_device_list();
}
Expand Down Expand Up @@ -479,8 +480,11 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx)
/* This instance is NOW RUNNING */
edac_dev->op_state = OP_RUNNING_POLL;

/* enable workq processing on this instance, default = 1000 msec */
edac_workq_setup(edac_dev, 1000);
/*
* enable workq processing on this instance,
* default = 1000 msec
*/
edac_device_workq_setup(edac_dev, 1000);
} else {
edac_dev->op_state = OP_RUNNING_INTERRUPT;
}
Expand Down Expand Up @@ -538,7 +542,7 @@ struct edac_device_ctl_info * edac_device_del_device(struct device *dev)
edac_dev->op_state = OP_OFFLINE;

/* clear workq processing on this instance */
edac_workq_teardown(edac_dev);
edac_device_workq_teardown(edac_dev);

/* Tear down the sysfs entries for this instance */
edac_device_remove_sysfs(edac_dev);
Expand Down
119 changes: 119 additions & 0 deletions trunk/drivers/edac/edac_mc.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
}
}

mci->op_state = OP_ALLOC;

return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_alloc);
Expand Down Expand Up @@ -215,6 +217,107 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
return NULL;
}

/*
* handler for EDAC to check if NMI type handler has asserted interrupt
*/
static int edac_mc_assert_error_check_and_clear(void)
{
int vreg;

if(edac_op_state == EDAC_OPSTATE_POLL)
return 1;

vreg = atomic_read(&edac_err_assert);
if(vreg) {
atomic_set(&edac_err_assert, 0);
return 1;
}

return 0;
}

/*
* edac_mc_workq_function
* performs the operation scheduled by a workq request
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
static void edac_mc_workq_function(struct work_struct *work_req)
{
struct delayed_work *d_work = (struct delayed_work*) work_req;
struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
#else
static void edac_mc_workq_function(void *ptr)
{
struct mem_ctl_info *mci = (struct mem_ctl_info *) ptr;
#endif

mutex_lock(&mem_ctls_mutex);

/* Only poll controllers that are running polled and have a check */
if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
mci->edac_check(mci);

/*
* FIXME: temp place holder for PCI checks,
* goes away when we break out PCI
*/
edac_pci_do_parity_check();

mutex_unlock(&mem_ctls_mutex);

/* Reschedule */
queue_delayed_work(edac_workqueue, &mci->work, edac_mc_get_poll_msec());
}

/*
* edac_mc_workq_setup
* initialize a workq item for this mci
* passing in the new delay period in msec
*/
void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
{
debugf0("%s()\n", __func__);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
#else
INIT_WORK(&mci->work, edac_mc_workq_function, mci);
#endif
queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
}

/*
* edac_mc_workq_teardown
* stop the workq processing on this mci
*/
void edac_mc_workq_teardown(struct mem_ctl_info *mci)
{
int status;

status = cancel_delayed_work(&mci->work);
if (status == 0) {
/* workq instance might be running, wait for it */
flush_workqueue(edac_workqueue);
}
}

/*
* edac_reset_delay_period
*/

void edac_reset_delay_period(struct mem_ctl_info *mci, unsigned long value)
{
mutex_lock(&mem_ctls_mutex);

/* cancel the current workq request */
edac_mc_workq_teardown(mci);

/* restart the workq request, with new delay value */
edac_mc_workq_setup(mci, value);

mutex_unlock(&mem_ctls_mutex);
}

/* Return 0 on success, 1 on failure.
* Before calling this function, caller must
* assign a unique value to mci->mc_idx.
Expand Down Expand Up @@ -351,6 +454,16 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
goto fail1;
}

/* If there IS a check routine, then we are running POLLED */
if (mci->edac_check != NULL) {
/* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL;

edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
}

/* Report action taken */
edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
mci->mod_name, mci->ctl_name, dev_name(mci));
Expand Down Expand Up @@ -386,6 +499,12 @@ struct mem_ctl_info * edac_mc_del_mc(struct device *dev)
return NULL;
}

/* marking MCI offline */
mci->op_state = OP_OFFLINE;

/* flush workq processes */
edac_mc_workq_teardown(mci);

edac_remove_sysfs_mci_device(mci);
del_mc_from_global_list(mci);
mutex_unlock(&mem_ctls_mutex);
Expand Down
14 changes: 10 additions & 4 deletions trunk/drivers/edac/edac_mc_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,28 @@ static int panic_on_ue;
static int poll_msec = 1000;

/* Getter functions for above */
int edac_get_log_ue()
int edac_get_log_ue(void)
{
return log_ue;
}

int edac_get_log_ce()
int edac_get_log_ce(void)
{
return log_ce;
}

int edac_get_panic_on_ue()
int edac_get_panic_on_ue(void)
{
return panic_on_ue;
}

int edac_get_poll_msec()
/* this is temporary */
int edac_mc_get_poll_msec(void)
{
return edac_get_poll_msec();
}

int edac_get_poll_msec(void)
{
return poll_msec;
}
Expand Down
Loading

0 comments on commit cc696b5

Please sign in to comment.