Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/powernv/opal_nvram.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
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
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/disk.h>
34
#include <sys/kernel.h>
35
#include <sys/mutex.h>
36
#include <sys/uio.h>
37
38
#include <dev/ofw/openfirm.h>
39
#include <dev/ofw/ofw_bus.h>
40
#include <dev/ofw/ofw_bus_subr.h>
41
42
#include <machine/bus.h>
43
#include <machine/md_var.h>
44
#include <machine/pio.h>
45
#include <machine/resource.h>
46
47
#include "opal.h"
48
49
#include <sys/rman.h>
50
51
#include <vm/vm.h>
52
#include <vm/pmap.h>
53
54
#define NVRAM_BUFSIZE (65536) /* 64k blocks */
55
56
struct opal_nvram_softc {
57
device_t sc_dev;
58
struct mtx sc_mtx;
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
#define NVRAM_LOCK(sc) mtx_lock(&sc->sc_mtx)
68
#define NVRAM_UNLOCK(sc) mtx_unlock(&sc->sc_mtx)
69
70
/*
71
* Device interface.
72
*/
73
static int opal_nvram_probe(device_t);
74
static int opal_nvram_attach(device_t);
75
static int opal_nvram_detach(device_t);
76
77
/*
78
* Driver methods.
79
*/
80
static device_method_t opal_nvram_methods[] = {
81
/* Device interface */
82
DEVMETHOD(device_probe, opal_nvram_probe),
83
DEVMETHOD(device_attach, opal_nvram_attach),
84
DEVMETHOD(device_detach, opal_nvram_detach),
85
{ 0, 0 }
86
};
87
88
static driver_t opal_nvram_driver = {
89
"opal_nvram",
90
opal_nvram_methods,
91
sizeof(struct opal_nvram_softc)
92
};
93
94
DRIVER_MODULE(opal_nvram, opal, opal_nvram_driver, 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_open = opal_nvram_open,
109
.d_close = opal_nvram_close,
110
.d_read = opal_nvram_read,
111
.d_write = opal_nvram_write,
112
.d_ioctl = opal_nvram_ioctl,
113
.d_name = "nvram",
114
};
115
116
static int
117
opal_nvram_probe(device_t dev)
118
{
119
120
if (!ofw_bus_is_compatible(dev, "ibm,opal-nvram"))
121
return (ENXIO);
122
123
device_set_desc(dev, "OPAL NVRAM");
124
return (BUS_PROBE_DEFAULT);
125
}
126
127
static int
128
opal_nvram_attach(device_t dev)
129
{
130
struct opal_nvram_softc *sc;
131
phandle_t node;
132
int err;
133
134
node = ofw_bus_get_node(dev);
135
sc = device_get_softc(dev);
136
137
sc->sc_dev = dev;
138
139
err = OF_getencprop(node, "#bytes", &sc->sc_size,
140
sizeof(sc->sc_size));
141
142
if (err < 0)
143
return (ENXIO);
144
145
sc->sc_buf = contigmalloc(NVRAM_BUFSIZE, M_DEVBUF, M_WAITOK,
146
0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
147
if (sc->sc_buf == NULL) {
148
device_printf(dev, "No memory for buffer.\n");
149
return (ENXIO);
150
}
151
sc->sc_buf_phys = pmap_kextract((vm_offset_t)sc->sc_buf);
152
sc->sc_cdev = make_dev(&opal_nvram_cdevsw, 0, 0, 0, 0600,
153
"nvram");
154
sc->sc_cdev->si_drv1 = sc;
155
156
mtx_init(&sc->sc_mtx, "opal_nvram", 0, MTX_DEF);
157
158
return (0);
159
}
160
161
static int
162
opal_nvram_detach(device_t dev)
163
{
164
struct opal_nvram_softc *sc;
165
166
sc = device_get_softc(dev);
167
168
if (sc->sc_cdev != NULL)
169
destroy_dev(sc->sc_cdev);
170
free(sc->sc_buf, M_DEVBUF);
171
172
mtx_destroy(&sc->sc_mtx);
173
174
return (0);
175
}
176
177
static int
178
opal_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td)
179
{
180
struct opal_nvram_softc *sc = dev->si_drv1;
181
int err;
182
183
err = 0;
184
185
NVRAM_LOCK(sc);
186
if (sc->sc_isopen)
187
err = EBUSY;
188
else
189
sc->sc_isopen = 1;
190
NVRAM_UNLOCK(sc);
191
192
return (err);
193
}
194
195
static int
196
opal_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
197
{
198
struct opal_nvram_softc *sc = dev->si_drv1;
199
200
NVRAM_LOCK(sc);
201
sc->sc_isopen = 0;
202
NVRAM_UNLOCK(sc);
203
204
return (0);
205
}
206
207
static int
208
opal_nvram_read(struct cdev *dev, struct uio *uio, int ioflag)
209
{
210
struct opal_nvram_softc *sc = dev->si_drv1;
211
int rv, amnt;
212
213
rv = 0;
214
215
NVRAM_LOCK(sc);
216
while (uio->uio_resid > 0) {
217
amnt = MIN(uio->uio_resid, sc->sc_size - uio->uio_offset);
218
amnt = MIN(amnt, NVRAM_BUFSIZE);
219
if (amnt == 0)
220
break;
221
222
rv = opal_call(OPAL_READ_NVRAM, sc->sc_buf_phys,
223
amnt, uio->uio_offset);
224
if (rv != OPAL_SUCCESS) {
225
switch (rv) {
226
case OPAL_HARDWARE:
227
rv = EIO;
228
break;
229
case OPAL_PARAMETER:
230
rv = EINVAL;
231
break;
232
}
233
break;
234
}
235
rv = uiomove(sc->sc_buf, amnt, uio);
236
if (rv != 0)
237
break;
238
}
239
NVRAM_UNLOCK(sc);
240
241
return (rv);
242
}
243
244
static int
245
opal_nvram_write(struct cdev *dev, struct uio *uio, int ioflag)
246
{
247
off_t offset;
248
int rv, amnt;
249
struct opal_nvram_softc *sc = dev->si_drv1;
250
251
rv = 0;
252
253
NVRAM_LOCK(sc);
254
while (uio->uio_resid > 0) {
255
amnt = MIN(uio->uio_resid, sc->sc_size - uio->uio_offset);
256
amnt = MIN(amnt, NVRAM_BUFSIZE);
257
if (amnt == 0) {
258
rv = ENOSPC;
259
break;
260
}
261
offset = uio->uio_offset;
262
rv = uiomove(sc->sc_buf, amnt, uio);
263
if (rv != 0)
264
break;
265
rv = opal_call(OPAL_WRITE_NVRAM, sc->sc_buf_phys, amnt,
266
offset);
267
if (rv != OPAL_SUCCESS) {
268
switch (rv) {
269
case OPAL_HARDWARE:
270
rv = EIO;
271
break;
272
case OPAL_PARAMETER:
273
rv = EINVAL;
274
break;
275
}
276
break;
277
}
278
}
279
280
NVRAM_UNLOCK(sc);
281
282
return (rv);
283
}
284
285
static int
286
opal_nvram_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
287
struct thread *td)
288
{
289
struct opal_nvram_softc *sc = dev->si_drv1;
290
291
switch (cmd) {
292
case DIOCGMEDIASIZE:
293
*(off_t *)data = sc->sc_size;
294
return (0);
295
}
296
return (EINVAL);
297
}
298
299