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:
Marc Zyngier 2016-12-19 17:56:32 +00:00
Родитель 3dfa576bfb
Коммит e4f9094b54
1 изменённых файлов: 46 добавлений и 36 удалений

Просмотреть файл

@ -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;