• Jean-Philippe Brucker's avatar
    iommu/arm-smmu: Fix polling of command queue · bcfced15
    Jean-Philippe Brucker authored
    When the SMMUv3 driver attempts to send a command, it adds an entry to the
    command queue. This is a circular buffer, where both the producer and
    consumer have a wrap bit. When producer.index == consumer.index and
    producer.wrap == consumer.wrap, the list is empty. When producer.index ==
    consumer.index and producer.wrap != consumer.wrap, the list is full.
    
    If the list is full when the driver needs to add a command, it waits for
    the SMMU to consume one command, and advance the consumer pointer. The
    problem is that we currently rely on "X before Y" operation to know if
    entries have been consumed, which is a bit fiddly since it only makes
    sense when the distance between X and Y is less than or equal to the size
    of the queue. At the moment when the list is full, we use "Consumer before
    Producer + 1", which is out of range and returns a value opposite to what
    we expect: when the queue transitions to not full, we stay in the polling
    loop and time out, printing an error.
    
    Given that the actual bug was difficult to determine, simplify the polling
    logic by relying exclusively on queue_full and queue_empty, that don't
    have this range constraint. Polling the queue is now straightforward:
    
    * When we want to add a command and the list is full, wait until it isn't
      full and retry.
    * After adding a sync, wait for the list to be empty before returning.
    Suggested-by: default avatarWill Deacon <will.deacon@arm.com>
    Signed-off-by: default avatarJean-Philippe Brucker <jean-philippe.brucker@arm.com>
    Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
    bcfced15
arm-smmu-v3.c 68.4 KB