ofw_cpu.c revision 255378
1250323Sdteske/*-
2250323Sdteske * Copyright (C) 2009 Nathan Whitehorn
3250323Sdteske * All rights reserved.
4252980Sdteske *
5250323Sdteske * Redistribution and use in source and binary forms, with or without
6250323Sdteske * modification, are permitted provided that the following conditions
7250323Sdteske * are met:
8250323Sdteske * 1. Redistributions of source code must retain the above copyright
9250323Sdteske *    notice, this list of conditions and the following disclaimer.
10250323Sdteske * 2. Redistributions in binary form must reproduce the above copyright
11250323Sdteske *    notice, this list of conditions and the following disclaimer in the
12250323Sdteske *    documentation and/or other materials provided with the distribution.
13250323Sdteske *
14250323Sdteske * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15250323Sdteske * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16252987Sdteske * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17250323Sdteske * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18250323Sdteske * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19250323Sdteske * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20252987Sdteske * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21250323Sdteske * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22250323Sdteske * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23250323Sdteske * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24250323Sdteske */
25250323Sdteske
26250323Sdteske#include <sys/cdefs.h>
27250323Sdteske__FBSDID("$FreeBSD: head/sys/powerpc/ofw/ofw_cpu.c 255378 2013-09-07 20:52:31Z nwhitehorn $");
28250323Sdteske
29250323Sdteske#include <sys/param.h>
30250323Sdteske#include <sys/systm.h>
31250323Sdteske#include <sys/kernel.h>
32250323Sdteske#include <sys/module.h>
33250323Sdteske#include <sys/malloc.h>
34250323Sdteske#include <sys/bus.h>
35252745Sdteske#include <sys/cpu.h>
36252745Sdteske#include <machine/bus.h>
37250323Sdteske
38250323Sdteske#include <dev/ofw/openfirm.h>
39252077Sdteske#include <dev/ofw/ofw_bus.h>
40250323Sdteske#include <dev/ofw/ofw_bus_subr.h>
41250323Sdteske
42250323Sdteskestatic int	ofw_cpulist_probe(device_t);
43250323Sdteskestatic int	ofw_cpulist_attach(device_t);
44250323Sdteskestatic const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev,
45250323Sdteske    device_t child);
46250323Sdteske
47250323Sdteskestatic MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information");
48250323Sdteske
49250323Sdteskestatic device_method_t ofw_cpulist_methods[] = {
50250323Sdteske	/* Device interface */
51250323Sdteske	DEVMETHOD(device_probe,		ofw_cpulist_probe),
52250323Sdteske	DEVMETHOD(device_attach,	ofw_cpulist_attach),
53252740Sdteske
54252745Sdteske	/* Bus interface */
55252745Sdteske	DEVMETHOD(bus_add_child,	bus_generic_add_child),
56257795Sdteske	DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
57252745Sdteske
58252745Sdteske	/* ofw_bus interface */
59252740Sdteske	DEVMETHOD(ofw_bus_get_devinfo,	ofw_cpulist_get_devinfo),
60252740Sdteske	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
61252745Sdteske	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
62252740Sdteske	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
63252740Sdteske	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
64250323Sdteske	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
65250323Sdteske
66250323Sdteske	DEVMETHOD_END
67250323Sdteske};
68250323Sdteske
69250323Sdteskestatic driver_t ofw_cpulist_driver = {
70250323Sdteske	"cpulist",
71250323Sdteske	ofw_cpulist_methods,
72250323Sdteske	0
73250323Sdteske};
74250323Sdteske
75250323Sdteskestatic devclass_t ofw_cpulist_devclass;
76250323Sdteske
77250323SdteskeDRIVER_MODULE(ofw_cpulist, nexus, ofw_cpulist_driver, ofw_cpulist_devclass,
78250323Sdteske    0, 0);
79250323Sdteske
80250323Sdteskestatic int
81250323Sdteskeofw_cpulist_probe(device_t dev)
82250323Sdteske{
83250323Sdteske	const char	*name;
84250323Sdteske
85250323Sdteske	name = ofw_bus_get_name(dev);
86250323Sdteske
87251355Sdteske	if (name == NULL || strcmp(name, "cpus") != 0)
88250323Sdteske		return (ENXIO);
89250323Sdteske
90251355Sdteske	device_set_desc(dev, "Open Firmware CPU Group");
91250323Sdteske
92250323Sdteske	return (0);
93251355Sdteske}
94250538Sdteske
95250323Sdteskestatic int
96250323Sdteskeofw_cpulist_attach(device_t dev)
97250323Sdteske{
98250538Sdteske	phandle_t root, child;
99250538Sdteske	device_t cdev;
100250538Sdteske	struct ofw_bus_devinfo *dinfo;
101250538Sdteske
102251354Sdteske	root = ofw_bus_get_node(dev);
103250323Sdteske
104250323Sdteske	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
105250323Sdteske		dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO);
106250538Sdteske
107250538Sdteske                if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
108250538Sdteske                        free(dinfo, M_OFWCPU);
109250538Sdteske                        continue;
110251354Sdteske                }
111250323Sdteske                cdev = device_add_child(dev, NULL, -1);
112251354Sdteske                if (cdev == NULL) {
113251355Sdteske                        device_printf(dev, "<%s>: device_add_child failed\n",
114250538Sdteske                            dinfo->obd_name);
115250323Sdteske                        ofw_bus_gen_destroy_devinfo(dinfo);
116250323Sdteske                        free(dinfo, M_OFWCPU);
117251355Sdteske                        continue;
118250323Sdteske                }
119250323Sdteske		device_set_ivars(cdev, dinfo);
120250323Sdteske	}
121250323Sdteske
122250323Sdteske	return (bus_generic_attach(dev));
123250323Sdteske}
124250323Sdteske
125250323Sdteskestatic const struct ofw_bus_devinfo *
126250323Sdteskeofw_cpulist_get_devinfo(device_t dev, device_t child)
127250323Sdteske{
128250323Sdteske	return (device_get_ivars(child));
129250323Sdteske}
130250323Sdteske
131250323Sdteskestatic int	ofw_cpu_probe(device_t);
132250323Sdteskestatic int	ofw_cpu_attach(device_t);
133250323Sdteskestatic int	ofw_cpu_read_ivar(device_t dev, device_t child, int index,
134250323Sdteske    uintptr_t *result);
135256181Sdteske
136250323Sdteskestruct ofw_cpu_softc {
137250323Sdteske	struct pcpu	*sc_cpu_pcpu;
138252771Sdteske	uint32_t	 sc_nominal_mhz;
139250323Sdteske};
140250323Sdteske
141250323Sdteskestatic device_method_t ofw_cpu_methods[] = {
142250323Sdteske	/* Device interface */
143250323Sdteske	DEVMETHOD(device_probe,		ofw_cpu_probe),
144250323Sdteske	DEVMETHOD(device_attach,	ofw_cpu_attach),
145250323Sdteske
146250323Sdteske	/* Bus interface */
147250323Sdteske	DEVMETHOD(bus_add_child,	bus_generic_add_child),
148250323Sdteske	DEVMETHOD(bus_read_ivar,	ofw_cpu_read_ivar),
149250323Sdteske	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
150250323Sdteske	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
151250323Sdteske	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
152250323Sdteske	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
153250323Sdteske	DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
154250323Sdteske
155250323Sdteske	DEVMETHOD_END
156250323Sdteske};
157250323Sdteske
158250323Sdteskestatic driver_t ofw_cpu_driver = {
159250323Sdteske	"cpu",
160250323Sdteske	ofw_cpu_methods,
161252771Sdteske	sizeof(struct ofw_cpu_softc)
162250323Sdteske};
163250323Sdteske
164250323Sdteskestatic devclass_t ofw_cpu_devclass;
165250323Sdteske
166250323SdteskeDRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, ofw_cpu_devclass, 0, 0);
167257795Sdteske
168250323Sdteskestatic int
169250323Sdteskeofw_cpu_probe(device_t dev)
170250323Sdteske{
171250323Sdteske	const char *type = ofw_bus_get_type(dev);
172257795Sdteske
173257795Sdteske	if (strcmp(type, "cpu") != 0)
174250323Sdteske		return (ENXIO);
175250323Sdteske
176250323Sdteske	device_set_desc(dev, "Open Firmware CPU");
177250323Sdteske	return (0);
178250323Sdteske}
179250323Sdteske
180250323Sdteskestatic int
181250323Sdteskeofw_cpu_attach(device_t dev)
182250323Sdteske{
183250323Sdteske	struct ofw_cpu_softc *sc;
184250323Sdteske	uint32_t cell;
185250323Sdteske
186250323Sdteske	sc = device_get_softc(dev);
187250323Sdteske	OF_getprop(ofw_bus_get_node(dev), "reg", &cell, sizeof(cell));
188250323Sdteske	sc->sc_cpu_pcpu = pcpu_find(cell);
189250323Sdteske	OF_getprop(ofw_bus_get_node(dev), "clock-frequency", &cell, sizeof(cell));
190250323Sdteske	sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */
191250323Sdteske
192250323Sdteske	bus_generic_probe(dev);
193250323Sdteske	return (bus_generic_attach(dev));
194250323Sdteske}
195250323Sdteske
196250323Sdteskestatic int
197250323Sdteskeofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
198250323Sdteske{
199250323Sdteske	struct ofw_cpu_softc *sc;
200250323Sdteske
201250323Sdteske	sc = device_get_softc(dev);
202250323Sdteske
203250323Sdteske	switch (index) {
204250323Sdteske	case CPU_IVAR_PCPU:
205250323Sdteske		*result = (uintptr_t)sc->sc_cpu_pcpu;
206250323Sdteske		return (0);
207250323Sdteske	case CPU_IVAR_NOMINAL_MHZ:
208250323Sdteske		*result = (uintptr_t)sc->sc_nominal_mhz;
209250323Sdteske		return (0);
210250323Sdteske	}
211252178Sdteske
212250323Sdteske	return (ENOENT);
213250323Sdteske}
214250323Sdteske
215250323Sdteske