Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Smp timebase synchronization for ppc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <asm/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #define NUM_ITER		300
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	kExit=0, kSetAndTest, kTest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) static struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	volatile u64		tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	volatile u64		mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	volatile int		cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	volatile int		handshake;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	int			filler[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	volatile int		ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	int			filler2[7];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	volatile int		race_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) } *tbsync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static volatile int		running;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) static void enter_contest(u64 mark, long add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	while (get_tb() < mark)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 		tbsync->race_result = add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) void smp_generic_take_timebase(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	int cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	u64 tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	while (!running)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		tbsync->ack = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		while (!tbsync->handshake)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 			barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 		cmd = tbsync->cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		tb = tbsync->tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		tbsync->ack = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 		if (cmd == kExit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		while (tbsync->handshake)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 			barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		if (cmd == kSetAndTest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 			set_tb(tb >> 32, tb & 0xfffffffful);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		enter_contest(tbsync->mark, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static int start_contest(int cmd, long offset, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	int i, score=0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	u64 tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	u64 mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	tbsync->cmd = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	local_irq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	for (i = -3; i < num; ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		tb = get_tb() + 400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		tbsync->tb = tb + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		tbsync->mark = mark = tb + 400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		tbsync->handshake = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		while (tbsync->ack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 			barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 		while (get_tb() <= tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 			barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		tbsync->handshake = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		enter_contest(mark, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		while (!tbsync->ack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 			barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		if (i++ > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 			score += tbsync->race_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	local_irq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	return score;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) void smp_generic_give_timebase(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	int i, score, score2, old, min=0, max=5000, offset=1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	pr_debug("Software timebase sync\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	/* if this fails then this kernel won't work anyway... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	tbsync = kzalloc( sizeof(*tbsync), GFP_KERNEL );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	running = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	while (!tbsync->ack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	pr_debug("Got ack\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	/* binary search */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	for (old = -1; old != offset ; offset = (min+max) / 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		score = start_contest(kSetAndTest, offset, NUM_ITER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		pr_debug("score %d, offset %d\n", score, offset );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		if( score > 0 )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			max = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 			min = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		old = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	score = start_contest(kSetAndTest, min, NUM_ITER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	score2 = start_contest(kSetAndTest, max, NUM_ITER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	pr_debug("Min %d (score %d), Max %d (score %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		 min, score, max, score2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	score = abs(score);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	score2 = abs(score2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	offset = (score < score2) ? min : max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	/* guard against inaccurate mttb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	for (i = 0; i < 10; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 		start_contest(kSetAndTest, offset, NUM_ITER/10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		if ((score2 = start_contest(kTest, offset, NUM_ITER)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 			score2 = -score2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 		if (score2 <= score || score2 < 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	pr_debug("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	/* exiting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	tbsync->cmd = kExit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	tbsync->handshake = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	while (tbsync->ack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	tbsync->handshake = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	kfree(tbsync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	tbsync = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	running = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }