mirror of
https://github.com/schoebel/mars
synced 2025-03-31 07:46:57 +00:00
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:
parent
726bbe17fc
commit
dfe2dc5b1c
kernel
218
kernel/brick.c
218
kernel/brick.c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user