linux-mips
[Top] [All Lists]

cmpxchg broken in some situation

To: linux-mips@linux-mips.org
Subject: cmpxchg broken in some situation
From: Fuxin Zhang <fxzhang@ict.ac.cn>
Date: Sun, 30 Sep 2007 18:34:42 +0800
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
User-agent: IceDove 1.5.0.10 (X11/20070329)
hi, Today I run across a possible bug of cmpxchg implementation. When playing with DRM on our Fulong, the following function (drivers/char/drm/drm_lock.c) is not working correctly in 64BIT mips:
  cmpxchg failed to set *lock to new value. (return 0 with *lock unchanged)
It is probably due to type conversions between unisigned int and unsigned long. When I change cmpxchg to mycmpxchg(attached below), problem disappeared.
int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
{
       unsigned int old, new, prev;
       volatile unsigned int *lock = &lock_data->hw_lock->lock;

       spin_lock(&lock_data->spinlock);
       if (lock_data->kernel_waiters != 0) {
               drm_lock_transfer(lock_data, 0);
               lock_data->idle_has_lock = 1;
               spin_unlock(&lock_data->spinlock);
               return 1;
       }
       spin_unlock(&lock_data->spinlock);

       do {
               old = *lock;
               new = _DRM_LOCKING_CONTEXT(old);
               prev = cmpxchg(lock, old, new);
       } while (prev != old);

if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
               DRM_ERROR("%d freed heavyweight lock held by %d\n",
                         context, _DRM_LOCKING_CONTEXT(old));
               return 1;
       }
       wake_up_interruptible(&lock_data->lock_queue);
       return 0;
}

static inline unsigned int mycmpxchg(volatile int * m, unsigned int old,
       unsigned int new)  //unsigned long to unsigned int
{
       __u32 retval;

       __asm__ __volatile__(
" .set push \n" " .set noat \n" " .set mips3 \n" "1: ll %0, %2 # __mycmpxchg_u32 \n" " bne %0, %z3, 2f \n" " .set mips0 \n" " move $1, %z4 \n" " .set mips3 \n" " sc $1, %1 \n" " beqz $1, 3f \n" "2: \n" " .subsection 2 \n" "3: b 1b \n" " .previous \n" " .set pop \n"
                       : "=&r" (retval), "=R" (*m)
                       : "R" (*m), "Jr" (old), "Jr" (new)
                       : "memory");

       smp_llsc_mb();

       return retval;
}



<Prev in Thread] Current Thread [Next in Thread>
  • cmpxchg broken in some situation, Fuxin Zhang <=