1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *	Implement 'Simple Boot Flag Specification 2.0'
4  */
5 #include <linux/types.h>
6 #include <linux/kernel.h>
7 #include <linux/init.h>
8 #include <linux/string.h>
9 #include <linux/spinlock.h>
10 #include <linux/acpi.h>
11 #include <linux/bitops.h>
12 #include <asm/io.h>
13 
14 #include <linux/mc146818rtc.h>
15 
16 #define SBF_RESERVED (0x78)
17 #define SBF_PNPOS    (1<<0)
18 #define SBF_BOOTING  (1<<1)
19 #define SBF_DIAG     (1<<2)
20 #define SBF_PARITY   (1<<7)
21 
22 int sbf_port __initdata = -1;	/* set via acpi_boot_init() */
23 
sbf_write(u8 v)24 static void __init sbf_write(u8 v)
25 {
26 	unsigned long flags;
27 
28 	if (sbf_port != -1) {
29 		if (!parity8(v))
30 			v ^= SBF_PARITY;
31 
32 		printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n",
33 			sbf_port, v);
34 
35 		spin_lock_irqsave(&rtc_lock, flags);
36 		CMOS_WRITE(v, sbf_port);
37 		spin_unlock_irqrestore(&rtc_lock, flags);
38 	}
39 }
40 
sbf_read(void)41 static u8 __init sbf_read(void)
42 {
43 	unsigned long flags;
44 	u8 v;
45 
46 	if (sbf_port == -1)
47 		return 0;
48 
49 	spin_lock_irqsave(&rtc_lock, flags);
50 	v = CMOS_READ(sbf_port);
51 	spin_unlock_irqrestore(&rtc_lock, flags);
52 
53 	return v;
54 }
55 
sbf_value_valid(u8 v)56 static bool __init sbf_value_valid(u8 v)
57 {
58 	if (v & SBF_RESERVED)		/* Reserved bits */
59 		return false;
60 	if (!parity8(v))
61 		return false;
62 
63 	return true;
64 }
65 
sbf_init(void)66 static int __init sbf_init(void)
67 {
68 	u8 v;
69 
70 	if (sbf_port == -1)
71 		return 0;
72 
73 	v = sbf_read();
74 	if (!sbf_value_valid(v)) {
75 		printk(KERN_WARNING "Simple Boot Flag value 0x%x read from "
76 			"CMOS RAM was invalid\n", v);
77 	}
78 
79 	v &= ~SBF_RESERVED;
80 	v &= ~SBF_BOOTING;
81 	v &= ~SBF_DIAG;
82 #if defined(CONFIG_ISAPNP)
83 	v |= SBF_PNPOS;
84 #endif
85 	sbf_write(v);
86 
87 	return 0;
88 }
89 arch_initcall(sbf_init);
90