infra: remove recursive button operations

All buttons should be switched step-by-step in future.
The previous patch should ensure that no harm can occur.
This commit is contained in:
Thomas Schoebel-Theuer 2013-05-09 11:43:28 +02:00 committed by Thomas Schoebel-Theuer
parent 726bbe17fc
commit dfe2dc5b1c
4 changed files with 39 additions and 250 deletions

View File

@ -377,47 +377,6 @@ int generic_brick_exit_full(struct generic_brick *brick)
}
EXPORT_SYMBOL_GPL(generic_brick_exit_full);
int generic_brick_exit_recursively(struct generic_brick *brick, bool destroy_inputs)
{
int final_status = 0;
LIST_HEAD(tmp);
list_add(&brick->tmp_head, &tmp);
while (!list_empty(&tmp)) {
int i;
int status;
int postpone = 0;
brick = container_of(tmp.next, struct generic_brick, tmp_head);
list_del_init(&brick->tmp_head);
for (i = 0; i < brick->type->max_outputs; i++) {
struct generic_output *output = brick->outputs[i];
if (output && output->nr_connected) {
postpone += output->nr_connected;
}
}
for (i = 0; i < brick->type->max_inputs; i++) {
struct generic_input *input = brick->inputs[i];
if (input && input->connect) {
struct generic_brick *other = input->connect->brick;
if (destroy_inputs) {
list_add(&other->tmp_head, &tmp);
postpone++;
} else {
}
}
}
if (postpone) {
list_add_tail(&brick->tmp_head, &tmp);
continue;
}
status = generic_brick_exit_full(brick);
if (status)
final_status = status;
}
return final_status;
}
EXPORT_SYMBOL_GPL(generic_brick_exit_recursively);
////////////////////////////////////////////////////////////////////////
// default implementations
@ -699,183 +658,6 @@ void set_button_wait(struct generic_brick *brick, bool val, bool force, int time
}
EXPORT_SYMBOL_GPL(set_button_wait);
/* Do it iteratively behind the scenes ;)
*/
int set_recursive_button(struct generic_brick *orig_brick, brick_switch_t mode, int timeout)
{
struct generic_brick **table = NULL;
int max = PAGE_SIZE / sizeof(void*) / 2;
int stack;
bool val = (mode == BR_ON_ONE || mode == BR_ON_ALL);
bool force = (mode != BR_OFF_ONE && mode != BR_OFF_ALL);
int pos;
int status;
#define PUSH_STACK(next) \
{ \
int j; \
bool found = false; \
/* eliminate duplicates */ \
for (j = 0; j < stack; j++) { \
if (table[j] == (next)) { \
BRICK_DBG(" double entry %d '%s' stack = %d\n", i, SAFE_STR((next)->brick_name), stack); \
found = true; \
break; \
} \
} \
if (!found) { \
BRICK_DBG(" push '%s' stack = %d\n", SAFE_STR((next)->brick_name), stack); \
table[stack++] = (next); \
if (unlikely(stack > max)) { \
BRICK_ERR("---- max = %d overflow, restarting...\n", max); \
goto restart; \
} \
} \
}
restart:
BRICK_DBG("-> orig_brick = '%s'\n", SAFE_STR(orig_brick->brick_name));
brick_mem_free(table);
max <<= 1;
table = brick_mem_alloc(max * sizeof(void*));
status = -ENOMEM;
if (unlikely(!table))
goto done;
stack = 0;
table[stack++] = orig_brick;
status = -EAGAIN;
for (pos = 0; pos < stack; pos++) {
struct generic_brick *brick = table[pos];
int max_inputs = 0;
int max_outputs = 0;
if (unlikely(!brick)) {
BRICK_ERR("intenal problem\n");
status = -EINVAL;
goto done;
}
if (likely(brick->type)) {
max_inputs = brick->type->max_inputs;
max_outputs = brick->type->max_outputs;
} else {
BRICK_WRN("uninitialized brick\n");
}
BRICK_DBG("--> pos = %d stack = %d brick = '%s' inputs = %d/%d outputs = %d/%d\n", pos, stack, SAFE_STR(brick->brick_name), brick->nr_inputs, max_inputs, brick->nr_outputs, max_outputs);
if (val) {
force = false;
if (unlikely(brick->power.force_off)) {
status = -EDEADLK;
goto done;
}
if (mode >= BR_ON_ALL) {
int i;
for (i = 0; i < max_inputs; i++) {
struct generic_input *input = brick->inputs[i];
struct generic_output *output;
struct generic_brick *next;
BRICK_DBG("---> i = %d\n", i);
//brick_msleep(1000);
if (!input)
continue;
output = input->connect;
if (!output)
continue;
next = output->brick;
if (!next)
continue;
PUSH_STACK(next);
}
}
} else if (mode >= BR_ON_ALL) {
int i;
for (i = 0; i < max_outputs; i++) {
struct generic_output *output = brick->outputs[i];
struct list_head *tmp;
BRICK_DBG("---> i = %d output = %p\n", i, output);
//brick_msleep(1000);
if (!output)
continue;
for (tmp = output->output_head.next; tmp && tmp != &output->output_head; tmp = tmp->next) {
struct generic_input *input = container_of(tmp, struct generic_input, input_head);
struct generic_brick *next = input->brick;
BRICK_DBG("----> tmp = %p input = %p next = %p\n", tmp, input, next);
//brick_msleep(1000);
if (unlikely(!next)) {
BRICK_ERR("oops, bad brick pointer\n");
status = -EINVAL;
goto done;
}
PUSH_STACK(next);
}
}
}
}
BRICK_DBG("-> stack = %d\n", stack);
while (stack > 0) {
struct generic_brick *brick = table[--stack];
if (unlikely(!brick)) {
BRICK_ERR("intenal problem\n");
status = -EINVAL;
goto done;
}
BRICK_DBG("--> switch '%s' stack = %d\n", SAFE_STR(brick->brick_name), stack);
set_button_wait(brick, val, force, timeout);
if (val ? !brick->power.led_on : !brick->power.led_off) {
BRICK_ERR("switching '%s' to %d: brick not ready (%s)\n", SAFE_STR(brick->brick_name), val, SAFE_STR(orig_brick->brick_name));
goto done;
}
if (force && !val && (mode == BR_FREE_ONE || mode == BR_FREE_ALL)) {
int max_inputs = 0;
int i;
if (likely(brick->type)) {
max_inputs = brick->type->max_inputs;
} else {
BRICK_WRN("uninitialized brick\n");
}
BRICK_DBG("---> freeing '%s'\n", SAFE_STR(brick->brick_name));
for (i = 0; i < max_inputs; i++) {
struct generic_input *input = brick->inputs[i];
BRICK_DBG("---> i = %d\n", i);
if (!input)
continue;
status = generic_disconnect(input);
if (status < 0) {
BRICK_ERR("disconnect %d failed, status = %d\n", i, status);
goto done;
}
}
if (brick->free) {
status = brick->free(brick);
if (status < 0) {
BRICK_ERR("freeing failed, status = %d\n", status);
goto done;
}
}
}
}
status = 0;
done:
BRICK_DBG("-> done status = %d\n", status);
brick_mem_free(table);
return status;
}
EXPORT_SYMBOL_GPL(set_recursive_button);
/////////////////////////////////////////////////////////////////
// meta stuff

