[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 1/9] AMD/IOMMU: redo awaiting of command completion
On 09/06/2021 10:26, Jan Beulich wrote: > The present abuse of the completion interrupt does not only stand in the > way of, down the road, using it for its actual purpose, but also > requires holding the IOMMU lock while waiting for command completion, > limiting parallelism and keeping interrupts off for non-negligible > periods of time. Have the IOMMU do an ordinary memory write instead of > signaling an otherwise disabled interrupt (by just updating a status > register bit). > > Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> > Reviewed-by: Paul Durrant <paul@xxxxxxx> While I agree with the direction of the patch, some of the details could do with improvement. > > --- a/xen/drivers/passthrough/amd/iommu_cmd.c > +++ b/xen/drivers/passthrough/amd/iommu_cmd.c > @@ -20,6 +20,9 @@ > #include "iommu.h" > #include "../ats.h" > > +#define CMD_COMPLETION_INIT 0 > +#define CMD_COMPLETION_DONE 1 > + > static void send_iommu_command(struct amd_iommu *iommu, > const uint32_t cmd[4]) > { > @@ -49,28 +52,31 @@ static void send_iommu_command(struct am > static void flush_command_buffer(struct amd_iommu *iommu, > unsigned int timeout_base) > { > + static DEFINE_PER_CPU(uint64_t, poll_slot); > + uint64_t *this_poll_slot = &this_cpu(poll_slot); > + paddr_t addr = virt_to_maddr(this_poll_slot); > uint32_t cmd[4]; > s_time_t start, timeout; > static unsigned int __read_mostly threshold = 1; > > - /* RW1C 'ComWaitInt' in status register */ > - writel(IOMMU_STATUS_COMP_WAIT_INT, > - iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET); > - > - /* send an empty COMPLETION_WAIT command to flush command buffer */ > - cmd[3] = cmd[2] = 0; > - set_field_in_reg_u32(IOMMU_CMD_COMPLETION_WAIT, 0, > + ACCESS_ONCE(*this_poll_slot) = CMD_COMPLETION_INIT; > + > + /* send a COMPLETION_WAIT command to flush command buffer */ > + cmd[0] = addr; > + set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, cmd[0], > + IOMMU_COMP_WAIT_S_FLAG_MASK, > + IOMMU_COMP_WAIT_S_FLAG_SHIFT, &cmd[0]); set_field_in_reg_u32() is a disaster of a function - both in terms of semantics, and code gen - and needs to be purged from the code. It is a shame we don't have a real struct for objects in the command buffer, but in lieu of that, this is just cmd[0] = addr | IOMMU_COMP_WAIT_S_FLAG_MASK; which is the direction that previous cleanup has gone. There are no current users of IOMMU_COMP_WAIT_S_FLAG_SHIFT, and ... > + cmd[1] = addr >> 32; > + set_field_in_reg_u32(IOMMU_CMD_COMPLETION_WAIT, cmd[1], > IOMMU_CMD_OPCODE_MASK, > IOMMU_CMD_OPCODE_SHIFT, &cmd[1]); > - set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0, > - IOMMU_COMP_WAIT_I_FLAG_MASK, > - IOMMU_COMP_WAIT_I_FLAG_SHIFT, &cmd[0]); ... this drops the final use of IOMMU_COMP_WAIT_I_FLAG_SHIFT, so both should be dropped. As for IOMMU_CMD_OPCODE_SHIFT, that can't be dropped yet, but it would still be better to use cmd[1] = (addr >> 32) | MASK_INSR(IOMMU_CMD_COMPLETION_WAIT, IOMMU_CMD_COMPLETION_WAIT); in the short term. ~Andrew P.S. an observation of cmd[1] means that AMD IOMMUs don't actually work for a physaddr width of >52, despite some support along these lines elsewhere in the spec.
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |