mirror of
https://github.com/schoebel/mars
synced 2025-04-29 14:48:08 +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
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);
|
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
|
// 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);
|
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
|
// meta stuff
|
||||||
|
@ -586,8 +586,6 @@ typedef enum {
|
|||||||
BR_FREE_ALL,
|
BR_FREE_ALL,
|
||||||
} brick_switch_t;
|
} brick_switch_t;
|
||||||
|
|
||||||
extern int set_recursive_button(struct generic_brick *brick, brick_switch_t mode, int timeout);
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// threads
|
// threads
|
||||||
|
@ -159,7 +159,6 @@ extern bool mars_check_inputs(struct mars_brick *brick);
|
|||||||
extern bool mars_check_outputs(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(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);
|
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
|
// strategy layer
|
||||||
@ -1229,7 +1206,44 @@ int mars_kill_brick(struct mars_brick *brick)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start shutdown
|
// 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:
|
done:
|
||||||
return status;
|
return status;
|
||||||
@ -1608,11 +1622,7 @@ do_switch:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// switch on/off (may fail silently, but responsibility is at the workers)
|
// 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);
|
MARS_DBG("switch '%s' to %d status = %d\n", new_path, switch_state, status);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user