View File

@ -586,8 +586,6 @@ typedef enum {
BR_FREE_ALL,
} brick_switch_t;
extern int set_recursive_button(struct generic_brick *brick, brick_switch_t mode, int timeout);
/////////////////////////////////////////////////////////////////////////
// threads

View File

@ -159,7 +159,6 @@ extern bool mars_check_inputs(struct mars_brick *brick);
extern bool mars_check_outputs(struct mars_brick *brick);
extern int mars_power_button(struct mars_brick *brick, bool val, bool force_off);
extern int mars_power_button_recursive(struct mars_brick *brick, bool val, bool force_off, int timeout);
/////////////////////////////////////////////////////////////////////////

View File

@ -472,29 +472,6 @@ int mars_power_button(struct mars_brick *brick, bool val, bool force_off)
}
EXPORT_SYMBOL_GPL(mars_power_button);
int mars_power_button_recursive(struct mars_brick *brick, bool val, bool force_off, int timeout)
{
int status = 0;
bool oldval = brick->power.button;
if (force_off && !val)
brick->power.force_off = true;
if (brick->power.force_off)
val = false;
if (val != oldval) {
brick_switch_t mode;
mode = (val ? BR_ON_ALL : (force_off ? BR_FREE_ALL : BR_OFF_ALL));
MARS_DBG("brick '%s' type '%s' power button %d -> %d (mode = %d)\n", brick->brick_path, brick->type->type_name, oldval, val, mode);
status = set_recursive_button((void*)brick, mode, timeout);
}
return status;
}
EXPORT_SYMBOL_GPL(mars_power_button_recursive);
/////////////////////////////////////////////////////////////////////
// strategy layer
@ -1229,7 +1206,44 @@ int mars_kill_brick(struct mars_brick *brick)
}
// start shutdown
status = set_recursive_button((void*)brick, BR_FREE_ONE, 0);
set_button_wait((void*)brick, false, true, 0);
if (likely(brick->power.led_off)) {
int max_inputs = 0;
int i;
if (likely(brick->type)) {
max_inputs = brick->type->max_inputs;
} else {
MARS_ERR("uninitialized brick '%s' '%s'\n", SAFE_STR(brick->brick_name), SAFE_STR(brick->brick_path));
}
MARS_DBG("---> freeing '%s' '%s'\n", SAFE_STR(brick->brick_name), SAFE_STR(brick->brick_path));
for (i = 0; i < max_inputs; i++) {
struct generic_input *input = (void*)brick->inputs[i];
if (!input)
continue;
status = generic_disconnect(input);
if (unlikely(status < 0)) {
MARS_ERR("brick '%s' '%s' disconnect %d failed, status = %d\n", SAFE_STR(brick->brick_name), SAFE_STR(brick->brick_path), i, status);
goto done;
}
}
if (likely(brick->free)) {
status = brick->free(brick);
if (unlikely(status < 0)) {
MARS_ERR("freeing '%s' '%s' failed, status = %d\n", SAFE_STR(brick->brick_name), SAFE_STR(brick->brick_path), status);
goto done;
}
} else {
MARS_ERR("brick '%s' '%s' has no destructor\n", SAFE_STR(brick->brick_name), SAFE_STR(brick->brick_path));
}
status = 0;
} else {
MARS_ERR("brick '%s' '%s' is not off\n", SAFE_STR(brick->brick_name), SAFE_STR(brick->brick_path));
status = -EIO;
}
done:
return status;
@ -1608,11 +1622,7 @@ do_switch:
}
// switch on/off (may fail silently, but responsibility is at the workers)
if (switch_state) {
status = mars_power_button_recursive((void*)brick, switch_state, false, 10 * HZ);
} else {
status = mars_power_button((void*)brick, switch_state, false);
}
status = mars_power_button((void*)brick, switch_state, false);
MARS_DBG("switch '%s' to %d status = %d\n", new_path, switch_state, status);
goto done;