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