Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 187255
b: refs/heads/master
c: ae74e82
h: refs/heads/master
i:
  187253: 87ee8be
  187251: 04afc23
  187247: c0a9b8d
v: v3
  • Loading branch information
Martin Wilck authored and Linus Torvalds committed Mar 12, 2010
1 parent c843f97 commit d6fcf10
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 3 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: f1eb1332b8f07e937add24c6fd2ac40b8737a2f4
refs/heads/master: ae74e823cb7d4cd476f623fce9a38f625f6c09a8
12 changes: 12 additions & 0 deletions trunk/Documentation/IPMI.txt
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ You can change this at module load time (for a module) with:
regshifts=<shift1>,<shift2>,...
slave_addrs=<addr1>,<addr2>,...
force_kipmid=<enable1>,<enable2>,...
kipmid_max_busy_us=<ustime1>,<ustime2>,...
unload_when_empty=[0|1]

Each of these except si_trydefaults is a list, the first item for the
Expand Down Expand Up @@ -433,6 +434,7 @@ kernel command line as:
ipmi_si.regshifts=<shift1>,<shift2>,...
ipmi_si.slave_addrs=<addr1>,<addr2>,...
ipmi_si.force_kipmid=<enable1>,<enable2>,...
ipmi_si.kipmid_max_busy_us=<ustime1>,<ustime2>,...

It works the same as the module parameters of the same names.

Expand All @@ -450,6 +452,16 @@ force this thread on or off. If you force it off and don't have
interrupts, the driver will run VERY slowly. Don't blame me,
these interfaces suck.

Unfortunately, this thread can use a lot of CPU depending on the
interface's performance. This can waste a lot of CPU and cause
various issues with detecting idle CPU and using extra power. To
avoid this, the kipmid_max_busy_us sets the maximum amount of time, in
microseconds, that kipmid will spin before sleeping for a tick. This
value sets a balance between performance and CPU waste and needs to be
tuned to your needs. Maybe, someday, auto-tuning will be added, but
that's not a simple thing and even the auto-tuning would need to be
tuned to the user's desired performance.

The driver supports a hot add and remove of interfaces. This way,
interfaces can be added or removed after the kernel is up and running.
This is done using /sys/modules/ipmi_si/parameters/hotmod, which is a
Expand Down
66 changes: 64 additions & 2 deletions trunk/drivers/char/ipmi/ipmi_si_intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ struct smi_info {
static int force_kipmid[SI_MAX_PARMS];
static int num_force_kipmid;

static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
static int num_max_busy_us;

static int unload_when_empty = 1;

static int try_smi_init(struct smi_info *smi);
Expand Down Expand Up @@ -925,23 +928,77 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion)
}
}

/*
* Use -1 in the nsec value of the busy waiting timespec to tell that
* we are spinning in kipmid looking for something and not delaying
* between checks
*/
static inline void ipmi_si_set_not_busy(struct timespec *ts)
{
ts->tv_nsec = -1;
}
static inline int ipmi_si_is_busy(struct timespec *ts)
{
return ts->tv_nsec != -1;
}

static int ipmi_thread_busy_wait(enum si_sm_result smi_result,
const struct smi_info *smi_info,
struct timespec *busy_until)
{
unsigned int max_busy_us = 0;

if (smi_info->intf_num < num_max_busy_us)
max_busy_us = kipmid_max_busy_us[smi_info->intf_num];
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
ipmi_si_set_not_busy(busy_until);
else if (!ipmi_si_is_busy(busy_until)) {
getnstimeofday(busy_until);
timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
} else {
struct timespec now;
getnstimeofday(&now);
if (unlikely(timespec_compare(&now, busy_until) > 0)) {
ipmi_si_set_not_busy(busy_until);
return 0;
}
}
return 1;
}


/*
* A busy-waiting loop for speeding up IPMI operation.
*
* Lousy hardware makes this hard. This is only enabled for systems
* that are not BT and do not have interrupts. It starts spinning
* when an operation is complete or until max_busy tells it to stop
* (if that is enabled). See the paragraph on kimid_max_busy_us in
* Documentation/IPMI.txt for details.
*/
static int ipmi_thread(void *data)
{
struct smi_info *smi_info = data;
unsigned long flags;
enum si_sm_result smi_result;
struct timespec busy_until;

ipmi_si_set_not_busy(&busy_until);
set_user_nice(current, 19);
while (!kthread_should_stop()) {
int busy_wait;

spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_result = smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
&busy_until);
if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
; /* do nothing */
else if (smi_result == SI_SM_CALL_WITH_DELAY)
else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
schedule();
else
schedule_timeout_interruptible(1);
schedule_timeout_interruptible(0);
}
return 0;
}
Expand Down Expand Up @@ -1212,6 +1269,11 @@ module_param(unload_when_empty, int, 0);
MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
" specified or found, default is 1. Setting to 0"
" is useful for hot add of devices using hotmod.");
module_param_array(kipmid_max_busy_us, uint, &num_max_busy_us, 0644);
MODULE_PARM_DESC(kipmid_max_busy_us,
"Max time (in microseconds) to busy-wait for IPMI data before"
" sleeping. 0 (default) means to wait forever. Set to 100-500"
" if kipmid is using up a lot of CPU time.");


static void std_irq_cleanup(struct smi_info *info)
Expand Down

0 comments on commit d6fcf10

Please sign in to comment.