1 /* 2 * arch/s390/lib/spinlock.c 3 * Out of line spinlock code. 4 * 5 * Copyright (C) IBM Corp. 2004, 2006 6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 7 */ 8 9 #include <linux/types.h> 10 #include <linux/module.h> 11 #include <linux/spinlock.h> 12 #include <linux/init.h> 13 #include <asm/io.h> 14 15 int spin_retry = 1000; 16 17 /** 18 * spin_retry= parameter 19 */ 20 static int __init spin_retry_setup(char *str) 21 { 22 spin_retry = simple_strtoul(str, &str, 0); 23 return 1; 24 } 25 __setup("spin_retry=", spin_retry_setup); 26 27 static inline void _raw_yield(void) 28 { 29 if (MACHINE_HAS_DIAG44) 30 asm volatile("diag 0,0,0x44"); 31 } 32 33 static inline void _raw_yield_cpu(int cpu) 34 { 35 if (MACHINE_HAS_DIAG9C) 36 asm volatile("diag %0,0,0x9c" 37 : : "d" (__cpu_logical_map[cpu])); 38 else 39 _raw_yield(); 40 } 41 42 void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc) 43 { 44 int count = spin_retry; 45 unsigned int cpu = ~smp_processor_id(); 46 47 while (1) { 48 if (count-- <= 0) { 49 unsigned int owner = lp->owner_cpu; 50 if (owner != 0) 51 _raw_yield_cpu(~owner); 52 count = spin_retry; 53 } 54 if (__raw_spin_is_locked(lp)) 55 continue; 56 if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) { 57 lp->owner_pc = pc; 58 return; 59 } 60 } 61 } 62 EXPORT_SYMBOL(_raw_spin_lock_wait); 63 64 int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc) 65 { 66 unsigned int cpu = ~smp_processor_id(); 67 int count; 68 69 for (count = spin_retry; count > 0; count--) { 70 if (__raw_spin_is_locked(lp)) 71 continue; 72 if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) { 73 lp->owner_pc = pc; 74 return 1; 75 } 76 } 77 return 0; 78 } 79 EXPORT_SYMBOL(_raw_spin_trylock_retry); 80 81 void _raw_spin_relax(raw_spinlock_t *lock) 82 { 83 unsigned int cpu = lock->owner_cpu; 84 if (cpu != 0) 85 _raw_yield_cpu(~cpu); 86 } 87 EXPORT_SYMBOL(_raw_spin_relax); 88 89 void _raw_read_lock_wait(raw_rwlock_t *rw) 90 { 91 unsigned int old; 92 int count = spin_retry; 93 94 while (1) { 95 if (count-- <= 0) { 96 _raw_yield(); 97 count = spin_retry; 98 } 99 if (!__raw_read_can_lock(rw)) 100 continue; 101 old = rw->lock & 0x7fffffffU; 102 if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) 103 return; 104 } 105 } 106 EXPORT_SYMBOL(_raw_read_lock_wait); 107 108 int _raw_read_trylock_retry(raw_rwlock_t *rw) 109 { 110 unsigned int old; 111 int count = spin_retry; 112 113 while (count-- > 0) { 114 if (!__raw_read_can_lock(rw)) 115 continue; 116 old = rw->lock & 0x7fffffffU; 117 if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) 118 return 1; 119 } 120 return 0; 121 } 122 EXPORT_SYMBOL(_raw_read_trylock_retry); 123 124 void _raw_write_lock_wait(raw_rwlock_t *rw) 125 { 126 int count = spin_retry; 127 128 while (1) { 129 if (count-- <= 0) { 130 _raw_yield(); 131 count = spin_retry; 132 } 133 if (!__raw_write_can_lock(rw)) 134 continue; 135 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) 136 return; 137 } 138 } 139 EXPORT_SYMBOL(_raw_write_lock_wait); 140 141 int _raw_write_trylock_retry(raw_rwlock_t *rw) 142 { 143 int count = spin_retry; 144 145 while (count-- > 0) { 146 if (!__raw_write_can_lock(rw)) 147 continue; 148 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) 149 return 1; 150 } 151 return 0; 152 } 153 EXPORT_SYMBOL(_raw_write_trylock_retry); 154