1 /* $NetBSD: x86_ipmi.c,v 1.1 2018/12/25 11:56:13 mlelstv Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 /* 29 * Copyright (c) 2005 Jordan Hargrave 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 45 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 */ 53 54 #include <sys/cdefs.h> 55 __KERNEL_RCSID(0, "$NetBSD: x86_ipmi.c,v 1.1 2018/12/25 11:56:13 mlelstv Exp $"); 56 57 #include <sys/types.h> 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/kernel.h> 61 #include <sys/pmf.h> 62 #include <sys/bus.h> 63 #include <sys/intr.h> 64 65 #include <x86/smbiosvar.h> 66 67 #include <dev/isa/isareg.h> 68 #include <dev/isa/isavar.h> 69 70 #include <x86/ipmivar.h> 71 72 #define SMBIOS_TYPE_IPMI 0x26 73 74 /* 75 * Format of SMBIOS IPMI Flags 76 * 77 * bit0: interrupt trigger mode (1=level, 0=edge) 78 * bit1: interrupt polarity (1=active high, 0=active low) 79 * bit2: reserved 80 * bit3: address LSB (1=odd,0=even) 81 * bit4: interrupt (1=specified, 0=not specified) 82 * bit5: reserved 83 * bit6/7: register spacing (1,4,2,err) 84 */ 85 #define SMIPMI_FLAG_IRQLVL (1L << 0) 86 #define SMIPMI_FLAG_IRQEN (1L << 3) 87 #define SMIPMI_FLAG_ODDOFFSET (1L << 4) 88 #define SMIPMI_FLAG_IFSPACING(x) (((x)>>6)&0x3) 89 #define IPMI_IOSPACING_BYTE 0 90 #define IPMI_IOSPACING_WORD 2 91 #define IPMI_IOSPACING_DWORD 1 92 93 static void 94 ipmi_smbios_probe(struct smbios_ipmi *pipmi, struct ipmi_attach_args *ia) 95 { 96 const char *platform; 97 98 aprint_debug("%s: %#.2x %#.2x %#.2x %#.2x %#08" PRIx64 99 " %#.2x %#.2x\n", __func__, 100 pipmi->smipmi_if_type, 101 pipmi->smipmi_if_rev, 102 pipmi->smipmi_i2c_address, 103 pipmi->smipmi_nvram_address, 104 pipmi->smipmi_base_address, 105 pipmi->smipmi_base_flags, 106 pipmi->smipmi_irq); 107 108 ia->iaa_if_type = pipmi->smipmi_if_type; 109 ia->iaa_if_rev = pipmi->smipmi_if_rev; 110 ia->iaa_if_irq = (pipmi->smipmi_base_flags & SMIPMI_FLAG_IRQEN) ? 111 pipmi->smipmi_irq : -1; 112 ia->iaa_if_irqlvl = (pipmi->smipmi_base_flags & SMIPMI_FLAG_IRQLVL) ? 113 IST_LEVEL : IST_EDGE; 114 115 switch (SMIPMI_FLAG_IFSPACING(pipmi->smipmi_base_flags)) { 116 case IPMI_IOSPACING_BYTE: 117 ia->iaa_if_iospacing = 1; 118 break; 119 120 case IPMI_IOSPACING_DWORD: 121 ia->iaa_if_iospacing = 4; 122 break; 123 124 case IPMI_IOSPACING_WORD: 125 ia->iaa_if_iospacing = 2; 126 break; 127 128 default: 129 ia->iaa_if_iospacing = 1; 130 aprint_error("%s: unknown register spacing\n", __func__); 131 } 132 133 /* Calculate base address (PCI BAR format) */ 134 if (pipmi->smipmi_base_address & 0x1) { 135 ia->iaa_if_iotype = 'i'; 136 ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0x1; 137 } else { 138 ia->iaa_if_iotype = 'm'; 139 ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0xF; 140 } 141 if (pipmi->smipmi_base_flags & SMIPMI_FLAG_ODDOFFSET) 142 ia->iaa_if_iobase++; 143 144 platform = pmf_get_platform("system-product"); 145 if (platform != NULL && 146 strcmp(platform, "ProLiant MicroServer") == 0 && 147 pipmi->smipmi_base_address != 0) { 148 ia->iaa_if_iospacing = 1; 149 ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0x7; 150 ia->iaa_if_iotype = 'i'; 151 return; 152 } 153 154 if (pipmi->smipmi_base_flags == 0x7f) { 155 /* IBM 325 eServer workaround */ 156 ia->iaa_if_iospacing = 1; 157 ia->iaa_if_iobase = pipmi->smipmi_base_address; 158 ia->iaa_if_iotype = 'i'; 159 return; 160 } 161 } 162 163 /* Scan memory for signature */ 164 static void * 165 scan_sig(long start, long end, int skip, int len, const void *data) 166 { 167 void *va; 168 169 while (start < end) { 170 va = ISA_HOLE_VADDR(start); 171 if (memcmp(va, data, len) == 0) 172 return (va); 173 174 start += skip; 175 } 176 177 return (NULL); 178 } 179 180 int 181 ipmi_probe(struct ipmi_attach_args *ia) 182 { 183 struct dmd_ipmi *pipmi; 184 struct smbtable tbl; 185 186 tbl.cookie = 0; 187 188 if (smbios_find_table(SMBIOS_TYPE_IPMIDEV, &tbl)) 189 ipmi_smbios_probe(tbl.tblhdr, ia); 190 else { 191 pipmi = scan_sig(0xC0000L, 0xFFFFFL, 16, 4, "IPMI"); 192 /* XXX hack to find Dell PowerEdge 8450 */ 193 if (pipmi == NULL) { 194 /* no IPMI found */ 195 return 0; 196 } 197 198 /* we have an IPMI signature, fill in attach arg structure */ 199 ia->iaa_if_type = pipmi->dmd_if_type; 200 ia->iaa_if_rev = pipmi->dmd_if_rev; 201 } 202 203 return 1; 204 } 205 206