diff options
author | Martin Wilck <martin.wilck@ts.fujitsu.com> | 2010-03-10 18:23:06 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:39 -0500 |
commit | ae74e823cb7d4cd476f623fce9a38f625f6c09a8 (patch) | |
tree | 404aba91d5c634cfc8d3ecc847281f12fc8e5e1e | |
parent | f1eb1332b8f07e937add24c6fd2ac40b8737a2f4 (diff) |
ipmi: add parameter to limit CPU usage in kipmid
In some cases kipmid can use a lot of CPU. This adds a way to tune the
CPU used by kipmid to help in those cases. By setting kipmid_max_busy_us
to a value between 100 and 500, it is possible to bring down kipmid CPU
load to practically 0 without loosing too much ipmi throughput
performance. Not setting the value, or setting the value to zero,
operation is unaffected.
Signed-off-by: Martin Wilck <martin.wilck@ts.fujitsu.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/IPMI.txt | 12 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 66 |
2 files changed, 76 insertions, 2 deletions
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index bc38283379f0..69dd29ed824e 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt | |||
@@ -365,6 +365,7 @@ You can change this at module load time (for a module) with: | |||
365 | regshifts=<shift1>,<shift2>,... | 365 | regshifts=<shift1>,<shift2>,... |
366 | slave_addrs=<addr1>,<addr2>,... | 366 | slave_addrs=<addr1>,<addr2>,... |
367 | force_kipmid=<enable1>,<enable2>,... | 367 | force_kipmid=<enable1>,<enable2>,... |
368 | kipmid_max_busy_us=<ustime1>,<ustime2>,... | ||
368 | unload_when_empty=[0|1] | 369 | unload_when_empty=[0|1] |
369 | 370 | ||
370 | Each of these except si_trydefaults is a list, the first item for the | 371 | Each of these except si_trydefaults is a list, the first item for the |
@@ -433,6 +434,7 @@ kernel command line as: | |||
433 | ipmi_si.regshifts=<shift1>,<shift2>,... | 434 | ipmi_si.regshifts=<shift1>,<shift2>,... |
434 | ipmi_si.slave_addrs=<addr1>,<addr2>,... | 435 | ipmi_si.slave_addrs=<addr1>,<addr2>,... |
435 | ipmi_si.force_kipmid=<enable1>,<enable2>,... | 436 | ipmi_si.force_kipmid=<enable1>,<enable2>,... |
437 | ipmi_si.kipmid_max_busy_us=<ustime1>,<ustime2>,... | ||
436 | 438 | ||
437 | It works the same as the module parameters of the same names. | 439 | It works the same as the module parameters of the same names. |
438 | 440 | ||
@@ -450,6 +452,16 @@ force this thread on or off. If you force it off and don't have | |||
450 | interrupts, the driver will run VERY slowly. Don't blame me, | 452 | interrupts, the driver will run VERY slowly. Don't blame me, |
451 | these interfaces suck. | 453 | these interfaces suck. |
452 | 454 | ||
455 | Unfortunately, this thread can use a lot of CPU depending on the | ||
456 | interface's performance. This can waste a lot of CPU and cause | ||
457 | various issues with detecting idle CPU and using extra power. To | ||
458 | avoid this, the kipmid_max_busy_us sets the maximum amount of time, in | ||
459 | microseconds, that kipmid will spin before sleeping for a tick. This | ||
460 | value sets a balance between performance and CPU waste and needs to be | ||
461 | tuned to your needs. Maybe, someday, auto-tuning will be added, but | ||
462 | that's not a simple thing and even the auto-tuning would need to be | ||
463 | tuned to the user's desired performance. | ||
464 | |||
453 | The driver supports a hot add and remove of interfaces. This way, | 465 | The driver supports a hot add and remove of interfaces. This way, |
454 | interfaces can be added or removed after the kernel is up and running. | 466 | interfaces can be added or removed after the kernel is up and running. |
455 | This is done using /sys/modules/ipmi_si/parameters/hotmod, which is a | 467 | This is done using /sys/modules/ipmi_si/parameters/hotmod, which is a |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 176f1751237f..c234ada64565 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -295,6 +295,9 @@ struct smi_info { | |||
295 | static int force_kipmid[SI_MAX_PARMS]; | 295 | static int force_kipmid[SI_MAX_PARMS]; |
296 | static int num_force_kipmid; | 296 | static int num_force_kipmid; |
297 | 297 | ||
298 | static unsigned int kipmid_max_busy_us[SI_MAX_PARMS]; | ||
299 | static int num_max_busy_us; | ||
300 | |||
298 | static int unload_when_empty = 1; | 301 | static int unload_when_empty = 1; |
299 | 302 | ||
300 | static int try_smi_init(struct smi_info *smi); | 303 | static int try_smi_init(struct smi_info *smi); |
@@ -925,23 +928,77 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) | |||
925 | } | 928 | } |
926 | } | 929 | } |
927 | 930 | ||
931 | /* | ||
932 | * Use -1 in the nsec value of the busy waiting timespec to tell that | ||
933 | * we are spinning in kipmid looking for something and not delaying | ||
934 | * between checks | ||
935 | */ | ||
936 | static inline void ipmi_si_set_not_busy(struct timespec *ts) | ||
937 | { | ||
938 | ts->tv_nsec = -1; | ||
939 | } | ||
940 | static inline int ipmi_si_is_busy(struct timespec *ts) | ||
941 | { | ||
942 | return ts->tv_nsec != -1; | ||
943 | } | ||
944 | |||
945 | static int ipmi_thread_busy_wait(enum si_sm_result smi_result, | ||
946 | const struct smi_info *smi_info, | ||
947 | struct timespec *busy_until) | ||
948 | { | ||
949 | unsigned int max_busy_us = 0; | ||
950 | |||
951 | if (smi_info->intf_num < num_max_busy_us) | ||
952 | max_busy_us = kipmid_max_busy_us[smi_info->intf_num]; | ||
953 | if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY) | ||
954 | ipmi_si_set_not_busy(busy_until); | ||
955 | else if (!ipmi_si_is_busy(busy_until)) { | ||
956 | getnstimeofday(busy_until); | ||
957 | timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC); | ||
958 | } else { | ||
959 | struct timespec now; | ||
960 | getnstimeofday(&now); | ||
961 | if (unlikely(timespec_compare(&now, busy_until) > 0)) { | ||
962 | ipmi_si_set_not_busy(busy_until); | ||
963 | return 0; | ||
964 | } | ||
965 | } | ||
966 | return 1; | ||
967 | } | ||
968 | |||
969 | |||
970 | /* | ||
971 | * A busy-waiting loop for speeding up IPMI operation. | ||
972 | * | ||
973 | * Lousy hardware makes this hard. This is only enabled for systems | ||
974 | * that are not BT and do not have interrupts. It starts spinning | ||
975 | * when an operation is complete or until max_busy tells it to stop | ||
976 | * (if that is enabled). See the paragraph on kimid_max_busy_us in | ||
977 | * Documentation/IPMI.txt for details. | ||
978 | */ | ||
928 | static int ipmi_thread(void *data) | 979 | static int ipmi_thread(void *data) |
929 | { | 980 | { |
930 | struct smi_info *smi_info = data; | 981 | struct smi_info *smi_info = data; |
931 | unsigned long flags; | 982 | unsigned long flags; |
932 | enum si_sm_result smi_result; | 983 | enum si_sm_result smi_result; |
984 | struct timespec busy_until; | ||
933 | 985 | ||
986 | ipmi_si_set_not_busy(&busy_until); | ||
934 | set_user_nice(current, 19); | 987 | set_user_nice(current, 19); |
935 | while (!kthread_should_stop()) { | 988 | while (!kthread_should_stop()) { |
989 | int busy_wait; | ||
990 | |||
936 | spin_lock_irqsave(&(smi_info->si_lock), flags); | 991 | spin_lock_irqsave(&(smi_info->si_lock), flags); |
937 | smi_result = smi_event_handler(smi_info, 0); | 992 | smi_result = smi_event_handler(smi_info, 0); |
938 | spin_unlock_irqrestore(&(smi_info->si_lock), flags); | 993 | spin_unlock_irqrestore(&(smi_info->si_lock), flags); |
994 | busy_wait = ipmi_thread_busy_wait(smi_result, smi_info, | ||
995 | &busy_until); | ||
939 | if (smi_result == SI_SM_CALL_WITHOUT_DELAY) | 996 | if (smi_result == SI_SM_CALL_WITHOUT_DELAY) |
940 | ; /* do nothing */ | 997 | ; /* do nothing */ |
941 | else if (smi_result == SI_SM_CALL_WITH_DELAY) | 998 | else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) |
942 | schedule(); | 999 | schedule(); |
943 | else | 1000 | else |
944 | schedule_timeout_interruptible(1); | 1001 | schedule_timeout_interruptible(0); |
945 | } | 1002 | } |
946 | return 0; | 1003 | return 0; |
947 | } | 1004 | } |
@@ -1212,6 +1269,11 @@ module_param(unload_when_empty, int, 0); | |||
1212 | MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are" | 1269 | MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are" |
1213 | " specified or found, default is 1. Setting to 0" | 1270 | " specified or found, default is 1. Setting to 0" |
1214 | " is useful for hot add of devices using hotmod."); | 1271 | " is useful for hot add of devices using hotmod."); |
1272 | module_param_array(kipmid_max_busy_us, uint, &num_max_busy_us, 0644); | ||
1273 | MODULE_PARM_DESC(kipmid_max_busy_us, | ||
1274 | "Max time (in microseconds) to busy-wait for IPMI data before" | ||
1275 | " sleeping. 0 (default) means to wait forever. Set to 100-500" | ||
1276 | " if kipmid is using up a lot of CPU time."); | ||
1215 | 1277 | ||
1216 | 1278 | ||
1217 | static void std_irq_cleanup(struct smi_info *info) | 1279 | static void std_irq_cleanup(struct smi_info *info) |