testop(test_and_clear_bit, bic)
testop(test_and_set_bit, orr)
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+ bool timeout, unsigned int max_try)
+{
+ unsigned long res, tmp;
+
+ prefetchw((const uint16_t *)p);
+
+ do
+ {
+ asm volatile ("// int_clear_mask16\n"
+ " ldrexh %2, %1\n"
+ " bic %2, %2, %3\n"
+ " strexh %0, %2, %1\n"
+ : "=&r" (res), "+Qo" (*p), "=&r" (tmp)
+ : "r" (mask));
+
+ if ( !res )
+ break;
+ } while ( !timeout || ((--max_try) > 0) );
+
+ return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+ if ( !int_clear_mask16(mask, p, false, 0) )
+ ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+ unsigned int max_try)
+{
+ return int_clear_mask16(mask, p, true, max_try);
+}
+
/*
* Local variables:
* mode: C
testop(test_and_clear_bit, bic)
testop(test_and_set_bit, orr)
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+ bool timeout, unsigned int max_try)
+{
+ unsigned long res, tmp;
+
+ do
+ {
+ asm volatile ("// int_clear_mask16\n"
+ " ldxrh %w2, %1\n"
+ " bic %w2, %w2, %w3\n"
+ " stxrh %w0, %w2, %1\n"
+ : "=&r" (res), "+Q" (*p), "=&r" (tmp)
+ : "r" (mask));
+
+ if ( !res )
+ break;
+ } while ( !timeout || ((--max_try) > 0) );
+
+ return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+ if ( !int_clear_mask16(mask, p, false, 0) )
+ ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+ unsigned int max_try)
+{
+ return int_clear_mask16(mask, p, true, max_try);
+}
+
/*
* Local variables:
* mode: C
void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
{
- /*
- * Note that this cannot be clear_bit(), as the access must be
- * confined to the specified 2 bytes.
- */
- uint16_t mask = ~(1 << nr), old;
-
- do {
- old = *addr;
- } while (guest_cmpxchg(d, addr, old, old & mask) != old);
+ guest_clear_mask16(d, BIT(nr), addr);
}
void gnttab_mark_dirty(struct domain *d, unsigned long l)
int test_and_clear_bit(int nr, volatile void *p);
int test_and_change_bit(int nr, volatile void *p);
+void clear_mask16(uint16_t mask, volatile void *p);
+
/*
* The helpers below may fail to update the memory if the action takes
* too long.
int *oldbit, unsigned int max_try);
bool test_and_change_bit_timeout(int nr, volatile void *p,
int *oldbit, unsigned int max_try);
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+ unsigned int max_try);
/**
* __test_and_set_bit - Set a bit and return its old value
#undef guest_testop
+static inline void guest_clear_mask16(struct domain *d, uint16_t mask,
+ volatile uint16_t *p)
+{
+ perfc_incr(atomics_guest);
+
+ if ( clear_mask16_timeout(mask, p, this_cpu(guest_safe_atomic_max)) )
+ return;
+
+ domain_pause_nosync(d);
+ clear_mask16(mask, p);
+ domain_unpause(d);
+}
+
static inline unsigned long __guest_cmpxchg(struct domain *d,
volatile void *ptr,
unsigned long old,