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) |
