summaryrefslogtreecommitdiff
path: root/arch/arch-ppc.h
blob: 804d596aecc632cb27f547c90a5b2b997ef79b42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#ifndef ARCH_PPC_H
#define ARCH_PPC_H

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

#define FIO_ARCH	(arch_ppc)

#define nop	do { } while (0)

#ifdef __powerpc64__
#define read_barrier()	__asm__ __volatile__ ("lwsync" : : : "memory")
#else
#define read_barrier()	__asm__ __volatile__ ("sync" : : : "memory")
#endif

#define write_barrier()	__asm__ __volatile__ ("sync" : : : "memory")

#ifdef __powerpc64__
#define PPC_CNTLZL "cntlzd"
#else
#define PPC_CNTLZL "cntlzw"
#endif

static inline int __ilog2(unsigned long bitmask)
{
	int lz;

	asm (PPC_CNTLZL " %0,%1" : "=r" (lz) : "r" (bitmask));
	return BITS_PER_LONG - 1 - lz;
}

static inline int arch_ffz(unsigned long bitmask)
{
	if ((bitmask = ~bitmask) == 0)
		return BITS_PER_LONG;
	return  __ilog2(bitmask & -bitmask);
}

static inline unsigned int mfspr(unsigned int reg)
{
	unsigned int val;

	asm volatile("mfspr %0,%1": "=r" (val) : "K" (reg));
	return val;
}

#define SPRN_TBRL  0x10C /* Time Base Register Lower */
#define SPRN_TBRU  0x10D /* Time Base Register Upper */
#define SPRN_ATBL  0x20E /* Alternate Time Base Lower */
#define SPRN_ATBU  0x20F /* Alternate Time Base Upper */

#ifdef __powerpc64__
static inline unsigned long long get_cpu_clock(void)
{
	unsigned long long rval;

	asm volatile(
		"90:	mfspr %0, %1;\n"
		"	cmpwi %0,0;\n"
		"	beq-  90b;\n"
	: "=r" (rval)
	: "i" (SPRN_TBRL)
	: "cr0");

	return rval;
}
#else
static inline unsigned long long get_cpu_clock(void)
{
	unsigned int tbl, tbu0, tbu1;
	unsigned long long ret;

	do {
		if (arch_flags & ARCH_FLAG_1) {
			tbu0 = mfspr(SPRN_ATBU);
			tbl = mfspr(SPRN_ATBL);
			tbu1 = mfspr(SPRN_ATBU);
		} else {
			tbu0 = mfspr(SPRN_TBRU);
			tbl = mfspr(SPRN_TBRL);
			tbu1 = mfspr(SPRN_TBRU);
		}
	} while (tbu0 != tbu1);

	ret = (((unsigned long long)tbu0) << 32) | tbl;
	return ret;
}
#endif

#if 0
static void atb_child(void)
{
	arch_flags |= ARCH_FLAG_1;
	get_cpu_clock();
	_exit(0);
}

static void atb_clocktest(void)
{
	pid_t pid;

	pid = fork();
	if (!pid)
		atb_child();
	else if (pid != -1) {
		int status;

		pid = wait(&status);
		if (pid == -1 || !WIFEXITED(status))
			arch_flags &= ~ARCH_FLAG_1;
		else
			arch_flags |= ARCH_FLAG_1;
	}
}
#endif

#define ARCH_HAVE_INIT
extern bool tsc_reliable;

static inline int arch_init(char *envp[])
{
#if 0
	tsc_reliable = true;
	atb_clocktest();
#endif
	return 0;
}

#define ARCH_HAVE_FFZ

/*
 * We don't have it on all platforms, lets comment this out until we
 * can handle it more intelligently.
 *
 * #define ARCH_HAVE_CPU_CLOCK
 */

/*
 * Let's have it defined for ppc64
 */

#ifdef __powerpc64__
#define ARCH_HAVE_CPU_CLOCK
#endif

#endif