shithub: riscv

ref: fb96a050f8a9d5f23da3557ba89251ffb73889bf
dir: /sys/src/ape/lib/ap/mips/lock.c/

View raw version
#define _LOCK_EXTENSION
#include <stdlib.h>
#include <string.h>
#include "../plan9/sys9.h"
#include <lock.h>

enum
{
	Pagesize	= 4096,
	Semperpg	= Pagesize/(16*sizeof(unsigned int)),
	Lockaddr	= 0x60000000,

	POWER		= 0x320,
	MAGNUM		= 0x330,
	MAGNUMII	= 0x340,
	R4K		= 0x500,
};

static	int arch;
extern	int C_3ktas(int*);
extern	int C_4ktas(int*);
extern	int C_fcr0(void);

static void
lockinit(void)
{
	int n;

	if(arch != 0)
		return;	/* allow multiple calls */
	arch = C_fcr0();
	switch(arch) {
	case POWER:
		if(_SEGATTACH(0,  "lock", (void*)Lockaddr, Pagesize) == (void*)-1) {
			arch = MAGNUM;
			break;
		}
		memset((void*)Lockaddr, 0, Pagesize);
		break;
	case MAGNUM:
	case MAGNUMII:
	case R4K:
		break;
	default:
		arch = R4K;
		break;
	}
	
}

void
lock(Lock *lk)
{
	int *hwsem;
	int hash;

retry:
	switch(arch) {
	case 0:
		lockinit();
		goto retry;
	case MAGNUM:
	case MAGNUMII:
		while(C_3ktas(&lk->val))
			_SLEEP(0);
		return;
	case R4K:
		for(;;){
			while(lk->val)
				;
			if(C_4ktas(&lk->val) == 0)
				return;
		}
		break;
	case POWER:
		/* Use low order lock bits to generate hash */
		hash = ((int)lk/sizeof(int)) & (Semperpg-1);
		hwsem = (int*)Lockaddr+hash;

		for(;;) {
			if((*hwsem & 1) == 0) {
				if(lk->val)
					*hwsem = 0;
				else {
					lk->val = 1;
					*hwsem = 0;
					return;
				}
			}
			while(lk->val)
				;
		}
	}	
}

int
canlock(Lock *lk)
{
	int *hwsem;
	int hash;

retry:
	switch(arch) {
	case 0:
		lockinit();
		goto retry;
	case MAGNUM:
	case MAGNUMII:
		if(C_3ktas(&lk->val))
			return 0;
		return 1;
	case R4K:
		if(C_4ktas(&lk->val))
			return 0;
		return 1;
	case POWER:
		/* Use low order lock bits to generate hash */
		hash = ((int)lk/sizeof(int)) & (Semperpg-1);
		hwsem = (int*)Lockaddr+hash;

		if((*hwsem & 1) == 0) {
			if(lk->val)
				*hwsem = 0;
			else {
				lk->val = 1;
				*hwsem = 0;
				return 1;
			}
		}
		return 0;
	}
	return -1;	/* not reached */
}

void
unlock(Lock *lk)
{
	lk->val = 0;
}

int
tas(int *p)
{
	int *hwsem;
	int hash;

retry:
	switch(arch) {
	case 0:
		lockinit();
		goto retry;
	case MAGNUM:
	case MAGNUMII:
		return C_3ktas(p);
	case R4K:
		return C_4ktas(p);
	case POWER:
		/* Use low order lock bits to generate hash */
		hash = ((int)p/sizeof(int)) & (Semperpg-1);
		hwsem = (int*)Lockaddr+hash;

		if((*hwsem & 1) == 0) {
			if(*p)
				*hwsem = 0;
			else {
				*p = 1;
				*hwsem = 0;
				return 0;
			}
		}
		return 1;
	}
	return -1;	/* not reached */
}