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