]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powernv/opal_nvram.c
Merge ACPICA 20191018.
[FreeBSD/FreeBSD.git] / sys / powerpc / powernv / opal_nvram.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Justin Hibbits
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
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/disk.h>
36 #include <sys/kernel.h>
37 #include <sys/uio.h>
38
39 #include <dev/ofw/openfirm.h>
40 #include <dev/ofw/ofw_bus.h>
41 #include <dev/ofw/ofw_bus_subr.h>
42
43 #include <machine/bus.h>
44 #include <machine/md_var.h>
45 #include <machine/pio.h>
46 #include <machine/resource.h>
47
48 #include "opal.h"
49
50 #include <sys/rman.h>
51
52 #include <vm/vm.h>
53 #include <vm/pmap.h>
54
55 #define NVRAM_BUFSIZE   (65536) /* 64k blocks */
56
57 struct opal_nvram_softc {
58         device_t         sc_dev;
59         uint32_t         sc_size;
60         uint8_t         *sc_buf;
61         vm_paddr_t       sc_buf_phys;
62
63         struct cdev     *sc_cdev;
64         int              sc_isopen;
65 };
66
67 /*
68  * Device interface.
69  */
70 static int              opal_nvram_probe(device_t);
71 static int              opal_nvram_attach(device_t);
72 static int              opal_nvram_detach(device_t);
73
74 /*
75  * Driver methods.
76  */
77 static device_method_t  opal_nvram_methods[] = {
78         /* Device interface */
79         DEVMETHOD(device_probe,         opal_nvram_probe),
80         DEVMETHOD(device_attach,        opal_nvram_attach),
81         DEVMETHOD(device_detach,        opal_nvram_detach),
82
83         { 0, 0 }
84 };
85
86 static driver_t opal_nvram_driver = {
87         "opal_nvram",
88         opal_nvram_methods,
89         sizeof(struct opal_nvram_softc)
90 };
91
92 static devclass_t opal_nvram_devclass;
93
94 DRIVER_MODULE(opal_nvram, opal, opal_nvram_driver, opal_nvram_devclass, 0, 0);
95
96 /*
97  * Cdev methods.
98  */
99
100 static  d_open_t        opal_nvram_open;
101 static  d_close_t       opal_nvram_close;
102 static  d_read_t        opal_nvram_read;
103 static  d_write_t       opal_nvram_write;
104 static  d_ioctl_t       opal_nvram_ioctl;
105
106 static struct cdevsw opal_nvram_cdevsw = {
107         .d_version =    D_VERSION,
108         .d_flags =      D_NEEDGIANT,
109         .d_open =       opal_nvram_open,
110         .d_close =      opal_nvram_close,
111         .d_read =       opal_nvram_read,
112         .d_write =      opal_nvram_write,
113         .d_ioctl =      opal_nvram_ioctl,
114         .d_name =       "nvram",
115 };
116
117 static int
118 opal_nvram_probe(device_t dev)
119 {
120
121         if (!ofw_bus_is_compatible(dev, "ibm,opal-nvram"))
122                 return (ENXIO);
123
124         device_set_desc(dev, "OPAL NVRAM");
125         return (BUS_PROBE_DEFAULT);
126 }
127
128 static int
129 opal_nvram_attach(device_t dev)
130 {
131         struct opal_nvram_softc *sc;
132         phandle_t node;
133         int err;
134
135         node = ofw_bus_get_node(dev);
136         sc = device_get_softc(dev);
137
138         sc->sc_dev = dev;
139
140         err = OF_getencprop(node, "#bytes", &sc->sc_size,
141             sizeof(sc->sc_size));
142
143         if (err < 0)
144                 return (ENXIO);
145
146         sc->sc_buf = contigmalloc(NVRAM_BUFSIZE, M_DEVBUF, M_WAITOK,
147             0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
148         if (sc->sc_buf == NULL) {
149                 device_printf(dev, "No memory for buffer.\n");
150                 return (ENXIO);
151         }
152         sc->sc_buf_phys = pmap_kextract((vm_offset_t)sc->sc_buf);
153         sc->sc_cdev = make_dev(&opal_nvram_cdevsw, 0, 0, 0, 0600,
154             "nvram");
155         sc->sc_cdev->si_drv1 = sc;
156
157         return (0);
158 }
159
160 static int
161 opal_nvram_detach(device_t dev)
162 {
163         struct opal_nvram_softc *sc;
164
165         sc = device_get_softc(dev);
166
167         if (sc->sc_cdev != NULL)
168                 destroy_dev(sc->sc_cdev);
169         if (sc->sc_buf != NULL)
170                 contigfree(sc->sc_buf, NVRAM_BUFSIZE, M_DEVBUF);
171         
172         return (0);
173 }
174
175 static int
176 opal_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td)
177 {
178         struct opal_nvram_softc *sc = dev->si_drv1;
179
180         if (sc->sc_isopen)
181                 return EBUSY;
182         sc->sc_isopen = 1;
183         return (0);
184 }
185
186 static int
187 opal_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
188 {
189         struct opal_nvram_softc *sc = dev->si_drv1;
190
191         sc->sc_isopen = 0;
192         return (0);
193 }
194
195 static int
196 opal_nvram_read(struct cdev *dev, struct uio *uio, int ioflag)
197 {
198         struct opal_nvram_softc *sc = dev->si_drv1;
199         int rv, amnt;
200
201         rv = 0;
202         while (uio->uio_resid > 0) {
203                 amnt = MIN(uio->uio_resid, sc->sc_size - uio->uio_offset);
204                 amnt = MIN(amnt, NVRAM_BUFSIZE);
205                 if (amnt == 0)
206                         break;
207
208                 rv = opal_call(OPAL_READ_NVRAM, sc->sc_buf_phys,
209                     amnt, uio->uio_offset);
210                 if (rv != OPAL_SUCCESS) {
211                         switch (rv) {
212                         case OPAL_HARDWARE:
213                                 rv = EIO;
214                                 break;
215                         case OPAL_PARAMETER:
216                                 rv = EINVAL;
217                                 break;
218                         }
219                         break;
220                 }
221                 rv = uiomove(sc->sc_buf, amnt, uio);
222                 if (rv != 0)
223                         break;
224         }
225         return (rv);
226 }
227
228 static int
229 opal_nvram_write(struct cdev *dev, struct uio *uio, int ioflag)
230 {
231         off_t offset;
232         int rv, amnt;
233         struct opal_nvram_softc *sc = dev->si_drv1;
234
235         rv = 0;
236         while (uio->uio_resid > 0) {
237                 amnt = MIN(uio->uio_resid, sc->sc_size - uio->uio_offset);
238                 amnt = MIN(amnt, NVRAM_BUFSIZE);
239                 if (amnt == 0) {
240                         rv = ENOSPC;
241                         break;
242                 }
243                 offset = uio->uio_offset;
244                 rv = uiomove(sc->sc_buf, amnt, uio);
245                 if (rv != 0)
246                         break;
247                 rv = opal_call(OPAL_WRITE_NVRAM, sc->sc_buf_phys, amnt,
248                     offset);
249                 if (rv != OPAL_SUCCESS) {
250                         switch (rv) {
251                         case OPAL_HARDWARE:
252                                 rv = EIO;
253                                 break;
254                         case OPAL_PARAMETER:
255                                 rv = EINVAL;
256                                 break;
257                         }
258                         break;
259                 }
260         }
261         return (rv);
262 }
263
264 static int
265 opal_nvram_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
266     struct thread *td)
267 {
268         struct opal_nvram_softc *sc = dev->si_drv1;
269
270         switch (cmd) {
271         case DIOCGMEDIASIZE:
272                 *(off_t *)data = sc->sc_size;
273                 return (0);
274         }
275         return (EINVAL);
276 }