xref: /netbsd-src/sys/arch/x86/x86/x86_ipmi.c (revision 76646d9e03c9615328f50b26f06c9b57e12e065b)
1 /*	$NetBSD: x86_ipmi.c,v 1.3 2021/10/07 12:52:27 msaitoh 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.3 2021/10/07 12:52:27 msaitoh 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 <dev/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
ipmi_smbios_probe(struct smbios_ipmi * pipmi,struct ipmi_attach_args * ia)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 *
scan_sig(long start,long end,int skip,int len,const void * data)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
ipmi_probe(struct ipmi_attach_args * ia)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