]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powernv/opal_dev.c
libarchive: merge security fix from vendor branch
[FreeBSD/FreeBSD.git] / sys / powerpc / powernv / opal_dev.c
1 /*-
2  * Copyright (c) 2015 Nathan Whitehorn
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/module.h>
31 #include <sys/bus.h>
32 #include <sys/conf.h>
33 #include <sys/clock.h>
34 #include <sys/cpu.h>
35 #include <sys/eventhandler.h>
36 #include <sys/kernel.h>
37 #include <sys/kthread.h>
38 #include <sys/reboot.h>
39 #include <sys/sysctl.h>
40 #include <sys/endian.h>
41
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
47 #include <dev/ofw/openfirm.h>
48
49 #include "clock_if.h"
50 #include "opal.h"
51
52 static int      opaldev_probe(device_t);
53 static int      opaldev_attach(device_t);
54 /* clock interface */
55 static int      opal_gettime(device_t dev, struct timespec *ts);
56 static int      opal_settime(device_t dev, struct timespec *ts);
57 /* ofw bus interface */
58 static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev,
59     device_t child);
60
61 static void     opal_shutdown(void *arg, int howto);
62 static void     opal_handle_shutdown_message(void *unused,
63     struct opal_msg *msg);
64 static void     opal_intr(void *);
65
66 static device_method_t  opaldev_methods[] = {
67         /* Device interface */
68         DEVMETHOD(device_probe,         opaldev_probe),
69         DEVMETHOD(device_attach,        opaldev_attach),
70
71         /* clock interface */
72         DEVMETHOD(clock_gettime,        opal_gettime),
73         DEVMETHOD(clock_settime,        opal_settime),
74
75         /* Bus interface */
76         DEVMETHOD(bus_child_pnpinfo,    ofw_bus_gen_child_pnpinfo),
77
78         /* ofw_bus interface */
79         DEVMETHOD(ofw_bus_get_devinfo,  opaldev_get_devinfo),
80         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
81         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
82         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
83         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
84         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
85
86         DEVMETHOD_END
87 };
88
89 static driver_t opaldev_driver = {
90         "opal",
91         opaldev_methods,
92         0
93 };
94
95 EARLY_DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, 0, 0, BUS_PASS_BUS);
96
97 static void opal_heartbeat(void);
98 static void opal_handle_messages(void);
99
100 static struct proc *opal_hb_proc;
101 static struct kproc_desc opal_heartbeat_kp = {
102         "opal_heartbeat",
103         opal_heartbeat,
104         &opal_hb_proc
105 };
106
107 SYSINIT(opal_heartbeat_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start,
108     &opal_heartbeat_kp);
109
110 static int opal_heartbeat_ms;
111 EVENTHANDLER_LIST_DEFINE(OPAL_ASYNC_COMP);
112 EVENTHANDLER_LIST_DEFINE(OPAL_EPOW);
113 EVENTHANDLER_LIST_DEFINE(OPAL_SHUTDOWN);
114 EVENTHANDLER_LIST_DEFINE(OPAL_HMI_EVT);
115 EVENTHANDLER_LIST_DEFINE(OPAL_DPO);
116 EVENTHANDLER_LIST_DEFINE(OPAL_OCC);
117
118 #define OPAL_SOFT_OFF           0
119 #define OPAL_SOFT_REBOOT        1
120
121 static void
122 opal_heartbeat(void)
123 {
124         uint64_t events;
125
126         if (opal_heartbeat_ms == 0)
127                 kproc_exit(0);
128
129         while (1) {
130                 events = 0;
131                 /* Turn the OPAL state crank */
132                 opal_call(OPAL_POLL_EVENTS, vtophys(&events));
133                 if (be64toh(events) & OPAL_EVENT_MSG_PENDING)
134                         opal_handle_messages();
135                 tsleep(opal_hb_proc, 0, "opal",
136                     MSEC_2_TICKS(opal_heartbeat_ms));
137         }
138 }
139
140 static int
141 opaldev_probe(device_t dev)
142 {
143         phandle_t iparent;
144         pcell_t *irqs;
145         int i, n_irqs;
146
147         if (!ofw_bus_is_compatible(dev, "ibm,opal-v3"))
148                 return (ENXIO);
149         if (opal_check() != 0)
150                 return (ENXIO);
151
152         device_set_desc(dev, "OPAL Abstraction Firmware");
153
154         /* Manually add IRQs before attaching */
155         if (OF_hasprop(ofw_bus_get_node(dev), "opal-interrupts")) {
156                 iparent = OF_finddevice("/interrupt-controller@0");
157                 iparent = OF_xref_from_node(iparent);
158
159                 n_irqs = OF_getproplen(ofw_bus_get_node(dev),
160                     "opal-interrupts") / sizeof(*irqs);
161                 irqs = malloc(n_irqs * sizeof(*irqs), M_DEVBUF, M_WAITOK);
162                 OF_getencprop(ofw_bus_get_node(dev), "opal-interrupts", irqs,
163                     n_irqs * sizeof(*irqs));
164                 for (i = 0; i < n_irqs; i++)
165                         bus_set_resource(dev, SYS_RES_IRQ, i,
166                             ofw_bus_map_intr(dev, iparent, 1, &irqs[i]), 1);
167                 free(irqs, M_DEVBUF);
168         }
169
170         return (BUS_PROBE_SPECIFIC);
171 }
172
173 static int
174 opaldev_attach(device_t dev)
175 {
176         phandle_t child;
177         device_t cdev;
178         uint64_t junk;
179         int i, rv;
180         uint32_t async_count;
181         struct ofw_bus_devinfo *dinfo;
182         struct resource *irq;
183
184         /* Test for RTC support and register clock if it works */
185         rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk));
186         do {
187                 rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk));
188                 if (rv == OPAL_BUSY_EVENT)
189                         rv = opal_call(OPAL_POLL_EVENTS, 0);
190         } while (rv == OPAL_BUSY_EVENT);
191
192         if (rv == OPAL_SUCCESS)
193                 clock_register(dev, 2000);
194
195         EVENTHANDLER_REGISTER(OPAL_SHUTDOWN, opal_handle_shutdown_message,
196             NULL, EVENTHANDLER_PRI_ANY);
197         EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL,
198             SHUTDOWN_PRI_LAST);
199
200         OF_getencprop(ofw_bus_get_node(dev), "ibm,heartbeat-ms",
201             &opal_heartbeat_ms, sizeof(opal_heartbeat_ms));
202         /* Bind to interrupts */
203         for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i,
204             RF_ACTIVE)) != NULL; i++)
205                 bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE |
206                     INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq),
207                     NULL);
208
209         OF_getencprop(ofw_bus_get_node(dev), "opal-msg-async-num",
210             &async_count, sizeof(async_count));
211         opal_init_async_tokens(async_count);
212
213         for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
214             child = OF_peer(child)) {
215                 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
216                 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
217                         free(dinfo, M_DEVBUF);
218                         continue;
219                 }
220                 cdev = device_add_child(dev, NULL, -1);
221                 if (cdev == NULL) {
222                         device_printf(dev, "<%s>: device_add_child failed\n",
223                             dinfo->obd_name);
224                         ofw_bus_gen_destroy_devinfo(dinfo);
225                         free(dinfo, M_DEVBUF);
226                         continue;
227                 }
228                 device_set_ivars(cdev, dinfo);
229         }
230
231         return (bus_generic_attach(dev));
232 }
233
234 static int
235 bcd2bin32(int bcd)
236 {
237         int out = 0;
238
239         out += bcd2bin(bcd & 0xff);
240         out += 100*bcd2bin((bcd & 0x0000ff00) >> 8);
241         out += 10000*bcd2bin((bcd & 0x00ff0000) >> 16);
242         out += 1000000*bcd2bin((bcd & 0xffff0000) >> 24);
243
244         return (out);
245 }
246
247 static int
248 bin2bcd32(int bin)
249 {
250         int out = 0;
251         int tmp;
252
253         tmp = bin % 100;
254         out += bin2bcd(tmp) * 0x1;
255         bin = bin / 100;
256
257         tmp = bin % 100;
258         out += bin2bcd(tmp) * 0x100;
259         bin = bin / 100;
260
261         tmp = bin % 100;
262         out += bin2bcd(tmp) * 0x10000;
263
264         return (out);
265 }
266
267 static int
268 opal_gettime(device_t dev, struct timespec *ts)
269 {
270         int rv;
271         struct clocktime ct;
272         uint32_t ymd;
273         uint64_t hmsm;
274
275         rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm));
276         while (rv == OPAL_BUSY_EVENT)  {
277                 opal_call(OPAL_POLL_EVENTS, 0);
278                 pause("opalrtc", 1);
279                 rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm));
280         }
281
282         if (rv != OPAL_SUCCESS)
283                 return (ENXIO);
284
285         hmsm = be64toh(hmsm);
286         ymd = be32toh(ymd);
287
288         ct.nsec = bcd2bin32((hmsm & 0x000000ffffff0000) >> 16) * 1000;
289         ct.sec  = bcd2bin((hmsm & 0x0000ff0000000000) >> 40);
290         ct.min  = bcd2bin((hmsm & 0x00ff000000000000) >> 48);
291         ct.hour = bcd2bin((hmsm & 0xff00000000000000) >> 56);
292
293         ct.day  = bcd2bin((ymd & 0x000000ff) >> 0);
294         ct.mon  = bcd2bin((ymd & 0x0000ff00) >> 8);
295         ct.year = bcd2bin32((ymd & 0xffff0000) >> 16);
296
297         return (clock_ct_to_ts(&ct, ts));
298 }
299
300 static int
301 opal_settime(device_t dev, struct timespec *ts)
302 {
303         int rv;
304         struct clocktime ct;
305         uint32_t ymd = 0;
306         uint64_t hmsm = 0;
307
308         clock_ts_to_ct(ts, &ct);
309
310         ymd |= (uint32_t)bin2bcd(ct.day);
311         ymd |= ((uint32_t)bin2bcd(ct.mon) << 8);
312         ymd |= ((uint32_t)bin2bcd32(ct.year) << 16);
313
314         hmsm |= ((uint64_t)bin2bcd32(ct.nsec/1000) << 16);
315         hmsm |= ((uint64_t)bin2bcd(ct.sec) << 40);
316         hmsm |= ((uint64_t)bin2bcd(ct.min) << 48);
317         hmsm |= ((uint64_t)bin2bcd(ct.hour) << 56);
318
319         /*
320          * We do NOT swap endian here, because the values are being sent
321          * via registers instead of indirect via memory.
322          */
323         do {
324                 rv = opal_call(OPAL_RTC_WRITE, ymd, hmsm);
325                 if (rv == OPAL_BUSY_EVENT) {
326                         rv = opal_call(OPAL_POLL_EVENTS, 0);
327                         pause("opalrtc", 1);
328                 }
329         } while (rv == OPAL_BUSY_EVENT);
330
331         if (rv != OPAL_SUCCESS)
332                 return (ENXIO);
333
334         return (0);
335 }
336
337 static const struct ofw_bus_devinfo *
338 opaldev_get_devinfo(device_t dev, device_t child)
339 {
340         return (device_get_ivars(child));
341 }
342
343 static void
344 opal_shutdown(void *arg, int howto)
345 {
346
347         if (howto & RB_HALT)
348                 opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */);
349         else
350                 opal_call(OPAL_CEC_REBOOT);
351
352         opal_call(OPAL_RETURN_CPU);
353 }
354
355 static void
356 opal_handle_shutdown_message(void *unused, struct opal_msg *msg)
357 {
358         int howto;
359
360         switch (be64toh(msg->params[0])) {
361         case OPAL_SOFT_OFF:
362                 howto = RB_POWEROFF;
363                 break;
364         case OPAL_SOFT_REBOOT:
365                 howto = RB_REROOT;
366                 break;
367         }
368         shutdown_nice(howto);
369 }
370
371 static void
372 opal_handle_messages(void)
373 {
374         static struct opal_msg msg;
375         uint64_t rv;
376         uint32_t type;
377
378         rv = opal_call(OPAL_GET_MSG, vtophys(&msg), sizeof(msg));
379
380         switch (rv) {
381         case OPAL_SUCCESS:
382                 break;
383         case OPAL_RESOURCE:
384                 /* no available messages - return */
385                 return;
386         case OPAL_PARAMETER:
387                 printf("%s error: invalid buffer. Please file a bug report.\n", __func__);
388                 return;
389         case OPAL_PARTIAL:
390                 printf("%s error: buffer is too small and messages was discarded. Please file a bug report.\n", __func__);
391                 return;
392         default:
393                 printf("%s opal_call returned unknown result <%lu>\n", __func__, rv);
394                 return;
395         }
396
397         type = be32toh(msg.msg_type);
398         switch (type) {
399         case OPAL_MSG_ASYNC_COMP:
400                 EVENTHANDLER_DIRECT_INVOKE(OPAL_ASYNC_COMP, &msg);
401                 break;
402         case OPAL_MSG_EPOW:
403                 EVENTHANDLER_DIRECT_INVOKE(OPAL_EPOW, &msg);
404                 break;
405         case OPAL_MSG_SHUTDOWN:
406                 EVENTHANDLER_DIRECT_INVOKE(OPAL_SHUTDOWN, &msg);
407                 break;
408         case OPAL_MSG_HMI_EVT:
409                 EVENTHANDLER_DIRECT_INVOKE(OPAL_HMI_EVT, &msg);
410                 break;
411         case OPAL_MSG_DPO:
412                 EVENTHANDLER_DIRECT_INVOKE(OPAL_DPO, &msg);
413                 break;
414         case OPAL_MSG_OCC:
415                 EVENTHANDLER_DIRECT_INVOKE(OPAL_OCC, &msg);
416                 break;
417         default:
418                 printf("%s Unknown OPAL message type %d\n", __func__, type);
419         }
420 }
421
422 static void
423 opal_intr(void *xintr)
424 {
425         uint64_t events = 0;
426
427         opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr,
428             vtophys(&events));
429         /* Wake up the heartbeat, if it's been setup. */
430         if (be64toh(events) != 0 && opal_hb_proc != NULL)
431                 wakeup(opal_hb_proc);
432
433 }