irqchip/gic-v3-its: Macro-ize its_send_single_command
Most ITS commands do operate on a collection object, and require a SYNC command to be performed on that collection in order to guarantee the execution of the first command. With GICv4 ITS, another set of commands perform similar operations on a VPE object, and a VSYNC operations must be executed to guarantee their execution. Given the similarities (post a command, perform a synchronization operation on a sync object), it makes sense to reuse the same mechanism for both class of commands. Let's start with turning its_send_single_command into a huge macro that performs the bulk of the work, and a set of helpers that make this macro usable for the GICv3 ITS commands. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
Родитель
3dfa576bfb
Коммит
e4f9094b54
|
@ -494,44 +494,54 @@ static void its_wait_for_range_completion(struct its_node *its,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void its_send_single_command(struct its_node *its,
|
/* Warning, macro hell follows */
|
||||||
its_cmd_builder_t builder,
|
#define BUILD_SINGLE_CMD_FUNC(name, buildtype, synctype, buildfn) \
|
||||||
struct its_cmd_desc *desc)
|
void name(struct its_node *its, \
|
||||||
{
|
buildtype builder, \
|
||||||
struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
|
struct its_cmd_desc *desc) \
|
||||||
struct its_collection *sync_col;
|
{ \
|
||||||
unsigned long flags;
|
struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
|
||||||
|
synctype *sync_obj; \
|
||||||
raw_spin_lock_irqsave(&its->lock, flags);
|
unsigned long flags; \
|
||||||
|
\
|
||||||
cmd = its_allocate_entry(its);
|
raw_spin_lock_irqsave(&its->lock, flags); \
|
||||||
if (!cmd) { /* We're soooooo screewed... */
|
\
|
||||||
pr_err_ratelimited("ITS can't allocate, dropping command\n");
|
cmd = its_allocate_entry(its); \
|
||||||
raw_spin_unlock_irqrestore(&its->lock, flags);
|
if (!cmd) { /* We're soooooo screewed... */ \
|
||||||
return;
|
raw_spin_unlock_irqrestore(&its->lock, flags); \
|
||||||
}
|
return; \
|
||||||
sync_col = builder(cmd, desc);
|
} \
|
||||||
its_flush_cmd(its, cmd);
|
sync_obj = builder(cmd, desc); \
|
||||||
|
its_flush_cmd(its, cmd); \
|
||||||
if (sync_col) {
|
\
|
||||||
sync_cmd = its_allocate_entry(its);
|
if (sync_obj) { \
|
||||||
if (!sync_cmd) {
|
sync_cmd = its_allocate_entry(its); \
|
||||||
pr_err_ratelimited("ITS can't SYNC, skipping\n");
|
if (!sync_cmd) \
|
||||||
goto post;
|
goto post; \
|
||||||
}
|
\
|
||||||
its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
|
buildfn(sync_cmd, sync_obj); \
|
||||||
its_encode_target(sync_cmd, sync_col->target_address);
|
its_flush_cmd(its, sync_cmd); \
|
||||||
its_fixup_cmd(sync_cmd);
|
} \
|
||||||
its_flush_cmd(its, sync_cmd);
|
\
|
||||||
}
|
post: \
|
||||||
|
next_cmd = its_post_commands(its); \
|
||||||
post:
|
raw_spin_unlock_irqrestore(&its->lock, flags); \
|
||||||
next_cmd = its_post_commands(its);
|
\
|
||||||
raw_spin_unlock_irqrestore(&its->lock, flags);
|
its_wait_for_range_completion(its, cmd, next_cmd); \
|
||||||
|
|
||||||
its_wait_for_range_completion(its, cmd, next_cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void its_build_sync_cmd(struct its_cmd_block *sync_cmd,
|
||||||
|
struct its_collection *sync_col)
|
||||||
|
{
|
||||||
|
its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
|
||||||
|
its_encode_target(sync_cmd, sync_col->target_address);
|
||||||
|
|
||||||
|
its_fixup_cmd(sync_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BUILD_SINGLE_CMD_FUNC(its_send_single_command, its_cmd_builder_t,
|
||||||
|
struct its_collection, its_build_sync_cmd)
|
||||||
|
|
||||||
static void its_send_inv(struct its_device *dev, u32 event_id)
|
static void its_send_inv(struct its_device *dev, u32 event_id)
|
||||||
{
|
{
|
||||||
struct its_cmd_desc desc;
|
struct its_cmd_desc desc;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче