Line data Source code
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 <asm/io.h> 12 : 13 : #include <linux/mc146818rtc.h> 14 : 15 : #define SBF_RESERVED (0x78) 16 : #define SBF_PNPOS (1<<0) 17 : #define SBF_BOOTING (1<<1) 18 : #define SBF_DIAG (1<<2) 19 : #define SBF_PARITY (1<<7) 20 : 21 : int sbf_port __initdata = -1; /* set via acpi_boot_init() */ 22 : 23 0 : static int __init parity(u8 v) 24 : { 25 0 : int x = 0; 26 0 : int i; 27 : 28 0 : for (i = 0; i < 8; i++) { 29 0 : x ^= (v & 1); 30 0 : v >>= 1; 31 : } 32 : 33 0 : return x; 34 : } 35 : 36 0 : static void __init sbf_write(u8 v) 37 : { 38 0 : unsigned long flags; 39 : 40 0 : if (sbf_port != -1) { 41 0 : v &= ~SBF_PARITY; 42 0 : if (!parity(v)) 43 0 : v |= SBF_PARITY; 44 : 45 0 : printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", 46 : sbf_port, v); 47 : 48 0 : spin_lock_irqsave(&rtc_lock, flags); 49 0 : CMOS_WRITE(v, sbf_port); 50 0 : spin_unlock_irqrestore(&rtc_lock, flags); 51 : } 52 0 : } 53 : 54 0 : static u8 __init sbf_read(void) 55 : { 56 0 : unsigned long flags; 57 0 : u8 v; 58 : 59 0 : if (sbf_port == -1) 60 : return 0; 61 : 62 0 : spin_lock_irqsave(&rtc_lock, flags); 63 0 : v = CMOS_READ(sbf_port); 64 0 : spin_unlock_irqrestore(&rtc_lock, flags); 65 : 66 0 : return v; 67 : } 68 : 69 0 : static int __init sbf_value_valid(u8 v) 70 : { 71 0 : if (v & SBF_RESERVED) /* Reserved bits */ 72 : return 0; 73 0 : if (!parity(v)) 74 0 : return 0; 75 : 76 : return 1; 77 : } 78 : 79 1 : static int __init sbf_init(void) 80 : { 81 1 : u8 v; 82 : 83 1 : if (sbf_port == -1) 84 : return 0; 85 : 86 0 : v = sbf_read(); 87 0 : if (!sbf_value_valid(v)) { 88 0 : printk(KERN_WARNING "Simple Boot Flag value 0x%x read from " 89 : "CMOS RAM was invalid\n", v); 90 : } 91 : 92 0 : v &= ~SBF_RESERVED; 93 0 : v &= ~SBF_BOOTING; 94 0 : v &= ~SBF_DIAG; 95 : #if defined(CONFIG_ISAPNP) 96 : v |= SBF_PNPOS; 97 : #endif 98 0 : sbf_write(v); 99 : 100 0 : return 0; 101 : } 102 : arch_initcall(sbf_init);