mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6: sparc64: Get rid of indirect p1275 PROM call buffer. sparc64: Fill a missing delay slot. sparc64: Make lock backoff really a NOP on UP builds. sparc64: simple microoptimizations for atomic functions sparc64: Make rwsems 64-bit. sparc64: Really fix atomic64_t interface types.
This commit is contained in:
commit
1a7c55368c
@ -20,14 +20,14 @@
|
||||
#define atomic64_set(v, i) (((v)->counter) = i)
|
||||
|
||||
extern void atomic_add(int, atomic_t *);
|
||||
extern void atomic64_add(int, atomic64_t *);
|
||||
extern void atomic64_add(long, atomic64_t *);
|
||||
extern void atomic_sub(int, atomic_t *);
|
||||
extern void atomic64_sub(int, atomic64_t *);
|
||||
extern void atomic64_sub(long, atomic64_t *);
|
||||
|
||||
extern int atomic_add_ret(int, atomic_t *);
|
||||
extern long atomic64_add_ret(int, atomic64_t *);
|
||||
extern long atomic64_add_ret(long, atomic64_t *);
|
||||
extern int atomic_sub_ret(int, atomic_t *);
|
||||
extern long atomic64_sub_ret(int, atomic64_t *);
|
||||
extern long atomic64_sub_ret(long, atomic64_t *);
|
||||
|
||||
#define atomic_dec_return(v) atomic_sub_ret(1, v)
|
||||
#define atomic64_dec_return(v) atomic64_sub_ret(1, v)
|
||||
|
@ -8,6 +8,9 @@
|
||||
#define BACKOFF_SETUP(reg) \
|
||||
mov 1, reg
|
||||
|
||||
#define BACKOFF_LABEL(spin_label, continue_label) \
|
||||
spin_label
|
||||
|
||||
#define BACKOFF_SPIN(reg, tmp, label) \
|
||||
mov reg, tmp; \
|
||||
88: brnz,pt tmp, 88b; \
|
||||
@ -22,9 +25,11 @@
|
||||
#else
|
||||
|
||||
#define BACKOFF_SETUP(reg)
|
||||
#define BACKOFF_SPIN(reg, tmp, label) \
|
||||
ba,pt %xcc, label; \
|
||||
nop;
|
||||
|
||||
#define BACKOFF_LABEL(spin_label, continue_label) \
|
||||
continue_label
|
||||
|
||||
#define BACKOFF_SPIN(reg, tmp, label)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -185,9 +185,8 @@ extern int prom_getunumber(int syndrome_code,
|
||||
char *buf, int buflen);
|
||||
|
||||
/* Retain physical memory to the caller across soft resets. */
|
||||
extern unsigned long prom_retain(const char *name,
|
||||
unsigned long pa_low, unsigned long pa_high,
|
||||
long size, long align);
|
||||
extern int prom_retain(const char *name, unsigned long size,
|
||||
unsigned long align, unsigned long *paddr);
|
||||
|
||||
/* Load explicit I/D TLB entries into the calling processor. */
|
||||
extern long prom_itlb_load(unsigned long index,
|
||||
@ -287,26 +286,6 @@ extern void prom_sun4v_guest_soft_state(void);
|
||||
extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
|
||||
|
||||
/* Client interface level routines. */
|
||||
extern long p1275_cmd(const char *, long, ...);
|
||||
|
||||
#if 0
|
||||
#define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x))
|
||||
#else
|
||||
#define P1275_SIZE(x) x
|
||||
#endif
|
||||
|
||||
/* We support at most 16 input and 1 output argument */
|
||||
#define P1275_ARG_NUMBER 0
|
||||
#define P1275_ARG_IN_STRING 1
|
||||
#define P1275_ARG_OUT_BUF 2
|
||||
#define P1275_ARG_OUT_32B 3
|
||||
#define P1275_ARG_IN_FUNCTION 4
|
||||
#define P1275_ARG_IN_BUF 5
|
||||
#define P1275_ARG_IN_64B 6
|
||||
|
||||
#define P1275_IN(x) ((x) & 0xf)
|
||||
#define P1275_OUT(x) (((x) << 4) & 0xf0)
|
||||
#define P1275_INOUT(i,o) (P1275_IN(i)|P1275_OUT(o))
|
||||
#define P1275_ARG(n,x) ((x) << ((n)*3 + 8))
|
||||
extern void p1275_cmd_direct(unsigned long *);
|
||||
|
||||
#endif /* !(__SPARC64_OPLIB_H) */
|
||||
|
@ -1,12 +0,0 @@
|
||||
/* rwsem-const.h: RW semaphore counter constants. */
|
||||
#ifndef _SPARC64_RWSEM_CONST_H
|
||||
#define _SPARC64_RWSEM_CONST_H
|
||||
|
||||
#define RWSEM_UNLOCKED_VALUE 0x00000000
|
||||
#define RWSEM_ACTIVE_BIAS 0x00000001
|
||||
#define RWSEM_ACTIVE_MASK 0x0000ffff
|
||||
#define RWSEM_WAITING_BIAS (-0x00010000)
|
||||
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
|
||||
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
|
||||
|
||||
#endif /* _SPARC64_RWSEM_CONST_H */
|
@ -15,16 +15,21 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/rwsem-const.h>
|
||||
|
||||
struct rwsem_waiter;
|
||||
|
||||
struct rw_semaphore {
|
||||
signed int count;
|
||||
spinlock_t wait_lock;
|
||||
struct list_head wait_list;
|
||||
signed long count;
|
||||
#define RWSEM_UNLOCKED_VALUE 0x00000000L
|
||||
#define RWSEM_ACTIVE_BIAS 0x00000001L
|
||||
#define RWSEM_ACTIVE_MASK 0xffffffffL
|
||||
#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
|
||||
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
|
||||
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
|
||||
spinlock_t wait_lock;
|
||||
struct list_head wait_list;
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
struct lockdep_map dep_map;
|
||||
struct lockdep_map dep_map;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -41,6 +46,11 @@ struct rw_semaphore {
|
||||
#define DECLARE_RWSEM(name) \
|
||||
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
|
||||
|
||||
extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
|
||||
extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
|
||||
extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
|
||||
extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
|
||||
|
||||
extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
|
||||
struct lock_class_key *key);
|
||||
|
||||
@ -51,27 +61,103 @@ do { \
|
||||
__init_rwsem((sem), #sem, &__key); \
|
||||
} while (0)
|
||||
|
||||
extern void __down_read(struct rw_semaphore *sem);
|
||||
extern int __down_read_trylock(struct rw_semaphore *sem);
|
||||
extern void __down_write(struct rw_semaphore *sem);
|
||||
extern int __down_write_trylock(struct rw_semaphore *sem);
|
||||
extern void __up_read(struct rw_semaphore *sem);
|
||||
extern void __up_write(struct rw_semaphore *sem);
|
||||
extern void __downgrade_write(struct rw_semaphore *sem);
|
||||
/*
|
||||
* lock for reading
|
||||
*/
|
||||
static inline void __down_read(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(atomic64_inc_return((atomic64_t *)(&sem->count)) <= 0L))
|
||||
rwsem_down_read_failed(sem);
|
||||
}
|
||||
|
||||
static inline int __down_read_trylock(struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
while ((tmp = sem->count) >= 0L) {
|
||||
if (tmp == cmpxchg(&sem->count, tmp,
|
||||
tmp + RWSEM_ACTIVE_READ_BIAS)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* lock for writing
|
||||
*/
|
||||
static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
|
||||
{
|
||||
__down_write(sem);
|
||||
long tmp;
|
||||
|
||||
tmp = atomic64_add_return(RWSEM_ACTIVE_WRITE_BIAS,
|
||||
(atomic64_t *)(&sem->count));
|
||||
if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
|
||||
rwsem_down_write_failed(sem);
|
||||
}
|
||||
|
||||
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
|
||||
static inline void __down_write(struct rw_semaphore *sem)
|
||||
{
|
||||
return atomic_add_return(delta, (atomic_t *)(&sem->count));
|
||||
__down_write_nested(sem, 0);
|
||||
}
|
||||
|
||||
static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
|
||||
static inline int __down_write_trylock(struct rw_semaphore *sem)
|
||||
{
|
||||
atomic_add(delta, (atomic_t *)(&sem->count));
|
||||
long tmp;
|
||||
|
||||
tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
|
||||
RWSEM_ACTIVE_WRITE_BIAS);
|
||||
return tmp == RWSEM_UNLOCKED_VALUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* unlock after reading
|
||||
*/
|
||||
static inline void __up_read(struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = atomic64_dec_return((atomic64_t *)(&sem->count));
|
||||
if (unlikely(tmp < -1L && (tmp & RWSEM_ACTIVE_MASK) == 0L))
|
||||
rwsem_wake(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* unlock after writing
|
||||
*/
|
||||
static inline void __up_write(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(atomic64_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
|
||||
(atomic64_t *)(&sem->count)) < 0L))
|
||||
rwsem_wake(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* implement atomic add functionality
|
||||
*/
|
||||
static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
|
||||
{
|
||||
atomic64_add(delta, (atomic64_t *)(&sem->count));
|
||||
}
|
||||
|
||||
/*
|
||||
* downgrade write lock to read lock
|
||||
*/
|
||||
static inline void __downgrade_write(struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = atomic64_add_return(-RWSEM_WAITING_BIAS, (atomic64_t *)(&sem->count));
|
||||
if (tmp < 0L)
|
||||
rwsem_downgrade_wake(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* implement exchange and add functionality
|
||||
*/
|
||||
static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
|
||||
{
|
||||
return atomic64_add_return(delta, (atomic64_t *)(&sem->count));
|
||||
}
|
||||
|
||||
static inline int rwsem_is_locked(struct rw_semaphore *sem)
|
||||
|
@ -106,6 +106,7 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
|
||||
*/
|
||||
#define write_pic(__p) \
|
||||
__asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \
|
||||
" nop\n\t" \
|
||||
".align 64\n" \
|
||||
"99:wr %0, 0x0, %%pic\n\t" \
|
||||
"rd %%pic, %%g0" : : "r" (__p))
|
||||
|
@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
|
||||
lib-$(CONFIG_SPARC32) += copy_user.o locks.o
|
||||
lib-y += atomic_$(BITS).o
|
||||
lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
|
||||
lib-y += rwsem_$(BITS).o
|
||||
lib-$(CONFIG_SPARC32) += rwsem_32.o
|
||||
lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o
|
||||
|
||||
lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o
|
||||
|
@ -21,7 +21,7 @@ atomic_add: /* %o0 = increment, %o1 = atomic_ptr */
|
||||
add %g1, %o0, %g7
|
||||
cas [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 2f
|
||||
bne,pn %icc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
@ -36,7 +36,7 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
|
||||
sub %g1, %o0, %g7
|
||||
cas [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 2f
|
||||
bne,pn %icc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
@ -51,11 +51,10 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
|
||||
add %g1, %o0, %g7
|
||||
cas [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 2f
|
||||
add %g7, %o0, %g7
|
||||
sra %g7, 0, %o0
|
||||
bne,pn %icc, BACKOFF_LABEL(2f, 1b)
|
||||
add %g1, %o0, %g1
|
||||
retl
|
||||
nop
|
||||
sra %g1, 0, %o0
|
||||
2: BACKOFF_SPIN(%o2, %o3, 1b)
|
||||
.size atomic_add_ret, .-atomic_add_ret
|
||||
|
||||
@ -67,11 +66,10 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
|
||||
sub %g1, %o0, %g7
|
||||
cas [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 2f
|
||||
sub %g7, %o0, %g7
|
||||
sra %g7, 0, %o0
|
||||
bne,pn %icc, BACKOFF_LABEL(2f, 1b)
|
||||
sub %g1, %o0, %g1
|
||||
retl
|
||||
nop
|
||||
sra %g1, 0, %o0
|
||||
2: BACKOFF_SPIN(%o2, %o3, 1b)
|
||||
.size atomic_sub_ret, .-atomic_sub_ret
|
||||
|
||||
@ -83,7 +81,7 @@ atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */
|
||||
add %g1, %o0, %g7
|
||||
casx [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
@ -98,7 +96,7 @@ atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */
|
||||
sub %g1, %o0, %g7
|
||||
casx [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
@ -113,11 +111,10 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
|
||||
add %g1, %o0, %g7
|
||||
casx [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %xcc, 2f
|
||||
add %g7, %o0, %g7
|
||||
mov %g7, %o0
|
||||
retl
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
add %g1, %o0, %o0
|
||||
2: BACKOFF_SPIN(%o2, %o3, 1b)
|
||||
.size atomic64_add_ret, .-atomic64_add_ret
|
||||
|
||||
@ -129,10 +126,9 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
|
||||
sub %g1, %o0, %g7
|
||||
casx [%o1], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %xcc, 2f
|
||||
sub %g7, %o0, %g7
|
||||
mov %g7, %o0
|
||||
retl
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
sub %g1, %o0, %o0
|
||||
2: BACKOFF_SPIN(%o2, %o3, 1b)
|
||||
.size atomic64_sub_ret, .-atomic64_sub_ret
|
||||
|
@ -22,7 +22,7 @@ test_and_set_bit: /* %o0=nr, %o1=addr */
|
||||
or %g7, %o2, %g1
|
||||
casx [%o1], %g7, %g1
|
||||
cmp %g7, %g1
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
and %g7, %o2, %g2
|
||||
clr %o0
|
||||
movrne %g2, 1, %o0
|
||||
@ -45,7 +45,7 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */
|
||||
andn %g7, %o2, %g1
|
||||
casx [%o1], %g7, %g1
|
||||
cmp %g7, %g1
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
and %g7, %o2, %g2
|
||||
clr %o0
|
||||
movrne %g2, 1, %o0
|
||||
@ -68,7 +68,7 @@ test_and_change_bit: /* %o0=nr, %o1=addr */
|
||||
xor %g7, %o2, %g1
|
||||
casx [%o1], %g7, %g1
|
||||
cmp %g7, %g1
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
and %g7, %o2, %g2
|
||||
clr %o0
|
||||
movrne %g2, 1, %o0
|
||||
@ -91,7 +91,7 @@ set_bit: /* %o0=nr, %o1=addr */
|
||||
or %g7, %o2, %g1
|
||||
casx [%o1], %g7, %g1
|
||||
cmp %g7, %g1
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
@ -112,7 +112,7 @@ clear_bit: /* %o0=nr, %o1=addr */
|
||||
andn %g7, %o2, %g1
|
||||
casx [%o1], %g7, %g1
|
||||
cmp %g7, %g1
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
@ -133,7 +133,7 @@ change_bit: /* %o0=nr, %o1=addr */
|
||||
xor %g7, %o2, %g1
|
||||
casx [%o1], %g7, %g1
|
||||
cmp %g7, %g1
|
||||
bne,pn %xcc, 2f
|
||||
bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
@ -1,163 +0,0 @@
|
||||
/* rwsem.S: RW semaphore assembler.
|
||||
*
|
||||
* Written by David S. Miller (davem@redhat.com), 2001.
|
||||
* Derived from asm-i386/rwsem.h
|
||||
*/
|
||||
|
||||
#include <asm/rwsem-const.h>
|
||||
|
||||
.section .sched.text, "ax"
|
||||
|
||||
.globl __down_read
|
||||
__down_read:
|
||||
1: lduw [%o0], %g1
|
||||
add %g1, 1, %g7
|
||||
cas [%o0], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 1b
|
||||
add %g7, 1, %g7
|
||||
cmp %g7, 0
|
||||
bl,pn %icc, 3f
|
||||
nop
|
||||
2:
|
||||
retl
|
||||
nop
|
||||
3:
|
||||
save %sp, -192, %sp
|
||||
call rwsem_down_read_failed
|
||||
mov %i0, %o0
|
||||
ret
|
||||
restore
|
||||
.size __down_read, .-__down_read
|
||||
|
||||
.globl __down_read_trylock
|
||||
__down_read_trylock:
|
||||
1: lduw [%o0], %g1
|
||||
add %g1, 1, %g7
|
||||
cmp %g7, 0
|
||||
bl,pn %icc, 2f
|
||||
mov 0, %o1
|
||||
cas [%o0], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 1b
|
||||
mov 1, %o1
|
||||
2: retl
|
||||
mov %o1, %o0
|
||||
.size __down_read_trylock, .-__down_read_trylock
|
||||
|
||||
.globl __down_write
|
||||
__down_write:
|
||||
sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
|
||||
or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
|
||||
1:
|
||||
lduw [%o0], %g3
|
||||
add %g3, %g1, %g7
|
||||
cas [%o0], %g3, %g7
|
||||
cmp %g3, %g7
|
||||
bne,pn %icc, 1b
|
||||
cmp %g7, 0
|
||||
bne,pn %icc, 3f
|
||||
nop
|
||||
2: retl
|
||||
nop
|
||||
3:
|
||||
save %sp, -192, %sp
|
||||
call rwsem_down_write_failed
|
||||
mov %i0, %o0
|
||||
ret
|
||||
restore
|
||||
.size __down_write, .-__down_write
|
||||
|
||||
.globl __down_write_trylock
|
||||
__down_write_trylock:
|
||||
sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
|
||||
or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
|
||||
1:
|
||||
lduw [%o0], %g3
|
||||
cmp %g3, 0
|
||||
bne,pn %icc, 2f
|
||||
mov 0, %o1
|
||||
add %g3, %g1, %g7
|
||||
cas [%o0], %g3, %g7
|
||||
cmp %g3, %g7
|
||||
bne,pn %icc, 1b
|
||||
mov 1, %o1
|
||||
2: retl
|
||||
mov %o1, %o0
|
||||
.size __down_write_trylock, .-__down_write_trylock
|
||||
|
||||
.globl __up_read
|
||||
__up_read:
|
||||
1:
|
||||
lduw [%o0], %g1
|
||||
sub %g1, 1, %g7
|
||||
cas [%o0], %g1, %g7
|
||||
cmp %g1, %g7
|
||||
bne,pn %icc, 1b
|
||||
cmp %g7, 0
|
||||
bl,pn %icc, 3f
|
||||
nop
|
||||
2: retl
|
||||
nop
|
||||
3: sethi %hi(RWSEM_ACTIVE_MASK), %g1
|
||||
sub %g7, 1, %g7
|
||||
or %g1, %lo(RWSEM_ACTIVE_MASK), %g1
|
||||
andcc %g7, %g1, %g0
|
||||
bne,pn %icc, 2b
|
||||
nop
|
||||
save %sp, -192, %sp
|
||||
call rwsem_wake
|
||||
mov %i0, %o0
|
||||
ret
|
||||
restore
|
||||
.size __up_read, .-__up_read
|
||||
|
||||
.globl __up_write
|
||||
__up_write:
|
||||
sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
|
||||
or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
|
||||
1:
|
||||
lduw [%o0], %g3
|
||||
sub %g3, %g1, %g7
|
||||
cas [%o0], %g3, %g7
|
||||
cmp %g3, %g7
|
||||
bne,pn %icc, 1b
|
||||
sub %g7, %g1, %g7
|
||||
cmp %g7, 0
|
||||
bl,pn %icc, 3f
|
||||
nop
|
||||
2:
|
||||
retl
|
||||
nop
|
||||
3:
|
||||
save %sp, -192, %sp
|
||||
call rwsem_wake
|
||||
mov %i0, %o0
|
||||
ret
|
||||
restore
|
||||
.size __up_write, .-__up_write
|
||||
|
||||
.globl __downgrade_write
|
||||
__downgrade_write:
|
||||
sethi %hi(RWSEM_WAITING_BIAS), %g1
|
||||
or %g1, %lo(RWSEM_WAITING_BIAS), %g1
|
||||
1:
|
||||
lduw [%o0], %g3
|
||||
sub %g3, %g1, %g7
|
||||
cas [%o0], %g3, %g7
|
||||
cmp %g3, %g7
|
||||
bne,pn %icc, 1b
|
||||
sub %g7, %g1, %g7
|
||||
cmp %g7, 0
|
||||
bl,pn %icc, 3f
|
||||
nop
|
||||
2:
|
||||
retl
|
||||
nop
|
||||
3:
|
||||
save %sp, -192, %sp
|
||||
call rwsem_downgrade_wake
|
||||
mov %i0, %o0
|
||||
ret
|
||||
restore
|
||||
.size __downgrade_write, .-__downgrade_write
|
@ -9,18 +9,18 @@
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
.text
|
||||
.globl prom_cif_interface
|
||||
prom_cif_interface:
|
||||
sethi %hi(p1275buf), %o0
|
||||
or %o0, %lo(p1275buf), %o0
|
||||
ldx [%o0 + 0x010], %o1 ! prom_cif_stack
|
||||
save %o1, -192, %sp
|
||||
ldx [%i0 + 0x008], %l2 ! prom_cif_handler
|
||||
.globl prom_cif_direct
|
||||
prom_cif_direct:
|
||||
sethi %hi(p1275buf), %o1
|
||||
or %o1, %lo(p1275buf), %o1
|
||||
ldx [%o1 + 0x0010], %o2 ! prom_cif_stack
|
||||
save %o2, -192, %sp
|
||||
ldx [%i1 + 0x0008], %l2 ! prom_cif_handler
|
||||
mov %g4, %l0
|
||||
mov %g5, %l1
|
||||
mov %g6, %l3
|
||||
call %l2
|
||||
add %i0, 0x018, %o0 ! prom_args
|
||||
mov %i0, %o0 ! prom_args
|
||||
mov %l0, %g4
|
||||
mov %l1, %g5
|
||||
mov %l3, %g6
|
||||
|
@ -21,14 +21,22 @@ extern int prom_stdin, prom_stdout;
|
||||
inline int
|
||||
prom_nbgetchar(void)
|
||||
{
|
||||
unsigned long args[7];
|
||||
char inc;
|
||||
|
||||
if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)|
|
||||
P1275_INOUT(3,1),
|
||||
prom_stdin, &inc, P1275_SIZE(1)) == 1)
|
||||
args[0] = (unsigned long) "read";
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) prom_stdin;
|
||||
args[4] = (unsigned long) &inc;
|
||||
args[5] = 1;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
if (args[6] == 1)
|
||||
return inc;
|
||||
else
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Non blocking put character to console device, returns -1 if
|
||||
@ -37,12 +45,22 @@ prom_nbgetchar(void)
|
||||
inline int
|
||||
prom_nbputchar(char c)
|
||||
{
|
||||
unsigned long args[7];
|
||||
char outc;
|
||||
|
||||
outc = c;
|
||||
if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
|
||||
P1275_INOUT(3,1),
|
||||
prom_stdout, &outc, P1275_SIZE(1)) == 1)
|
||||
|
||||
args[0] = (unsigned long) "write";
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) prom_stdout;
|
||||
args[4] = (unsigned long) &outc;
|
||||
args[5] = 1;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
if (args[6] == 1)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
@ -67,7 +85,15 @@ prom_putchar(char c)
|
||||
void
|
||||
prom_puts(const char *s, int len)
|
||||
{
|
||||
p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
|
||||
P1275_INOUT(3,1),
|
||||
prom_stdout, s, P1275_SIZE(len));
|
||||
unsigned long args[7];
|
||||
|
||||
args[0] = (unsigned long) "write";
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) prom_stdout;
|
||||
args[4] = (unsigned long) s;
|
||||
args[5] = len;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
@ -18,16 +18,32 @@
|
||||
int
|
||||
prom_devopen(const char *dstr)
|
||||
{
|
||||
return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)|
|
||||
P1275_INOUT(1,1),
|
||||
dstr);
|
||||
unsigned long args[5];
|
||||
|
||||
args[0] = (unsigned long) "open";
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) dstr;
|
||||
args[4] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[4];
|
||||
}
|
||||
|
||||
/* Close the device described by device handle 'dhandle'. */
|
||||
int
|
||||
prom_devclose(int dhandle)
|
||||
{
|
||||
p1275_cmd ("close", P1275_INOUT(1,0), dhandle);
|
||||
unsigned long args[4];
|
||||
|
||||
args[0] = (unsigned long) "close";
|
||||
args[1] = 1;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned int) dhandle;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -37,5 +53,15 @@ prom_devclose(int dhandle)
|
||||
void
|
||||
prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
|
||||
{
|
||||
p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo);
|
||||
unsigned long args[7];
|
||||
|
||||
args[0] = (unsigned long) "seek";
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) dhandle;
|
||||
args[4] = seekhi;
|
||||
args[5] = seeklo;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
@ -20,10 +20,17 @@
|
||||
|
||||
int prom_service_exists(const char *service_name)
|
||||
{
|
||||
int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_INOUT(1, 1), service_name);
|
||||
unsigned long args[5];
|
||||
|
||||
if (err)
|
||||
args[0] = (unsigned long) "test";
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) service_name;
|
||||
args[4] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
if (args[4])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -31,30 +38,47 @@ int prom_service_exists(const char *service_name)
|
||||
void prom_sun4v_guest_soft_state(void)
|
||||
{
|
||||
const char *svc = "SUNW,soft-state-supported";
|
||||
unsigned long args[3];
|
||||
|
||||
if (!prom_service_exists(svc))
|
||||
return;
|
||||
p1275_cmd(svc, P1275_INOUT(0, 0));
|
||||
args[0] = (unsigned long) svc;
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
/* Reset and reboot the machine with the command 'bcommand'. */
|
||||
void prom_reboot(const char *bcommand)
|
||||
{
|
||||
unsigned long args[4];
|
||||
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_reboot(bcommand);
|
||||
#endif
|
||||
p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_INOUT(1, 0), bcommand);
|
||||
args[0] = (unsigned long) "boot";
|
||||
args[1] = 1;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned long) bcommand;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
/* Forth evaluate the expression contained in 'fstring'. */
|
||||
void prom_feval(const char *fstring)
|
||||
{
|
||||
unsigned long args[5];
|
||||
|
||||
if (!fstring || fstring[0] == 0)
|
||||
return;
|
||||
p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_INOUT(1, 1), fstring);
|
||||
args[0] = (unsigned long) "interpret";
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) fstring;
|
||||
args[4] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
EXPORT_SYMBOL(prom_feval);
|
||||
|
||||
@ -68,6 +92,7 @@ extern void smp_release(void);
|
||||
*/
|
||||
void prom_cmdline(void)
|
||||
{
|
||||
unsigned long args[3];
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
@ -76,7 +101,11 @@ void prom_cmdline(void)
|
||||
smp_capture();
|
||||
#endif
|
||||
|
||||
p1275_cmd("enter", P1275_INOUT(0, 0));
|
||||
args[0] = (unsigned long) "enter";
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
smp_release();
|
||||
@ -90,22 +119,32 @@ void prom_cmdline(void)
|
||||
*/
|
||||
void notrace prom_halt(void)
|
||||
{
|
||||
unsigned long args[3];
|
||||
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_power_off();
|
||||
#endif
|
||||
again:
|
||||
p1275_cmd("exit", P1275_INOUT(0, 0));
|
||||
args[0] = (unsigned long) "exit";
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
p1275_cmd_direct(args);
|
||||
goto again; /* PROM is out to get me -DaveM */
|
||||
}
|
||||
|
||||
void prom_halt_power_off(void)
|
||||
{
|
||||
unsigned long args[3];
|
||||
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled)
|
||||
ldom_power_off();
|
||||
#endif
|
||||
p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
|
||||
args[0] = (unsigned long) "SUNW,power-off";
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
/* if nothing else helps, we just halt */
|
||||
prom_halt();
|
||||
@ -114,10 +153,15 @@ void prom_halt_power_off(void)
|
||||
/* Set prom sync handler to call function 'funcp'. */
|
||||
void prom_setcallback(callback_func_t funcp)
|
||||
{
|
||||
unsigned long args[5];
|
||||
if (!funcp)
|
||||
return;
|
||||
p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
|
||||
P1275_INOUT(1, 1), funcp);
|
||||
args[0] = (unsigned long) "set-callback";
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) funcp;
|
||||
args[4] = (unsigned long) -1;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
|
||||
@ -173,57 +217,61 @@ static int prom_get_memory_ihandle(void)
|
||||
}
|
||||
|
||||
/* Load explicit I/D TLB entries. */
|
||||
static long tlb_load(const char *type, unsigned long index,
|
||||
unsigned long tte_data, unsigned long vaddr)
|
||||
{
|
||||
unsigned long args[9];
|
||||
|
||||
args[0] = (unsigned long) prom_callmethod_name;
|
||||
args[1] = 5;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) type;
|
||||
args[4] = (unsigned int) prom_get_mmu_ihandle();
|
||||
args[5] = vaddr;
|
||||
args[6] = tte_data;
|
||||
args[7] = index;
|
||||
args[8] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (long) args[8];
|
||||
}
|
||||
|
||||
long prom_itlb_load(unsigned long index,
|
||||
unsigned long tte_data,
|
||||
unsigned long vaddr)
|
||||
{
|
||||
return p1275_cmd(prom_callmethod_name,
|
||||
(P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_ARG(2, P1275_ARG_IN_64B) |
|
||||
P1275_ARG(3, P1275_ARG_IN_64B) |
|
||||
P1275_INOUT(5, 1)),
|
||||
"SUNW,itlb-load",
|
||||
prom_get_mmu_ihandle(),
|
||||
/* And then our actual args are pushed backwards. */
|
||||
vaddr,
|
||||
tte_data,
|
||||
index);
|
||||
return tlb_load("SUNW,itlb-load", index, tte_data, vaddr);
|
||||
}
|
||||
|
||||
long prom_dtlb_load(unsigned long index,
|
||||
unsigned long tte_data,
|
||||
unsigned long vaddr)
|
||||
{
|
||||
return p1275_cmd(prom_callmethod_name,
|
||||
(P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_ARG(2, P1275_ARG_IN_64B) |
|
||||
P1275_ARG(3, P1275_ARG_IN_64B) |
|
||||
P1275_INOUT(5, 1)),
|
||||
"SUNW,dtlb-load",
|
||||
prom_get_mmu_ihandle(),
|
||||
/* And then our actual args are pushed backwards. */
|
||||
vaddr,
|
||||
tte_data,
|
||||
index);
|
||||
return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr);
|
||||
}
|
||||
|
||||
int prom_map(int mode, unsigned long size,
|
||||
unsigned long vaddr, unsigned long paddr)
|
||||
{
|
||||
int ret = p1275_cmd(prom_callmethod_name,
|
||||
(P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_ARG(3, P1275_ARG_IN_64B) |
|
||||
P1275_ARG(4, P1275_ARG_IN_64B) |
|
||||
P1275_ARG(6, P1275_ARG_IN_64B) |
|
||||
P1275_INOUT(7, 1)),
|
||||
prom_map_name,
|
||||
prom_get_mmu_ihandle(),
|
||||
mode,
|
||||
size,
|
||||
vaddr,
|
||||
0,
|
||||
paddr);
|
||||
unsigned long args[11];
|
||||
int ret;
|
||||
|
||||
args[0] = (unsigned long) prom_callmethod_name;
|
||||
args[1] = 7;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) prom_map_name;
|
||||
args[4] = (unsigned int) prom_get_mmu_ihandle();
|
||||
args[5] = (unsigned int) mode;
|
||||
args[6] = size;
|
||||
args[7] = vaddr;
|
||||
args[8] = 0;
|
||||
args[9] = paddr;
|
||||
args[10] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
ret = (int) args[10];
|
||||
if (ret == 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
@ -231,40 +279,51 @@ int prom_map(int mode, unsigned long size,
|
||||
|
||||
void prom_unmap(unsigned long size, unsigned long vaddr)
|
||||
{
|
||||
p1275_cmd(prom_callmethod_name,
|
||||
(P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_ARG(2, P1275_ARG_IN_64B) |
|
||||
P1275_ARG(3, P1275_ARG_IN_64B) |
|
||||
P1275_INOUT(4, 0)),
|
||||
prom_unmap_name,
|
||||
prom_get_mmu_ihandle(),
|
||||
size,
|
||||
vaddr);
|
||||
unsigned long args[7];
|
||||
|
||||
args[0] = (unsigned long) prom_callmethod_name;
|
||||
args[1] = 4;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned long) prom_unmap_name;
|
||||
args[4] = (unsigned int) prom_get_mmu_ihandle();
|
||||
args[5] = size;
|
||||
args[6] = vaddr;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
/* Set aside physical memory which is not touched or modified
|
||||
* across soft resets.
|
||||
*/
|
||||
unsigned long prom_retain(const char *name,
|
||||
unsigned long pa_low, unsigned long pa_high,
|
||||
long size, long align)
|
||||
int prom_retain(const char *name, unsigned long size,
|
||||
unsigned long align, unsigned long *paddr)
|
||||
{
|
||||
/* XXX I don't think we return multiple values correctly.
|
||||
* XXX OBP supposedly returns pa_low/pa_high here, how does
|
||||
* XXX it work?
|
||||
*/
|
||||
unsigned long args[11];
|
||||
|
||||
/* If align is zero, the pa_low/pa_high args are passed,
|
||||
* else they are not.
|
||||
args[0] = (unsigned long) prom_callmethod_name;
|
||||
args[1] = 5;
|
||||
args[2] = 3;
|
||||
args[3] = (unsigned long) "SUNW,retain";
|
||||
args[4] = (unsigned int) prom_get_memory_ihandle();
|
||||
args[5] = align;
|
||||
args[6] = size;
|
||||
args[7] = (unsigned long) name;
|
||||
args[8] = (unsigned long) -1;
|
||||
args[9] = (unsigned long) -1;
|
||||
args[10] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
if (args[8])
|
||||
return (int) args[8];
|
||||
|
||||
/* Next we get "phys_high" then "phys_low". On 64-bit
|
||||
* the phys_high cell is don't care since the phys_low
|
||||
* cell has the full value.
|
||||
*/
|
||||
if (align == 0)
|
||||
return p1275_cmd("SUNW,retain",
|
||||
(P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
|
||||
name, pa_low, pa_high, size, align);
|
||||
else
|
||||
return p1275_cmd("SUNW,retain",
|
||||
(P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
|
||||
name, size, align);
|
||||
*paddr = args[10];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get "Unumber" string for the SIMM at the given
|
||||
@ -277,62 +336,129 @@ int prom_getunumber(int syndrome_code,
|
||||
unsigned long phys_addr,
|
||||
char *buf, int buflen)
|
||||
{
|
||||
return p1275_cmd(prom_callmethod_name,
|
||||
(P1275_ARG(0, P1275_ARG_IN_STRING) |
|
||||
P1275_ARG(3, P1275_ARG_OUT_BUF) |
|
||||
P1275_ARG(6, P1275_ARG_IN_64B) |
|
||||
P1275_INOUT(8, 2)),
|
||||
"SUNW,get-unumber", prom_get_memory_ihandle(),
|
||||
buflen, buf, P1275_SIZE(buflen),
|
||||
0, phys_addr, syndrome_code);
|
||||
unsigned long args[12];
|
||||
|
||||
args[0] = (unsigned long) prom_callmethod_name;
|
||||
args[1] = 7;
|
||||
args[2] = 2;
|
||||
args[3] = (unsigned long) "SUNW,get-unumber";
|
||||
args[4] = (unsigned int) prom_get_memory_ihandle();
|
||||
args[5] = buflen;
|
||||
args[6] = (unsigned long) buf;
|
||||
args[7] = 0;
|
||||
args[8] = phys_addr;
|
||||
args[9] = (unsigned int) syndrome_code;
|
||||
args[10] = (unsigned long) -1;
|
||||
args[11] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[10];
|
||||
}
|
||||
|
||||
/* Power management extensions. */
|
||||
void prom_sleepself(void)
|
||||
{
|
||||
p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
|
||||
unsigned long args[3];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,sleep-self";
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
int prom_sleepsystem(void)
|
||||
{
|
||||
return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
|
||||
unsigned long args[4];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,sleep-system";
|
||||
args[1] = 0;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) -1;
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[3];
|
||||
}
|
||||
|
||||
int prom_wakeupsystem(void)
|
||||
{
|
||||
return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
|
||||
unsigned long args[4];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,wakeup-system";
|
||||
args[1] = 0;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) -1;
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[3];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
|
||||
{
|
||||
p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg);
|
||||
unsigned long args[6];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,start-cpu";
|
||||
args[1] = 3;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned int) cpunode;
|
||||
args[4] = pc;
|
||||
args[5] = arg;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
|
||||
{
|
||||
p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0),
|
||||
cpuid, pc, arg);
|
||||
unsigned long args[6];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid";
|
||||
args[1] = 3;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned int) cpuid;
|
||||
args[4] = pc;
|
||||
args[5] = arg;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
void prom_stopcpu_cpuid(int cpuid)
|
||||
{
|
||||
p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
|
||||
cpuid);
|
||||
unsigned long args[4];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid";
|
||||
args[1] = 1;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned int) cpuid;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
void prom_stopself(void)
|
||||
{
|
||||
p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
|
||||
unsigned long args[3];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,stop-self";
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
void prom_idleself(void)
|
||||
{
|
||||
p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
|
||||
unsigned long args[3];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,idle-self";
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
|
||||
void prom_resumecpu(int cpunode)
|
||||
{
|
||||
p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
|
||||
unsigned long args[4];
|
||||
|
||||
args[0] = (unsigned long) "SUNW,resume-cpu";
|
||||
args[1] = 1;
|
||||
args[2] = 0;
|
||||
args[3] = (unsigned int) cpunode;
|
||||
p1275_cmd_direct(args);
|
||||
}
|
||||
#endif
|
||||
|
@ -22,13 +22,11 @@ struct {
|
||||
long prom_callback; /* 0x00 */
|
||||
void (*prom_cif_handler)(long *); /* 0x08 */
|
||||
unsigned long prom_cif_stack; /* 0x10 */
|
||||
unsigned long prom_args [23]; /* 0x18 */
|
||||
char prom_buffer [3000];
|
||||
} p1275buf;
|
||||
|
||||
extern void prom_world(int);
|
||||
|
||||
extern void prom_cif_interface(void);
|
||||
extern void prom_cif_direct(unsigned long *args);
|
||||
extern void prom_cif_callback(void);
|
||||
|
||||
/*
|
||||
@ -36,114 +34,20 @@ extern void prom_cif_callback(void);
|
||||
*/
|
||||
DEFINE_RAW_SPINLOCK(prom_entry_lock);
|
||||
|
||||
long p1275_cmd(const char *service, long fmt, ...)
|
||||
void p1275_cmd_direct(unsigned long *args)
|
||||
{
|
||||
char *p, *q;
|
||||
unsigned long flags;
|
||||
int nargs, nrets, i;
|
||||
va_list list;
|
||||
long attrs, x;
|
||||
|
||||
p = p1275buf.prom_buffer;
|
||||
|
||||
raw_local_save_flags(flags);
|
||||
raw_local_irq_restore(PIL_NMI);
|
||||
raw_spin_lock(&prom_entry_lock);
|
||||
|
||||
p1275buf.prom_args[0] = (unsigned long)p; /* service */
|
||||
strcpy (p, service);
|
||||
p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
|
||||
p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */
|
||||
p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */
|
||||
attrs = fmt >> 8;
|
||||
va_start(list, fmt);
|
||||
for (i = 0; i < nargs; i++, attrs >>= 3) {
|
||||
switch (attrs & 0x7) {
|
||||
case P1275_ARG_NUMBER:
|
||||
p1275buf.prom_args[i + 3] =
|
||||
(unsigned)va_arg(list, long);
|
||||
break;
|
||||
case P1275_ARG_IN_64B:
|
||||
p1275buf.prom_args[i + 3] =
|
||||
va_arg(list, unsigned long);
|
||||
break;
|
||||
case P1275_ARG_IN_STRING:
|
||||
strcpy (p, va_arg(list, char *));
|
||||
p1275buf.prom_args[i + 3] = (unsigned long)p;
|
||||
p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
|
||||
break;
|
||||
case P1275_ARG_OUT_BUF:
|
||||
(void) va_arg(list, char *);
|
||||
p1275buf.prom_args[i + 3] = (unsigned long)p;
|
||||
x = va_arg(list, long);
|
||||
i++; attrs >>= 3;
|
||||
p = (char *)(((long)(p + (int)x + 7)) & ~7);
|
||||
p1275buf.prom_args[i + 3] = x;
|
||||
break;
|
||||
case P1275_ARG_IN_BUF:
|
||||
q = va_arg(list, char *);
|
||||
p1275buf.prom_args[i + 3] = (unsigned long)p;
|
||||
x = va_arg(list, long);
|
||||
i++; attrs >>= 3;
|
||||
memcpy (p, q, (int)x);
|
||||
p = (char *)(((long)(p + (int)x + 7)) & ~7);
|
||||
p1275buf.prom_args[i + 3] = x;
|
||||
break;
|
||||
case P1275_ARG_OUT_32B:
|
||||
(void) va_arg(list, char *);
|
||||
p1275buf.prom_args[i + 3] = (unsigned long)p;
|
||||
p += 32;
|
||||
break;
|
||||
case P1275_ARG_IN_FUNCTION:
|
||||
p1275buf.prom_args[i + 3] =
|
||||
(unsigned long)prom_cif_callback;
|
||||
p1275buf.prom_callback = va_arg(list, long);
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(list);
|
||||
|
||||
prom_world(1);
|
||||
prom_cif_interface();
|
||||
prom_cif_direct(args);
|
||||
prom_world(0);
|
||||
|
||||
attrs = fmt >> 8;
|
||||
va_start(list, fmt);
|
||||
for (i = 0; i < nargs; i++, attrs >>= 3) {
|
||||
switch (attrs & 0x7) {
|
||||
case P1275_ARG_NUMBER:
|
||||
(void) va_arg(list, long);
|
||||
break;
|
||||
case P1275_ARG_IN_STRING:
|
||||
(void) va_arg(list, char *);
|
||||
break;
|
||||
case P1275_ARG_IN_FUNCTION:
|
||||
(void) va_arg(list, long);
|
||||
break;
|
||||
case P1275_ARG_IN_BUF:
|
||||
(void) va_arg(list, char *);
|
||||
(void) va_arg(list, long);
|
||||
i++; attrs >>= 3;
|
||||
break;
|
||||
case P1275_ARG_OUT_BUF:
|
||||
p = va_arg(list, char *);
|
||||
x = va_arg(list, long);
|
||||
memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x);
|
||||
i++; attrs >>= 3;
|
||||
break;
|
||||
case P1275_ARG_OUT_32B:
|
||||
p = va_arg(list, char *);
|
||||
memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(list);
|
||||
x = p1275buf.prom_args [nargs + 3];
|
||||
|
||||
raw_spin_unlock(&prom_entry_lock);
|
||||
raw_local_irq_restore(flags);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void prom_cif_init(void *cif_handler, void *cif_stack)
|
||||
|
@ -16,22 +16,39 @@
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/ldc.h>
|
||||
|
||||
static int prom_node_to_node(const char *type, int node)
|
||||
{
|
||||
unsigned long args[5];
|
||||
|
||||
args[0] = (unsigned long) type;
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) node;
|
||||
args[4] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[4];
|
||||
}
|
||||
|
||||
/* Return the child of node 'node' or zero if no this node has no
|
||||
* direct descendent.
|
||||
*/
|
||||
inline int __prom_getchild(int node)
|
||||
{
|
||||
return p1275_cmd ("child", P1275_INOUT(1, 1), node);
|
||||
return prom_node_to_node("child", node);
|
||||
}
|
||||
|
||||
inline int prom_getchild(int node)
|
||||
{
|
||||
int cnode;
|
||||
|
||||
if(node == -1) return 0;
|
||||
if (node == -1)
|
||||
return 0;
|
||||
cnode = __prom_getchild(node);
|
||||
if(cnode == -1) return 0;
|
||||
return (int)cnode;
|
||||
if (cnode == -1)
|
||||
return 0;
|
||||
return cnode;
|
||||
}
|
||||
EXPORT_SYMBOL(prom_getchild);
|
||||
|
||||
@ -39,10 +56,12 @@ inline int prom_getparent(int node)
|
||||
{
|
||||
int cnode;
|
||||
|
||||
if(node == -1) return 0;
|
||||
cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
|
||||
if(cnode == -1) return 0;
|
||||
return (int)cnode;
|
||||
if (node == -1)
|
||||
return 0;
|
||||
cnode = prom_node_to_node("parent", node);
|
||||
if (cnode == -1)
|
||||
return 0;
|
||||
return cnode;
|
||||
}
|
||||
|
||||
/* Return the next sibling of node 'node' or zero if no more siblings
|
||||
@ -50,7 +69,7 @@ inline int prom_getparent(int node)
|
||||
*/
|
||||
inline int __prom_getsibling(int node)
|
||||
{
|
||||
return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node);
|
||||
return prom_node_to_node(prom_peer_name, node);
|
||||
}
|
||||
|
||||
inline int prom_getsibling(int node)
|
||||
@ -72,11 +91,21 @@ EXPORT_SYMBOL(prom_getsibling);
|
||||
*/
|
||||
inline int prom_getproplen(int node, const char *prop)
|
||||
{
|
||||
if((!node) || (!prop)) return -1;
|
||||
return p1275_cmd ("getproplen",
|
||||
P1275_ARG(1,P1275_ARG_IN_STRING)|
|
||||
P1275_INOUT(2, 1),
|
||||
node, prop);
|
||||
unsigned long args[6];
|
||||
|
||||
if (!node || !prop)
|
||||
return -1;
|
||||
|
||||
args[0] = (unsigned long) "getproplen";
|
||||
args[1] = 2;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) node;
|
||||
args[4] = (unsigned long) prop;
|
||||
args[5] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[5];
|
||||
}
|
||||
EXPORT_SYMBOL(prom_getproplen);
|
||||
|
||||
@ -87,19 +116,25 @@ EXPORT_SYMBOL(prom_getproplen);
|
||||
inline int prom_getproperty(int node, const char *prop,
|
||||
char *buffer, int bufsize)
|
||||
{
|
||||
unsigned long args[8];
|
||||
int plen;
|
||||
|
||||
plen = prom_getproplen(node, prop);
|
||||
if ((plen > bufsize) || (plen == 0) || (plen == -1)) {
|
||||
if ((plen > bufsize) || (plen == 0) || (plen == -1))
|
||||
return -1;
|
||||
} else {
|
||||
/* Ok, things seem all right. */
|
||||
return p1275_cmd(prom_getprop_name,
|
||||
P1275_ARG(1,P1275_ARG_IN_STRING)|
|
||||
P1275_ARG(2,P1275_ARG_OUT_BUF)|
|
||||
P1275_INOUT(4, 1),
|
||||
node, prop, buffer, P1275_SIZE(plen));
|
||||
}
|
||||
|
||||
args[0] = (unsigned long) prom_getprop_name;
|
||||
args[1] = 4;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) node;
|
||||
args[4] = (unsigned long) prop;
|
||||
args[5] = (unsigned long) buffer;
|
||||
args[6] = bufsize;
|
||||
args[7] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[7];
|
||||
}
|
||||
EXPORT_SYMBOL(prom_getproperty);
|
||||
|
||||
@ -110,7 +145,7 @@ inline int prom_getint(int node, const char *prop)
|
||||
{
|
||||
int intprop;
|
||||
|
||||
if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
|
||||
if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
|
||||
return intprop;
|
||||
|
||||
return -1;
|
||||
@ -126,7 +161,8 @@ int prom_getintdefault(int node, const char *property, int deflt)
|
||||
int retval;
|
||||
|
||||
retval = prom_getint(node, property);
|
||||
if(retval == -1) return deflt;
|
||||
if (retval == -1)
|
||||
return deflt;
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -138,7 +174,8 @@ int prom_getbool(int node, const char *prop)
|
||||
int retval;
|
||||
|
||||
retval = prom_getproplen(node, prop);
|
||||
if(retval == -1) return 0;
|
||||
if (retval == -1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(prom_getbool);
|
||||
@ -152,7 +189,8 @@ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
|
||||
int len;
|
||||
|
||||
len = prom_getproperty(node, prop, user_buf, ubuf_size);
|
||||
if(len != -1) return;
|
||||
if (len != -1)
|
||||
return;
|
||||
user_buf[0] = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(prom_getstring);
|
||||
@ -164,7 +202,8 @@ int prom_nodematch(int node, const char *name)
|
||||
{
|
||||
char namebuf[128];
|
||||
prom_getproperty(node, "name", namebuf, sizeof(namebuf));
|
||||
if(strcmp(namebuf, name) == 0) return 1;
|
||||
if (strcmp(namebuf, name) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -190,16 +229,29 @@ int prom_searchsiblings(int node_start, const char *nodename)
|
||||
}
|
||||
EXPORT_SYMBOL(prom_searchsiblings);
|
||||
|
||||
static const char *prom_nextprop_name = "nextprop";
|
||||
|
||||
/* Return the first property type for node 'node'.
|
||||
* buffer should be at least 32B in length
|
||||
*/
|
||||
inline char *prom_firstprop(int node, char *buffer)
|
||||
{
|
||||
unsigned long args[7];
|
||||
|
||||
*buffer = 0;
|
||||
if(node == -1) return buffer;
|
||||
p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)|
|
||||
P1275_INOUT(3, 0),
|
||||
node, (char *) 0x0, buffer);
|
||||
if (node == -1)
|
||||
return buffer;
|
||||
|
||||
args[0] = (unsigned long) prom_nextprop_name;
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) node;
|
||||
args[4] = 0;
|
||||
args[5] = (unsigned long) buffer;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
EXPORT_SYMBOL(prom_firstprop);
|
||||
@ -210,9 +262,10 @@ EXPORT_SYMBOL(prom_firstprop);
|
||||
*/
|
||||
inline char *prom_nextprop(int node, const char *oprop, char *buffer)
|
||||
{
|
||||
unsigned long args[7];
|
||||
char buf[32];
|
||||
|
||||
if(node == -1) {
|
||||
if (node == -1) {
|
||||
*buffer = 0;
|
||||
return buffer;
|
||||
}
|
||||
@ -220,10 +273,17 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer)
|
||||
strcpy (buf, oprop);
|
||||
oprop = buf;
|
||||
}
|
||||
p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
|
||||
P1275_ARG(2,P1275_ARG_OUT_32B)|
|
||||
P1275_INOUT(3, 0),
|
||||
node, oprop, buffer);
|
||||
|
||||
args[0] = (unsigned long) prom_nextprop_name;
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) node;
|
||||
args[4] = (unsigned long) oprop;
|
||||
args[5] = (unsigned long) buffer;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
EXPORT_SYMBOL(prom_nextprop);
|
||||
@ -231,12 +291,19 @@ EXPORT_SYMBOL(prom_nextprop);
|
||||
int
|
||||
prom_finddevice(const char *name)
|
||||
{
|
||||
unsigned long args[5];
|
||||
|
||||
if (!name)
|
||||
return 0;
|
||||
return p1275_cmd(prom_finddev_name,
|
||||
P1275_ARG(0,P1275_ARG_IN_STRING)|
|
||||
P1275_INOUT(1, 1),
|
||||
name);
|
||||
args[0] = (unsigned long) "finddevice";
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned long) name;
|
||||
args[4] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[4];
|
||||
}
|
||||
EXPORT_SYMBOL(prom_finddevice);
|
||||
|
||||
@ -247,7 +314,7 @@ int prom_node_has_property(int node, const char *prop)
|
||||
*buf = 0;
|
||||
do {
|
||||
prom_nextprop(node, buf, buf);
|
||||
if(!strcmp(buf, prop))
|
||||
if (!strcmp(buf, prop))
|
||||
return 1;
|
||||
} while (*buf);
|
||||
return 0;
|
||||
@ -260,6 +327,8 @@ EXPORT_SYMBOL(prom_node_has_property);
|
||||
int
|
||||
prom_setprop(int node, const char *pname, char *value, int size)
|
||||
{
|
||||
unsigned long args[8];
|
||||
|
||||
if (size == 0)
|
||||
return 0;
|
||||
if ((pname == 0) || (value == 0))
|
||||
@ -271,19 +340,37 @@ prom_setprop(int node, const char *pname, char *value, int size)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
|
||||
P1275_ARG(2,P1275_ARG_IN_BUF)|
|
||||
P1275_INOUT(4, 1),
|
||||
node, pname, value, P1275_SIZE(size));
|
||||
args[0] = (unsigned long) "setprop";
|
||||
args[1] = 4;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) node;
|
||||
args[4] = (unsigned long) pname;
|
||||
args[5] = (unsigned long) value;
|
||||
args[6] = size;
|
||||
args[7] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[7];
|
||||
}
|
||||
EXPORT_SYMBOL(prom_setprop);
|
||||
|
||||
inline int prom_inst2pkg(int inst)
|
||||
{
|
||||
unsigned long args[5];
|
||||
int node;
|
||||
|
||||
node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst);
|
||||
if (node == -1) return 0;
|
||||
args[0] = (unsigned long) "instance-to-package";
|
||||
args[1] = 1;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) inst;
|
||||
args[4] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
node = (int) args[4];
|
||||
if (node == -1)
|
||||
return 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -296,17 +383,28 @@ prom_pathtoinode(const char *path)
|
||||
int node, inst;
|
||||
|
||||
inst = prom_devopen (path);
|
||||
if (inst == 0) return 0;
|
||||
node = prom_inst2pkg (inst);
|
||||
prom_devclose (inst);
|
||||
if (node == -1) return 0;
|
||||
if (inst == 0)
|
||||
return 0;
|
||||
node = prom_inst2pkg(inst);
|
||||
prom_devclose(inst);
|
||||
if (node == -1)
|
||||
return 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
int prom_ihandle2path(int handle, char *buffer, int bufsize)
|
||||
{
|
||||
return p1275_cmd("instance-to-path",
|
||||
P1275_ARG(1,P1275_ARG_OUT_BUF)|
|
||||
P1275_INOUT(3, 1),
|
||||
handle, buffer, P1275_SIZE(bufsize));
|
||||
unsigned long args[7];
|
||||
|
||||
args[0] = (unsigned long) "instance-to-path";
|
||||
args[1] = 3;
|
||||
args[2] = 1;
|
||||
args[3] = (unsigned int) handle;
|
||||
args[4] = (unsigned long) buffer;
|
||||
args[5] = bufsize;
|
||||
args[6] = (unsigned long) -1;
|
||||
|
||||
p1275_cmd_direct(args);
|
||||
|
||||
return (int) args[6];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user