1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ipmi_si_platform.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Handling for platform devices in IPMI (ACPI, OF, and things
6*4882a593Smuzhiyun * coming from the platform.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define pr_fmt(fmt) "ipmi_platform: " fmt
10*4882a593Smuzhiyun #define dev_fmt pr_fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/types.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/of_device.h>
15*4882a593Smuzhiyun #include <linux/of_platform.h>
16*4882a593Smuzhiyun #include <linux/of_address.h>
17*4882a593Smuzhiyun #include <linux/of_irq.h>
18*4882a593Smuzhiyun #include <linux/acpi.h>
19*4882a593Smuzhiyun #include "ipmi_si.h"
20*4882a593Smuzhiyun #include "ipmi_dmi.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static bool platform_registered;
23*4882a593Smuzhiyun static bool si_tryplatform = true;
24*4882a593Smuzhiyun #ifdef CONFIG_ACPI
25*4882a593Smuzhiyun static bool si_tryacpi = true;
26*4882a593Smuzhiyun #endif
27*4882a593Smuzhiyun #ifdef CONFIG_OF
28*4882a593Smuzhiyun static bool si_tryopenfirmware = true;
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun #ifdef CONFIG_DMI
31*4882a593Smuzhiyun static bool si_trydmi = true;
32*4882a593Smuzhiyun #else
33*4882a593Smuzhiyun static bool si_trydmi = false;
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun module_param_named(tryplatform, si_tryplatform, bool, 0);
37*4882a593Smuzhiyun MODULE_PARM_DESC(tryplatform, "Setting this to zero will disable the"
38*4882a593Smuzhiyun " default scan of the interfaces identified via platform"
39*4882a593Smuzhiyun " interfaces besides ACPI, OpenFirmware, and DMI");
40*4882a593Smuzhiyun #ifdef CONFIG_ACPI
41*4882a593Smuzhiyun module_param_named(tryacpi, si_tryacpi, bool, 0);
42*4882a593Smuzhiyun MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the"
43*4882a593Smuzhiyun " default scan of the interfaces identified via ACPI");
44*4882a593Smuzhiyun #endif
45*4882a593Smuzhiyun #ifdef CONFIG_OF
46*4882a593Smuzhiyun module_param_named(tryopenfirmware, si_tryopenfirmware, bool, 0);
47*4882a593Smuzhiyun MODULE_PARM_DESC(tryopenfirmware, "Setting this to zero will disable the"
48*4882a593Smuzhiyun " default scan of the interfaces identified via OpenFirmware");
49*4882a593Smuzhiyun #endif
50*4882a593Smuzhiyun #ifdef CONFIG_DMI
51*4882a593Smuzhiyun module_param_named(trydmi, si_trydmi, bool, 0);
52*4882a593Smuzhiyun MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the"
53*4882a593Smuzhiyun " default scan of the interfaces identified via DMI");
54*4882a593Smuzhiyun #endif
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #ifdef CONFIG_ACPI
57*4882a593Smuzhiyun /* For GPE-type interrupts. */
ipmi_acpi_gpe(acpi_handle gpe_device,u32 gpe_number,void * context)58*4882a593Smuzhiyun static u32 ipmi_acpi_gpe(acpi_handle gpe_device,
59*4882a593Smuzhiyun u32 gpe_number, void *context)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun struct si_sm_io *io = context;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun ipmi_si_irq_handler(io->irq, io->irq_handler_data);
64*4882a593Smuzhiyun return ACPI_INTERRUPT_HANDLED;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
acpi_gpe_irq_cleanup(struct si_sm_io * io)67*4882a593Smuzhiyun static void acpi_gpe_irq_cleanup(struct si_sm_io *io)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun if (!io->irq)
70*4882a593Smuzhiyun return;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun ipmi_irq_start_cleanup(io);
73*4882a593Smuzhiyun acpi_remove_gpe_handler(NULL, io->irq, &ipmi_acpi_gpe);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
acpi_gpe_irq_setup(struct si_sm_io * io)76*4882a593Smuzhiyun static int acpi_gpe_irq_setup(struct si_sm_io *io)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun acpi_status status;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (!io->irq)
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun status = acpi_install_gpe_handler(NULL,
84*4882a593Smuzhiyun io->irq,
85*4882a593Smuzhiyun ACPI_GPE_LEVEL_TRIGGERED,
86*4882a593Smuzhiyun &ipmi_acpi_gpe,
87*4882a593Smuzhiyun io);
88*4882a593Smuzhiyun if (status != AE_OK) {
89*4882a593Smuzhiyun dev_warn(io->dev,
90*4882a593Smuzhiyun "Unable to claim ACPI GPE %d, running polled\n",
91*4882a593Smuzhiyun io->irq);
92*4882a593Smuzhiyun io->irq = 0;
93*4882a593Smuzhiyun return -EINVAL;
94*4882a593Smuzhiyun } else {
95*4882a593Smuzhiyun io->irq_cleanup = acpi_gpe_irq_cleanup;
96*4882a593Smuzhiyun ipmi_irq_finish_setup(io);
97*4882a593Smuzhiyun dev_info(io->dev, "Using ACPI GPE %d\n", io->irq);
98*4882a593Smuzhiyun return 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun #endif
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun static struct resource *
ipmi_get_info_from_resources(struct platform_device * pdev,struct si_sm_io * io)104*4882a593Smuzhiyun ipmi_get_info_from_resources(struct platform_device *pdev,
105*4882a593Smuzhiyun struct si_sm_io *io)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun struct resource *res, *res_second;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_IO, 0);
110*4882a593Smuzhiyun if (res) {
111*4882a593Smuzhiyun io->addr_space = IPMI_IO_ADDR_SPACE;
112*4882a593Smuzhiyun } else {
113*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
114*4882a593Smuzhiyun if (res)
115*4882a593Smuzhiyun io->addr_space = IPMI_MEM_ADDR_SPACE;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun if (!res) {
118*4882a593Smuzhiyun dev_err(&pdev->dev, "no I/O or memory address\n");
119*4882a593Smuzhiyun return NULL;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun io->addr_data = res->start;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun io->regspacing = DEFAULT_REGSPACING;
124*4882a593Smuzhiyun res_second = platform_get_resource(pdev,
125*4882a593Smuzhiyun (io->addr_space == IPMI_IO_ADDR_SPACE) ?
126*4882a593Smuzhiyun IORESOURCE_IO : IORESOURCE_MEM,
127*4882a593Smuzhiyun 1);
128*4882a593Smuzhiyun if (res_second) {
129*4882a593Smuzhiyun if (res_second->start > io->addr_data)
130*4882a593Smuzhiyun io->regspacing = res_second->start - io->addr_data;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun return res;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
platform_ipmi_probe(struct platform_device * pdev)136*4882a593Smuzhiyun static int platform_ipmi_probe(struct platform_device *pdev)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct si_sm_io io;
139*4882a593Smuzhiyun u8 type, slave_addr, addr_source, regsize, regshift;
140*4882a593Smuzhiyun int rv;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source);
143*4882a593Smuzhiyun if (rv)
144*4882a593Smuzhiyun addr_source = SI_PLATFORM;
145*4882a593Smuzhiyun if (addr_source >= SI_LAST)
146*4882a593Smuzhiyun return -EINVAL;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (addr_source == SI_SMBIOS) {
149*4882a593Smuzhiyun if (!si_trydmi)
150*4882a593Smuzhiyun return -ENODEV;
151*4882a593Smuzhiyun } else if (addr_source != SI_HARDCODED) {
152*4882a593Smuzhiyun if (!si_tryplatform)
153*4882a593Smuzhiyun return -ENODEV;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type);
157*4882a593Smuzhiyun if (rv)
158*4882a593Smuzhiyun return -ENODEV;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun memset(&io, 0, sizeof(io));
161*4882a593Smuzhiyun io.addr_source = addr_source;
162*4882a593Smuzhiyun dev_info(&pdev->dev, "probing via %s\n",
163*4882a593Smuzhiyun ipmi_addr_src_to_str(addr_source));
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun switch (type) {
166*4882a593Smuzhiyun case SI_KCS:
167*4882a593Smuzhiyun case SI_SMIC:
168*4882a593Smuzhiyun case SI_BT:
169*4882a593Smuzhiyun io.si_type = type;
170*4882a593Smuzhiyun break;
171*4882a593Smuzhiyun case SI_TYPE_INVALID: /* User disabled this in hardcode. */
172*4882a593Smuzhiyun return -ENODEV;
173*4882a593Smuzhiyun default:
174*4882a593Smuzhiyun dev_err(&pdev->dev, "ipmi-type property is invalid\n");
175*4882a593Smuzhiyun return -EINVAL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun io.regsize = DEFAULT_REGSIZE;
179*4882a593Smuzhiyun rv = device_property_read_u8(&pdev->dev, "reg-size", ®size);
180*4882a593Smuzhiyun if (!rv)
181*4882a593Smuzhiyun io.regsize = regsize;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun io.regshift = 0;
184*4882a593Smuzhiyun rv = device_property_read_u8(&pdev->dev, "reg-shift", ®shift);
185*4882a593Smuzhiyun if (!rv)
186*4882a593Smuzhiyun io.regshift = regshift;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun if (!ipmi_get_info_from_resources(pdev, &io))
189*4882a593Smuzhiyun return -EINVAL;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr);
192*4882a593Smuzhiyun if (rv)
193*4882a593Smuzhiyun io.slave_addr = 0x20;
194*4882a593Smuzhiyun else
195*4882a593Smuzhiyun io.slave_addr = slave_addr;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun io.irq = platform_get_irq_optional(pdev, 0);
198*4882a593Smuzhiyun if (io.irq > 0)
199*4882a593Smuzhiyun io.irq_setup = ipmi_std_irq_setup;
200*4882a593Smuzhiyun else
201*4882a593Smuzhiyun io.irq = 0;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun io.dev = &pdev->dev;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun pr_info("ipmi_si: %s: %s %#lx regsize %d spacing %d irq %d\n",
206*4882a593Smuzhiyun ipmi_addr_src_to_str(addr_source),
207*4882a593Smuzhiyun (io.addr_space == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
208*4882a593Smuzhiyun io.addr_data, io.regsize, io.regspacing, io.irq);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun ipmi_si_add_smi(&io);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun #ifdef CONFIG_OF
216*4882a593Smuzhiyun static const struct of_device_id of_ipmi_match[] = {
217*4882a593Smuzhiyun { .type = "ipmi", .compatible = "ipmi-kcs",
218*4882a593Smuzhiyun .data = (void *)(unsigned long) SI_KCS },
219*4882a593Smuzhiyun { .type = "ipmi", .compatible = "ipmi-smic",
220*4882a593Smuzhiyun .data = (void *)(unsigned long) SI_SMIC },
221*4882a593Smuzhiyun { .type = "ipmi", .compatible = "ipmi-bt",
222*4882a593Smuzhiyun .data = (void *)(unsigned long) SI_BT },
223*4882a593Smuzhiyun {},
224*4882a593Smuzhiyun };
225*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_ipmi_match);
226*4882a593Smuzhiyun
of_ipmi_probe(struct platform_device * pdev)227*4882a593Smuzhiyun static int of_ipmi_probe(struct platform_device *pdev)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun const struct of_device_id *match;
230*4882a593Smuzhiyun struct si_sm_io io;
231*4882a593Smuzhiyun struct resource resource;
232*4882a593Smuzhiyun const __be32 *regsize, *regspacing, *regshift;
233*4882a593Smuzhiyun struct device_node *np = pdev->dev.of_node;
234*4882a593Smuzhiyun int ret;
235*4882a593Smuzhiyun int proplen;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (!si_tryopenfirmware)
238*4882a593Smuzhiyun return -ENODEV;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun dev_info(&pdev->dev, "probing via device tree\n");
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun match = of_match_device(of_ipmi_match, &pdev->dev);
243*4882a593Smuzhiyun if (!match)
244*4882a593Smuzhiyun return -ENODEV;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun if (!of_device_is_available(np))
247*4882a593Smuzhiyun return -EINVAL;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun ret = of_address_to_resource(np, 0, &resource);
250*4882a593Smuzhiyun if (ret) {
251*4882a593Smuzhiyun dev_warn(&pdev->dev, "invalid address from OF\n");
252*4882a593Smuzhiyun return ret;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun regsize = of_get_property(np, "reg-size", &proplen);
256*4882a593Smuzhiyun if (regsize && proplen != 4) {
257*4882a593Smuzhiyun dev_warn(&pdev->dev, "invalid regsize from OF\n");
258*4882a593Smuzhiyun return -EINVAL;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun regspacing = of_get_property(np, "reg-spacing", &proplen);
262*4882a593Smuzhiyun if (regspacing && proplen != 4) {
263*4882a593Smuzhiyun dev_warn(&pdev->dev, "invalid regspacing from OF\n");
264*4882a593Smuzhiyun return -EINVAL;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun regshift = of_get_property(np, "reg-shift", &proplen);
268*4882a593Smuzhiyun if (regshift && proplen != 4) {
269*4882a593Smuzhiyun dev_warn(&pdev->dev, "invalid regshift from OF\n");
270*4882a593Smuzhiyun return -EINVAL;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun memset(&io, 0, sizeof(io));
274*4882a593Smuzhiyun io.si_type = (enum si_type) match->data;
275*4882a593Smuzhiyun io.addr_source = SI_DEVICETREE;
276*4882a593Smuzhiyun io.irq_setup = ipmi_std_irq_setup;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (resource.flags & IORESOURCE_IO)
279*4882a593Smuzhiyun io.addr_space = IPMI_IO_ADDR_SPACE;
280*4882a593Smuzhiyun else
281*4882a593Smuzhiyun io.addr_space = IPMI_MEM_ADDR_SPACE;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun io.addr_data = resource.start;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE;
286*4882a593Smuzhiyun io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING;
287*4882a593Smuzhiyun io.regshift = regshift ? be32_to_cpup(regshift) : 0;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
290*4882a593Smuzhiyun io.dev = &pdev->dev;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n",
293*4882a593Smuzhiyun io.addr_data, io.regsize, io.regspacing, io.irq);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun return ipmi_si_add_smi(&io);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun #else
298*4882a593Smuzhiyun #define of_ipmi_match NULL
of_ipmi_probe(struct platform_device * dev)299*4882a593Smuzhiyun static int of_ipmi_probe(struct platform_device *dev)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun return -ENODEV;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun #endif
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun #ifdef CONFIG_ACPI
find_slave_address(struct si_sm_io * io,int slave_addr)306*4882a593Smuzhiyun static int find_slave_address(struct si_sm_io *io, int slave_addr)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun #ifdef CONFIG_IPMI_DMI_DECODE
309*4882a593Smuzhiyun if (!slave_addr)
310*4882a593Smuzhiyun slave_addr = ipmi_dmi_get_slave_addr(io->si_type,
311*4882a593Smuzhiyun io->addr_space,
312*4882a593Smuzhiyun io->addr_data);
313*4882a593Smuzhiyun #endif
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return slave_addr;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
acpi_ipmi_probe(struct platform_device * pdev)318*4882a593Smuzhiyun static int acpi_ipmi_probe(struct platform_device *pdev)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct si_sm_io io;
321*4882a593Smuzhiyun acpi_handle handle;
322*4882a593Smuzhiyun acpi_status status;
323*4882a593Smuzhiyun unsigned long long tmp;
324*4882a593Smuzhiyun struct resource *res;
325*4882a593Smuzhiyun int rv = -EINVAL;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (!si_tryacpi)
328*4882a593Smuzhiyun return -ENODEV;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun handle = ACPI_HANDLE(&pdev->dev);
331*4882a593Smuzhiyun if (!handle)
332*4882a593Smuzhiyun return -ENODEV;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun memset(&io, 0, sizeof(io));
335*4882a593Smuzhiyun io.addr_source = SI_ACPI;
336*4882a593Smuzhiyun dev_info(&pdev->dev, "probing via ACPI\n");
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun io.addr_info.acpi_info.acpi_handle = handle;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* _IFT tells us the interface type: KCS, BT, etc */
341*4882a593Smuzhiyun status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
342*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
343*4882a593Smuzhiyun dev_err(&pdev->dev,
344*4882a593Smuzhiyun "Could not find ACPI IPMI interface type\n");
345*4882a593Smuzhiyun goto err_free;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun switch (tmp) {
349*4882a593Smuzhiyun case 1:
350*4882a593Smuzhiyun io.si_type = SI_KCS;
351*4882a593Smuzhiyun break;
352*4882a593Smuzhiyun case 2:
353*4882a593Smuzhiyun io.si_type = SI_SMIC;
354*4882a593Smuzhiyun break;
355*4882a593Smuzhiyun case 3:
356*4882a593Smuzhiyun io.si_type = SI_BT;
357*4882a593Smuzhiyun break;
358*4882a593Smuzhiyun case 4: /* SSIF, just ignore */
359*4882a593Smuzhiyun rv = -ENODEV;
360*4882a593Smuzhiyun goto err_free;
361*4882a593Smuzhiyun default:
362*4882a593Smuzhiyun dev_info(&pdev->dev, "unknown IPMI type %lld\n", tmp);
363*4882a593Smuzhiyun goto err_free;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun io.regsize = DEFAULT_REGSIZE;
367*4882a593Smuzhiyun io.regshift = 0;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun res = ipmi_get_info_from_resources(pdev, &io);
370*4882a593Smuzhiyun if (!res) {
371*4882a593Smuzhiyun rv = -EINVAL;
372*4882a593Smuzhiyun goto err_free;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /* If _GPE exists, use it; otherwise use standard interrupts */
376*4882a593Smuzhiyun status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
377*4882a593Smuzhiyun if (ACPI_SUCCESS(status)) {
378*4882a593Smuzhiyun io.irq = tmp;
379*4882a593Smuzhiyun io.irq_setup = acpi_gpe_irq_setup;
380*4882a593Smuzhiyun } else {
381*4882a593Smuzhiyun int irq = platform_get_irq_optional(pdev, 0);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (irq > 0) {
384*4882a593Smuzhiyun io.irq = irq;
385*4882a593Smuzhiyun io.irq_setup = ipmi_std_irq_setup;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun io.slave_addr = find_slave_address(&io, io.slave_addr);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun io.dev = &pdev->dev;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun dev_info(io.dev, "%pR regsize %d spacing %d irq %d\n",
394*4882a593Smuzhiyun res, io.regsize, io.regspacing, io.irq);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun request_module("acpi_ipmi");
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return ipmi_si_add_smi(&io);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun err_free:
401*4882a593Smuzhiyun return rv;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun static const struct acpi_device_id acpi_ipmi_match[] = {
405*4882a593Smuzhiyun { "IPI0001", 0 },
406*4882a593Smuzhiyun { },
407*4882a593Smuzhiyun };
408*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match);
409*4882a593Smuzhiyun #else
acpi_ipmi_probe(struct platform_device * dev)410*4882a593Smuzhiyun static int acpi_ipmi_probe(struct platform_device *dev)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun return -ENODEV;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun #endif
415*4882a593Smuzhiyun
ipmi_probe(struct platform_device * pdev)416*4882a593Smuzhiyun static int ipmi_probe(struct platform_device *pdev)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun if (pdev->dev.of_node && of_ipmi_probe(pdev) == 0)
419*4882a593Smuzhiyun return 0;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (acpi_ipmi_probe(pdev) == 0)
422*4882a593Smuzhiyun return 0;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun return platform_ipmi_probe(pdev);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
ipmi_remove(struct platform_device * pdev)427*4882a593Smuzhiyun static int ipmi_remove(struct platform_device *pdev)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun return ipmi_si_remove_by_dev(&pdev->dev);
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
pdev_match_name(struct device * dev,const void * data)432*4882a593Smuzhiyun static int pdev_match_name(struct device *dev, const void *data)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun struct platform_device *pdev = to_platform_device(dev);
435*4882a593Smuzhiyun const char *name = data;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun return strcmp(pdev->name, name) == 0;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
ipmi_remove_platform_device_by_name(char * name)440*4882a593Smuzhiyun void ipmi_remove_platform_device_by_name(char *name)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun struct device *dev;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun while ((dev = bus_find_device(&platform_bus_type, NULL, name,
445*4882a593Smuzhiyun pdev_match_name))) {
446*4882a593Smuzhiyun struct platform_device *pdev = to_platform_device(dev);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun platform_device_unregister(pdev);
449*4882a593Smuzhiyun put_device(dev);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun static const struct platform_device_id si_plat_ids[] = {
454*4882a593Smuzhiyun { "dmi-ipmi-si", 0 },
455*4882a593Smuzhiyun { "hardcode-ipmi-si", 0 },
456*4882a593Smuzhiyun { "hotmod-ipmi-si", 0 },
457*4882a593Smuzhiyun { }
458*4882a593Smuzhiyun };
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun struct platform_driver ipmi_platform_driver = {
461*4882a593Smuzhiyun .driver = {
462*4882a593Smuzhiyun .name = SI_DEVICE_NAME,
463*4882a593Smuzhiyun .of_match_table = of_ipmi_match,
464*4882a593Smuzhiyun .acpi_match_table = ACPI_PTR(acpi_ipmi_match),
465*4882a593Smuzhiyun },
466*4882a593Smuzhiyun .probe = ipmi_probe,
467*4882a593Smuzhiyun .remove = ipmi_remove,
468*4882a593Smuzhiyun .id_table = si_plat_ids
469*4882a593Smuzhiyun };
470*4882a593Smuzhiyun
ipmi_si_platform_init(void)471*4882a593Smuzhiyun void ipmi_si_platform_init(void)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun int rv = platform_driver_register(&ipmi_platform_driver);
474*4882a593Smuzhiyun if (rv)
475*4882a593Smuzhiyun pr_err("Unable to register driver: %d\n", rv);
476*4882a593Smuzhiyun else
477*4882a593Smuzhiyun platform_registered = true;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
ipmi_si_platform_shutdown(void)480*4882a593Smuzhiyun void ipmi_si_platform_shutdown(void)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun if (platform_registered)
483*4882a593Smuzhiyun platform_driver_unregister(&ipmi_platform_driver);
484*4882a593Smuzhiyun }
485