Branch data 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 : 3 : static int __init sbf_init(void) 80 : : { 81 : 3 : u8 v; 82 : : 83 [ - + ]: 3 : 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);