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>

+46 -36
+46 -36
drivers/irqchip/irq-gic-v3-its.c
··· 494 494 } 495 495 } 496 496 497 - static void its_send_single_command(struct its_node *its, 498 - its_cmd_builder_t builder, 499 - struct its_cmd_desc *desc) 500 - { 501 - struct its_cmd_block *cmd, *sync_cmd, *next_cmd; 502 - struct its_collection *sync_col; 503 - unsigned long flags; 504 - 505 - raw_spin_lock_irqsave(&its->lock, flags); 506 - 507 - cmd = its_allocate_entry(its); 508 - if (!cmd) { /* We're soooooo screewed... */ 509 - pr_err_ratelimited("ITS can't allocate, dropping command\n"); 510 - raw_spin_unlock_irqrestore(&its->lock, flags); 511 - return; 512 - } 513 - sync_col = builder(cmd, desc); 514 - its_flush_cmd(its, cmd); 515 - 516 - if (sync_col) { 517 - sync_cmd = its_allocate_entry(its); 518 - if (!sync_cmd) { 519 - pr_err_ratelimited("ITS can't SYNC, skipping\n"); 520 - goto post; 521 - } 522 - its_encode_cmd(sync_cmd, GITS_CMD_SYNC); 523 - its_encode_target(sync_cmd, sync_col->target_address); 524 - its_fixup_cmd(sync_cmd); 525 - its_flush_cmd(its, sync_cmd); 526 - } 527 - 528 - post: 529 - next_cmd = its_post_commands(its); 530 - raw_spin_unlock_irqrestore(&its->lock, flags); 531 - 532 - its_wait_for_range_completion(its, cmd, next_cmd); 497 + /* Warning, macro hell follows */ 498 + #define BUILD_SINGLE_CMD_FUNC(name, buildtype, synctype, buildfn) \ 499 + void name(struct its_node *its, \ 500 + buildtype builder, \ 501 + struct its_cmd_desc *desc) \ 502 + { \ 503 + struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \ 504 + synctype *sync_obj; \ 505 + unsigned long flags; \ 506 + \ 507 + raw_spin_lock_irqsave(&its->lock, flags); \ 508 + \ 509 + cmd = its_allocate_entry(its); \ 510 + if (!cmd) { /* We're soooooo screewed... */ \ 511 + raw_spin_unlock_irqrestore(&its->lock, flags); \ 512 + return; \ 513 + } \ 514 + sync_obj = builder(cmd, desc); \ 515 + its_flush_cmd(its, cmd); \ 516 + \ 517 + if (sync_obj) { \ 518 + sync_cmd = its_allocate_entry(its); \ 519 + if (!sync_cmd) \ 520 + goto post; \ 521 + \ 522 + buildfn(sync_cmd, sync_obj); \ 523 + its_flush_cmd(its, sync_cmd); \ 524 + } \ 525 + \ 526 + post: \ 527 + next_cmd = its_post_commands(its); \ 528 + raw_spin_unlock_irqrestore(&its->lock, flags); \ 529 + \ 530 + its_wait_for_range_completion(its, cmd, next_cmd); \ 533 531 } 532 + 533 + static void its_build_sync_cmd(struct its_cmd_block *sync_cmd, 534 + struct its_collection *sync_col) 535 + { 536 + its_encode_cmd(sync_cmd, GITS_CMD_SYNC); 537 + its_encode_target(sync_cmd, sync_col->target_address); 538 + 539 + its_fixup_cmd(sync_cmd); 540 + } 541 + 542 + static BUILD_SINGLE_CMD_FUNC(its_send_single_command, its_cmd_builder_t, 543 + struct its_collection, its_build_sync_cmd) 534 544 535 545 static void its_send_inv(struct its_device *dev, u32 event_id) 536 546 {