1/*
2 *	SMP locks primitives for building ix86 locks
3 *	(not yet used).
4 *
5 *		Alan Cox, alan@cymru.net, 1995
6 */
7
8/*
9 *	This would be much easier but far less clear and easy
10 *	to borrow for other processors if it was just assembler.
11 */
12
13extern __inline__ void prim_spin_lock(struct spinlock *sp)
14{
15	int processor=smp_processor_id();
16
17	/*
18	 *	Grab the lock bit
19	 */
20
21	while(lock_set_bit(0,&sp->lock))
22	{
23		/*
24		 *	Failed, but that's cos we own it!
25		 */
26
27		if(sp->cpu==processor)
28		{
29			sp->users++;
30			return 0;
31		}
32		/*
33		 *	Spin in the cache S state if possible
34		 */
35		while(sp->lock)
36		{
37			/*
38			 *	Wait for any invalidates to go off
39			 */
40
41			if(smp_invalidate_needed&(1<<processor))
42				while(lock_clear_bit(processor,&smp_invalidate_needed))
43					local_flush_tlb();
44			sp->spins++;
45		}
46		/*
47		 *	Someone wrote the line, we go 'I' and get
48		 *	the cache entry. Now try to regrab
49		 */
50	}
51	sp->users++;sp->cpu=processor;
52	return 1;
53}
54
55/*
56 *	Release a spin lock
57 */
58
59extern __inline__ int prim_spin_unlock(struct spinlock *sp)
60{
61	/* This is safe. The decrement is still guarded by the lock. A multilock would
62	   not be safe this way */
63	if(!--sp->users)
64	{
65		lock_clear_bit(0,&sp->lock);sp->cpu= NO_PROC_ID;
66		return 1;
67	}
68	return 0;
69}
70
71
72/*
73 *	Non blocking lock grab
74 */
75
76extern __inline__ int prim_spin_lock_nb(struct spinlock *sp)
77{
78	if(lock_set_bit(0,&sp->lock))
79		return 0;		/* Locked already */
80	sp->users++;
81	return 1;			/* We got the lock */
82}
83
84
85/*
86 *	These wrap the locking primitives up for usage
87 */
88
89extern __inline__ void spinlock(struct spinlock *sp)
90{
91	if(sp->priority<current->lock_order)
92		panic("lock order violation: %s (%d)\n", sp->name, current->lock_order);
93	if(prim_spin_lock(sp))
94	{
95		/*
96		 *	We got a new lock. Update the priority chain
97		 */
98		sp->oldpri=current->lock_order;
99		current->lock_order=sp->priority;
100	}
101}
102
103extern __inline__ void spinunlock(struct spinlock *sp)
104{
105	if(current->lock_order!=sp->priority)
106		panic("lock release order violation %s (%d)\n", sp->name, current->lock_order);
107	if(prim_spin_unlock(sp))
108	{
109		/*
110		 *	Update the debugging lock priority chain. We dumped
111		 *	our last right to the lock.
112		 */
113		current->lock_order=sp->oldpri;
114	}
115}
116
117extern __inline__ void spintestlock(struct spinlock *sp)
118{
119	/*
120	 *	We do no sanity checks, it's legal to optimistically
121	 *	get a lower lock.
122	 */
123	prim_spin_lock_nb(sp);
124}
125
126extern __inline__ void spintestunlock(struct spinlock *sp)
127{
128	/*
129	 *	A testlock doesn't update the lock chain so we
130	 *	must not update it on free
131	 */
132	prim_spin_unlock(sp);
133}
134