vdevice.c revision 273675
11708Sstevel/*-
21708Sstevel * Copyright (c) 2011 Nathan Whitehorn
31708Sstevel * All rights reserved.
41708Sstevel *
51708Sstevel * Redistribution and use in source and binary forms, with or without
61708Sstevel * modification, are permitted provided that the following conditions
71708Sstevel * are met:
81708Sstevel * 1. Redistributions of source code must retain the above copyright
91708Sstevel *    notice, this list of conditions and the following disclaimer.
101708Sstevel * 2. Redistributions in binary form must reproduce the above copyright
111708Sstevel *    notice, this list of conditions and the following disclaimer in the
121708Sstevel *    documentation and/or other materials provided with the distribution.
131708Sstevel *
141708Sstevel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151708Sstevel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161708Sstevel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171708Sstevel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181708Sstevel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191708Sstevel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201708Sstevel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211708Sstevel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
226954Smb158278 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231708Sstevel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241708Sstevel * SUCH DAMAGE.
251708Sstevel */
261708Sstevel
271708Sstevel#include <sys/cdefs.h>
281708Sstevel__FBSDID("$FreeBSD: stable/10/sys/powerpc/pseries/vdevice.c 273675 2014-10-26 04:01:57Z ian $");
291708Sstevel
301708Sstevel#include <sys/param.h>
311708Sstevel#include <sys/systm.h>
321708Sstevel#include <sys/kernel.h>
331708Sstevel#include <sys/module.h>
341708Sstevel#include <sys/malloc.h>
351708Sstevel#include <sys/bus.h>
361708Sstevel#include <sys/cpu.h>
371708Sstevel#include <machine/bus.h>
381708Sstevel#include <machine/intr_machdep.h>
391708Sstevel
401708Sstevel#include <dev/ofw/openfirm.h>
411708Sstevel#include <dev/ofw/ofw_bus.h>
421708Sstevel#include <dev/ofw/ofw_bus_subr.h>
431708Sstevel
441708Sstevel#include <powerpc/pseries/plpar_iommu.h>
451708Sstevel
461708Sstevel#include "iommu_if.h"
471708Sstevel
481708Sstevelstatic int	vdevice_probe(device_t);
491708Sstevelstatic int	vdevice_attach(device_t);
501708Sstevelstatic const struct ofw_bus_devinfo *vdevice_get_devinfo(device_t dev,
511708Sstevel    device_t child);
521708Sstevelstatic int	vdevice_print_child(device_t dev, device_t child);
531708Sstevelstatic struct resource_list *vdevice_get_resource_list(device_t, device_t);
541708Sstevelstatic bus_dma_tag_t vdevice_get_dma_tag(device_t dev, device_t child);
551708Sstevel
561708Sstevel/*
573013Sanovick * VDevice devinfo
583156Sgirish */
591708Sstevelstruct vdevice_devinfo {
601708Sstevel	struct ofw_bus_devinfo mdi_obdinfo;
611708Sstevel	struct resource_list mdi_resources;
621708Sstevel	bus_dma_tag_t mdi_dma_tag;
631708Sstevel};
641708Sstevel
651708Sstevelstatic device_method_t vdevice_methods[] = {
661708Sstevel	/* Device interface */
671708Sstevel	DEVMETHOD(device_probe,		vdevice_probe),
681708Sstevel	DEVMETHOD(device_attach,	vdevice_attach),
691708Sstevel
701708Sstevel	/* Bus interface */
711708Sstevel	DEVMETHOD(bus_add_child,	bus_generic_add_child),
721708Sstevel	DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
731708Sstevel	DEVMETHOD(bus_print_child,	vdevice_print_child),
741708Sstevel	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
751708Sstevel	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
761708Sstevel	DEVMETHOD(bus_alloc_resource,	bus_generic_rl_alloc_resource),
771708Sstevel	DEVMETHOD(bus_release_resource,	bus_generic_rl_release_resource),
781708Sstevel	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
791708Sstevel	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
801708Sstevel	DEVMETHOD(bus_get_resource_list, vdevice_get_resource_list),
811708Sstevel
821708Sstevel	/* ofw_bus interface */
831708Sstevel	DEVMETHOD(ofw_bus_get_devinfo,	vdevice_get_devinfo),
841708Sstevel	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
851708Sstevel	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
861708Sstevel	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
871708Sstevel	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
881708Sstevel	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
891708Sstevel
901708Sstevel	/* IOMMU interface */
914017Smb158278	DEVMETHOD(bus_get_dma_tag,	vdevice_get_dma_tag),
921708Sstevel	DEVMETHOD(iommu_map,		phyp_iommu_map),
931708Sstevel	DEVMETHOD(iommu_unmap,		phyp_iommu_unmap),
941708Sstevel
951708Sstevel	DEVMETHOD_END
961708Sstevel};
971708Sstevel
981708Sstevelstatic driver_t vdevice_driver = {
991708Sstevel	"vdevice",
1001708Sstevel	vdevice_methods,
1011708Sstevel	0
1024017Smb158278};
1034017Smb158278
1044017Smb158278static devclass_t vdevice_devclass;
1054017Smb158278
1064017Smb158278DRIVER_MODULE(vdevice, ofwbus, vdevice_driver, vdevice_devclass, 0, 0);
1071708Sstevel
1081708Sstevelstatic int
1094017Smb158278vdevice_probe(device_t dev)
1104017Smb158278{
1114017Smb158278	const char	*name;
1124017Smb158278
1134017Smb158278	name = ofw_bus_get_name(dev);
1144017Smb158278
1154017Smb158278	if (name == NULL || strcmp(name, "vdevice") != 0)
1164017Smb158278		return (ENXIO);
1174017Smb158278
1184017Smb158278	if (!ofw_bus_is_compatible(dev, "IBM,vdevice"))
1194017Smb158278		return (ENXIO);
1204017Smb158278
1214017Smb158278	device_set_desc(dev, "POWER Hypervisor Virtual Device Root");
1224017Smb158278
1234017Smb158278	return (0);
1244017Smb158278}
1251708Sstevel
1261708Sstevelstatic int
1271708Sstevelvdevice_attach(device_t dev)
1281708Sstevel{
1291708Sstevel	phandle_t root, child;
1301708Sstevel	device_t cdev;
1311708Sstevel	struct vdevice_devinfo *dinfo;
1321708Sstevel
1331708Sstevel	root = ofw_bus_get_node(dev);
1341708Sstevel
1351708Sstevel	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
1361708Sstevel		dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
1371708Sstevel
1381708Sstevel                if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo,
1391708Sstevel		    child) != 0) {
1401708Sstevel                        free(dinfo, M_DEVBUF);
1411708Sstevel                        continue;
1421708Sstevel                }
1431708Sstevel		resource_list_init(&dinfo->mdi_resources);
1441708Sstevel
1451708Sstevel		ofw_bus_intr_to_rl(dev, child, &dinfo->mdi_resources);
1461708Sstevel
1471708Sstevel                cdev = device_add_child(dev, NULL, -1);
1481708Sstevel                if (cdev == NULL) {
1491708Sstevel                        device_printf(dev, "<%s>: device_add_child failed\n",
1501708Sstevel                            dinfo->mdi_obdinfo.obd_name);
1511708Sstevel                        ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
1521708Sstevel                        free(dinfo, M_DEVBUF);
1531708Sstevel                        continue;
1541708Sstevel                }
1551708Sstevel		device_set_ivars(cdev, dinfo);
1561708Sstevel	}
1571708Sstevel
1581708Sstevel	return (bus_generic_attach(dev));
1591708Sstevel}
1601708Sstevel
1611708Sstevelstatic const struct ofw_bus_devinfo *
1621708Sstevelvdevice_get_devinfo(device_t dev, device_t child)
1631708Sstevel{
1641708Sstevel	return (device_get_ivars(child));
1651708Sstevel}
1661708Sstevel
1671708Sstevelstatic int
1681708Sstevelvdevice_print_child(device_t dev, device_t child)
1691708Sstevel{
1701708Sstevel	struct vdevice_devinfo *dinfo;
1711708Sstevel	struct resource_list *rl;
1721708Sstevel	int retval = 0;
1731708Sstevel
1741708Sstevel	dinfo = device_get_ivars(child);
1751708Sstevel	rl = &dinfo->mdi_resources;
1761708Sstevel
1771708Sstevel	retval += bus_print_child_header(dev, child);
1781708Sstevel
1791708Sstevel	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
1801708Sstevel
1811708Sstevel	retval += bus_print_child_footer(dev, child);
1824017Smb158278
1834017Smb158278	return (retval);
1844017Smb158278}
1854017Smb158278
1864017Smb158278static struct resource_list *
1874017Smb158278vdevice_get_resource_list (device_t dev, device_t child)
1881708Sstevel{
1891708Sstevel        struct vdevice_devinfo *dinfo;
1901708Sstevel
1911708Sstevel        dinfo = device_get_ivars(child);
1921708Sstevel        return (&dinfo->mdi_resources);
1931708Sstevel}
1941708Sstevel
1951708Sstevelstatic bus_dma_tag_t
1961708Sstevelvdevice_get_dma_tag(device_t dev, device_t child)
1971708Sstevel{
1981708Sstevel	struct vdevice_devinfo *dinfo;
1991708Sstevel	while (child != NULL && device_get_parent(child) != dev)
2001708Sstevel		child = device_get_parent(child);
2011708Sstevel        dinfo = device_get_ivars(child);
2021708Sstevel
2034017Smb158278	if (dinfo->mdi_dma_tag == NULL) {
2041708Sstevel		bus_dma_tag_create(bus_get_dma_tag(dev),
2051708Sstevel		    1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
2061708Sstevel		    NULL, NULL, BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED,
2071708Sstevel		    BUS_SPACE_MAXSIZE, 0, NULL, NULL, &dinfo->mdi_dma_tag);
2081708Sstevel		phyp_iommu_set_dma_tag(dev, child, dinfo->mdi_dma_tag);
2091708Sstevel	}
2101708Sstevel
2111708Sstevel        return (dinfo->mdi_dma_tag);
2121708Sstevel}
2131708Sstevel
2141708Sstevel