cmpxchg broken in some situation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
}




[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux