Index: stable/10/sys/conf/files.powerpc =================================================================== --- stable/10/sys/conf/files.powerpc (revision 283476) +++ stable/10/sys/conf/files.powerpc (revision 283477) @@ -1,247 +1,249 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # # font.h optional sc \ compile-with "uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ no-obj no-implicit-rule before-depend \ clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8" # # There is only an asm version on ppc64. cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs powerpc compile-with "${ZFS_C}" cddl/contrib/opensolaris/common/atomic/powerpc64/opensolaris_atomic.S optional zfs powerpc64 compile-with "${ZFS_S}" crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/bm/if_bm.c optional bm powermac dev/adb/adb_bus.c optional adb dev/adb/adb_kbd.c optional adb dev/adb/adb_mouse.c optional adb dev/adb/adb_hb_if.m optional adb dev/adb/adb_if.m optional adb dev/adb/adb_buttons.c optional adb dev/agp/agp_apple.c optional agp powermac dev/fb/fb.c optional sc dev/fdt/fdt_powerpc.c optional fdt +# ofwbus depends on simplebus. +dev/fdt/simplebus.c optional aim | fdt dev/hwpmc/hwpmc_powerpc.c optional hwpmc dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc dev/hwpmc/hwpmc_ppc970.c optional hwpmc dev/iicbus/ad7417.c optional ad7417 powermac dev/iicbus/adt746x.c optional adt746x powermac dev/iicbus/ds1631.c optional ds1631 powermac dev/iicbus/ds1775.c optional ds1775 powermac dev/iicbus/max6690.c optional max6690 powermac dev/kbd/kbd.c optional sc | vt dev/nand/nfc_fsl.c optional nand mpc85xx # ofw can be either aim or fdt: fdt case handled in files. aim only powerpc specific. dev/ofw/openfirm.c optional aim dev/ofw/openfirmio.c optional aim dev/ofw/ofw_bus_if.m optional aim dev/ofw/ofw_cpu.c optional aim dev/ofw/ofw_if.m optional aim dev/ofw/ofw_bus_subr.c optional aim dev/ofw/ofw_console.c optional aim dev/ofw/ofw_disk.c optional ofwd aim dev/ofw/ofw_iicbus.c optional iicbus aim dev/ofw/ofwbus.c optional aim | fdt dev/ofw/ofw_standard.c optional aim powerpc dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx dev/scc/scc_bfe_macio.c optional scc powermac dev/sec/sec.c optional sec mpc85xx dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac dev/sound/macio/davbus.c optional snd_davbus powermac dev/sound/macio/i2s.c optional snd_ai2s powermac dev/sound/macio/onyx.c optional snd_ai2s iicbus powermac dev/sound/macio/snapper.c optional snd_ai2s iicbus powermac dev/sound/macio/tumbler.c optional snd_ai2s iicbus powermac dev/syscons/scgfbrndr.c optional sc dev/syscons/scterm-teken.c optional sc dev/syscons/scvtb.c optional sc dev/tsec/if_tsec.c optional tsec dev/tsec/if_tsec_fdt.c optional tsec fdt dev/uart/uart_cpu_powerpc.c optional uart dev/usb/controller/ehci_fsl.c optional ehci mpc85xx dev/vt/hw/ofwfb/ofwfb.c optional vt aim kern/kern_clocksource.c standard kern/subr_dummy_vdso_tc.c standard kern/syscalls.c optional ktr libkern/ashldi3.c optional powerpc libkern/ashrdi3.c optional powerpc libkern/bcmp.c standard libkern/cmpdi2.c optional powerpc libkern/divdi3.c optional powerpc libkern/ffs.c standard libkern/ffsl.c standard libkern/fls.c standard libkern/flsl.c standard libkern/lshrdi3.c optional powerpc libkern/memmove.c standard libkern/memset.c standard libkern/moddi3.c optional powerpc libkern/qdivrem.c optional powerpc libkern/ucmpdi2.c optional powerpc libkern/udivdi3.c optional powerpc libkern/umoddi3.c optional powerpc powerpc/aim/interrupt.c optional aim powerpc/aim/locore.S optional aim no-obj powerpc/aim/machdep.c optional aim powerpc/aim/mmu_oea.c optional aim powerpc powerpc/aim/mmu_oea64.c optional aim powerpc/aim/moea64_if.m optional aim powerpc/aim/moea64_native.c optional aim powerpc/aim/mp_cpudep.c optional aim powerpc/aim/slb.c optional aim powerpc64 powerpc/aim/trap.c optional aim powerpc/aim/uma_machdep.c optional aim powerpc/booke/interrupt.c optional booke powerpc/booke/locore.S optional booke no-obj powerpc/booke/machdep.c optional booke powerpc/booke/machdep_e500.c optional booke_e500 powerpc/booke/mp_cpudep.c optional booke smp powerpc/booke/platform_bare.c optional booke powerpc/booke/pmap.c optional booke powerpc/booke/trap.c optional booke powerpc/cpufreq/dfs.c optional cpufreq powerpc/cpufreq/pcr.c optional cpufreq aim powerpc/cpufreq/pmufreq.c optional cpufreq aim pmu powerpc/fpu/fpu_add.c optional fpu_emu powerpc/fpu/fpu_compare.c optional fpu_emu powerpc/fpu/fpu_div.c optional fpu_emu powerpc/fpu/fpu_emu.c optional fpu_emu powerpc/fpu/fpu_explode.c optional fpu_emu powerpc/fpu/fpu_implode.c optional fpu_emu powerpc/fpu/fpu_mul.c optional fpu_emu powerpc/fpu/fpu_sqrt.c optional fpu_emu powerpc/fpu/fpu_subr.c optional fpu_emu powerpc/mambo/mambocall.S optional mambo powerpc/mambo/mambo.c optional mambo powerpc/mambo/mambo_console.c optional mambo powerpc/mambo/mambo_disk.c optional mambo powerpc/mpc85xx/atpic.c optional mpc85xx isa powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 fdt powerpc/mpc85xx/ds1553_core.c optional ds1553 powerpc/mpc85xx/i2c.c optional iicbus fdt powerpc/mpc85xx/isa.c optional mpc85xx isa powerpc/mpc85xx/lbc.c optional mpc85xx powerpc/mpc85xx/mpc85xx.c optional mpc85xx powerpc/mpc85xx/platform_mpc85xx.c optional mpc85xx powerpc/mpc85xx/pci_mpc85xx.c optional pci mpc85xx powerpc/ofw/ofw_machdep.c standard powerpc/ofw/ofw_pci.c optional pci powerpc/ofw/ofw_pcibus.c optional pci powerpc/ofw/ofw_pcib_pci.c optional pci powerpc/ofw/ofw_real.c optional aim powerpc/ofw/ofw_syscons.c optional sc aim powerpc/ofw/ofwcall32.S optional aim powerpc powerpc/ofw/ofwcall64.S optional aim powerpc64 powerpc/ofw/ofwmagic.S optional aim powerpc/ofw/openpic_ofw.c optional aim | fdt powerpc/ofw/rtas.c optional aim powerpc/powermac/ata_kauai.c optional powermac ata | powermac atamacio powerpc/powermac/ata_macio.c optional powermac ata | powermac atamacio powerpc/powermac/ata_dbdma.c optional powermac ata | powermac atamacio powerpc/powermac/atibl.c optional powermac atibl powerpc/powermac/cuda.c optional powermac cuda powerpc/powermac/cpcht.c optional powermac pci powerpc/powermac/dbdma.c optional powermac pci powerpc/powermac/fcu.c optional powermac fcu powerpc/powermac/grackle.c optional powermac pci powerpc/powermac/hrowpic.c optional powermac pci powerpc/powermac/kiic.c optional powermac kiic powerpc/powermac/macgpio.c optional powermac pci powerpc/powermac/macio.c optional powermac pci powerpc/powermac/nvbl.c optional powermac nvbl powerpc/powermac/platform_powermac.c optional powermac powerpc/powermac/powermac_thermal.c optional powermac powerpc/powermac/pswitch.c optional powermac pswitch powerpc/powermac/pmu.c optional powermac pmu powerpc/powermac/smu.c optional powermac smu powerpc/powermac/smusat.c optional powermac smu powerpc/powermac/uninorth.c optional powermac powerpc/powermac/uninorthpci.c optional powermac pci powerpc/powermac/vcoregpio.c optional powermac powerpc/powermac/windtunnel.c optional powermac windtunnel powerpc/powerpc/altivec.c standard powerpc/powerpc/autoconf.c standard powerpc/powerpc/bcopy.c standard powerpc/powerpc/bus_machdep.c standard powerpc/powerpc/busdma_machdep.c standard powerpc/powerpc/clock.c standard powerpc/powerpc/copyinout.c standard powerpc/powerpc/copystr.c standard powerpc/powerpc/cpu.c standard powerpc/powerpc/db_disasm.c optional ddb powerpc/powerpc/db_hwwatch.c optional ddb powerpc/powerpc/db_interface.c optional ddb powerpc/powerpc/db_trace.c optional ddb powerpc/powerpc/dump_machdep.c standard powerpc/powerpc/elf32_machdep.c optional powerpc | compat_freebsd32 powerpc/powerpc/elf64_machdep.c optional powerpc64 powerpc/powerpc/exec_machdep.c standard powerpc/powerpc/fpu.c standard powerpc/powerpc/fuswintr.c standard powerpc/powerpc/gdb_machdep.c optional gdb powerpc/powerpc/in_cksum.c optional inet | inet6 powerpc/powerpc/intr_machdep.c standard powerpc/powerpc/iommu_if.m standard powerpc/powerpc/mem.c optional mem powerpc/powerpc/mmu_if.m standard powerpc/powerpc/mp_machdep.c optional smp powerpc/powerpc/nexus.c standard powerpc/powerpc/openpic.c standard powerpc/powerpc/pic_if.m standard powerpc/powerpc/pmap_dispatch.c standard powerpc/powerpc/platform.c standard powerpc/powerpc/platform_if.m standard powerpc/powerpc/sc_machdep.c optional sc powerpc/powerpc/setjmp.S standard powerpc/powerpc/sigcode32.S optional powerpc | compat_freebsd32 powerpc/powerpc/sigcode64.S optional powerpc64 powerpc/powerpc/swtch32.S optional powerpc powerpc/powerpc/swtch64.S optional powerpc64 powerpc/powerpc/stack_machdep.c optional ddb | stack powerpc/powerpc/suswintr.c standard powerpc/powerpc/syncicache.c standard powerpc/powerpc/sys_machdep.c standard powerpc/powerpc/uio_machdep.c standard powerpc/powerpc/vm_machdep.c standard powerpc/ps3/ehci_ps3.c optional ps3 ehci powerpc/ps3/ohci_ps3.c optional ps3 ohci powerpc/ps3/if_glc.c optional ps3 glc powerpc/ps3/mmu_ps3.c optional ps3 powerpc/ps3/platform_ps3.c optional ps3 powerpc/ps3/ps3bus.c optional ps3 powerpc/ps3/ps3cdrom.c optional ps3 scbus powerpc/ps3/ps3disk.c optional ps3 powerpc/ps3/ps3pic.c optional ps3 powerpc/ps3/ps3_syscons.c optional ps3 vt powerpc/ps3/ps3-hvcall.S optional ps3 powerpc/pseries/phyp-hvcall.S optional pseries powerpc64 powerpc/pseries/mmu_phyp.c optional pseries powerpc64 powerpc/pseries/phyp_console.c optional pseries powerpc64 uart powerpc/pseries/phyp_llan.c optional llan powerpc/pseries/phyp_vscsi.c optional pseries powerpc64 scbus powerpc/pseries/platform_chrp.c optional pseries powerpc/pseries/plpar_iommu.c optional pseries powerpc64 powerpc/pseries/plpar_pcibus.c optional pseries powerpc64 pci powerpc/pseries/rtas_dev.c optional pseries powerpc/pseries/rtas_pci.c optional pseries pci powerpc/pseries/vdevice.c optional pseries powerpc64 powerpc/pseries/xics.c optional pseries powerpc64 powerpc/psim/iobus.c optional psim powerpc/psim/ata_iobus.c optional ata psim powerpc/psim/openpic_iobus.c optional psim powerpc/psim/uart_iobus.c optional uart psim powerpc/wii/platform_wii.c optional wii powerpc/wii/wii_bus.c optional wii powerpc/wii/wii_pic.c optional wii powerpc/wii/wii_fb.c optional wii powerpc/wii/wii_gpio.c optional wii wiigpio powerpc/wii/wii_ipc.c optional wii Index: stable/10/sys/dev/fdt/simplebus.c =================================================================== --- stable/10/sys/dev/fdt/simplebus.c (revision 283476) +++ stable/10/sys/dev/fdt/simplebus.c (revision 283477) @@ -1,385 +1,423 @@ /*- * Copyright (c) 2013 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include -struct simplebus_range { - uint64_t bus; - uint64_t host; - uint64_t size; -}; +#include -struct simplebus_softc { - device_t dev; - phandle_t node; - - struct simplebus_range *ranges; - int nranges; - - pcell_t acells, scells; -}; - -struct simplebus_devinfo { - struct ofw_bus_devinfo obdinfo; - struct resource_list rl; -}; - /* * Bus interface. */ static int simplebus_probe(device_t dev); static int simplebus_attach(device_t dev); static struct resource *simplebus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static void simplebus_probe_nomatch(device_t bus, device_t child); static int simplebus_print_child(device_t bus, device_t child); - +static device_t simplebus_add_child(device_t dev, u_int order, + const char *name, int unit); +static struct resource_list *simplebus_get_resource_list(device_t bus, + device_t child); /* * ofw_bus interface */ static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus, device_t child); /* * local methods */ static int simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc); -static struct simplebus_devinfo *simplebus_setup_dinfo(device_t dev, - phandle_t node); /* * Driver methods. */ static device_method_t simplebus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, simplebus_probe), DEVMETHOD(device_attach, simplebus_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ + DEVMETHOD(bus_add_child, simplebus_add_child), DEVMETHOD(bus_print_child, simplebus_print_child), DEVMETHOD(bus_probe_nomatch, simplebus_probe_nomatch), + DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), + DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), + DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; -static driver_t simplebus_driver = { - "simplebus", - simplebus_methods, - sizeof(struct simplebus_softc) -}; +DEFINE_CLASS_0(simplebus, simplebus_driver, simplebus_methods, + sizeof(struct simplebus_softc)); + static devclass_t simplebus_devclass; EARLY_DRIVER_MODULE(simplebus, ofwbus, simplebus_driver, simplebus_devclass, 0, 0, BUS_PASS_BUS); EARLY_DRIVER_MODULE(simplebus, simplebus, simplebus_driver, simplebus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); static int simplebus_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); /* * FDT data puts a "simple-bus" compatible string on many things that * have children but aren't really busses in our world. Without a * ranges property we will fail to attach, so just fail to probe too. */ if (!(ofw_bus_is_compatible(dev, "simple-bus") && ofw_bus_has_prop(dev, "ranges")) && (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev), "soc") != 0)) return (ENXIO); device_set_desc(dev, "Flattened device tree simple bus"); return (BUS_PROBE_GENERIC); } static int simplebus_attach(device_t dev) { struct simplebus_softc *sc; - struct simplebus_devinfo *di; phandle_t node; - device_t cdev; - node = ofw_bus_get_node(dev); sc = device_get_softc(dev); + simplebus_init(dev, 0); + if (simplebus_fill_ranges(sc->node, sc) < 0) { + device_printf(dev, "could not get ranges\n"); + return (ENXIO); + } + /* + * In principle, simplebus could have an interrupt map, but ignore that + * for now + */ + + for (node = OF_child(sc->node); node > 0; node = OF_peer(node)) + simplebus_add_device(dev, node, 0, NULL, -1, NULL); + return (bus_generic_attach(dev)); +} + +void +simplebus_init(device_t dev, phandle_t node) +{ + struct simplebus_softc *sc; + + sc = device_get_softc(dev); + if (node == 0) + node = ofw_bus_get_node(dev); sc->dev = dev; sc->node = node; /* * Some important numbers */ sc->acells = 2; OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); sc->scells = 1; OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); - - if (simplebus_fill_ranges(node, sc) < 0) { - device_printf(dev, "could not get ranges\n"); - return (ENXIO); - } - - /* - * In principle, simplebus could have an interrupt map, but ignore that - * for now - */ - - for (node = OF_child(node); node > 0; node = OF_peer(node)) { - if ((di = simplebus_setup_dinfo(dev, node)) == NULL) - continue; - cdev = device_add_child(dev, NULL, -1); - if (cdev == NULL) { - device_printf(dev, "<%s>: device_add_child failed\n", - di->obdinfo.obd_name); - resource_list_free(&di->rl); - ofw_bus_gen_destroy_devinfo(&di->obdinfo); - free(di, M_DEVBUF); - continue; - } - device_set_ivars(cdev, di); - } - - return (bus_generic_attach(dev)); } static int simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc) { int host_address_cells; cell_t *base_ranges; ssize_t nbase_ranges; int err; int i, j, k; err = OF_searchencprop(OF_parent(node), "#address-cells", &host_address_cells, sizeof(host_address_cells)); if (err <= 0) return (-1); nbase_ranges = OF_getproplen(node, "ranges"); if (nbase_ranges < 0) return (-1); sc->nranges = nbase_ranges / sizeof(cell_t) / (sc->acells + host_address_cells + sc->scells); if (sc->nranges == 0) return (0); sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), M_DEVBUF, M_WAITOK); base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); OF_getencprop(node, "ranges", base_ranges, nbase_ranges); for (i = 0, j = 0; i < sc->nranges; i++) { sc->ranges[i].bus = 0; for (k = 0; k < sc->acells; k++) { sc->ranges[i].bus <<= 32; sc->ranges[i].bus |= base_ranges[j++]; } sc->ranges[i].host = 0; for (k = 0; k < host_address_cells; k++) { sc->ranges[i].host <<= 32; sc->ranges[i].host |= base_ranges[j++]; } sc->ranges[i].size = 0; for (k = 0; k < sc->scells; k++) { sc->ranges[i].size <<= 32; sc->ranges[i].size |= base_ranges[j++]; } } free(base_ranges, M_DEVBUF); return (sc->nranges); } -static struct simplebus_devinfo * -simplebus_setup_dinfo(device_t dev, phandle_t node) +struct simplebus_devinfo * +simplebus_setup_dinfo(device_t dev, phandle_t node, + struct simplebus_devinfo *di) { struct simplebus_softc *sc; struct simplebus_devinfo *ndi; sc = device_get_softc(dev); - - ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); + if (di == NULL) + ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); + else + ndi = di; if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { - free(ndi, M_DEVBUF); + if (di == NULL) + free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->rl); ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl); ofw_bus_intr_to_rl(dev, node, &ndi->rl); return (ndi); } +device_t +simplebus_add_device(device_t dev, phandle_t node, u_int order, + const char *name, int unit, struct simplebus_devinfo *di) +{ + struct simplebus_devinfo *ndi; + device_t cdev; + + if ((ndi = simplebus_setup_dinfo(dev, node, di)) == NULL) + return (NULL); + cdev = device_add_child_ordered(dev, order, name, unit); + if (cdev == NULL) { + device_printf(dev, "<%s>: device_add_child failed\n", + ndi->obdinfo.obd_name); + resource_list_free(&ndi->rl); + ofw_bus_gen_destroy_devinfo(&ndi->obdinfo); + if (di == NULL) + free(ndi, M_DEVBUF); + return (NULL); + } + device_set_ivars(cdev, ndi); + + return(cdev); +} + +static device_t +simplebus_add_child(device_t dev, u_int order, const char *name, int unit) +{ + device_t cdev; + struct simplebus_devinfo *ndi; + + cdev = device_add_child_ordered(dev, order, name, unit); + if (cdev == NULL) + return (NULL); + + ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); + ndi->obdinfo.obd_node = -1; + resource_list_init(&ndi->rl); + device_set_ivars(cdev, ndi); + + return (cdev); +} + static const struct ofw_bus_devinfo * simplebus_get_devinfo(device_t bus __unused, device_t child) { struct simplebus_devinfo *ndi; ndi = device_get_ivars(child); return (&ndi->obdinfo); } +static struct resource_list * +simplebus_get_resource_list(device_t bus __unused, device_t child) +{ + struct simplebus_devinfo *ndi; + + ndi = device_get_ivars(child); + return (&ndi->rl); +} + static struct resource * simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct simplebus_softc *sc; struct simplebus_devinfo *di; struct resource_list_entry *rle; int j; sc = device_get_softc(bus); /* * Request for the default allocation with a given rid: use resource * list stored in the local device info. */ if ((start == 0UL) && (end == ~0UL)) { if ((di = device_get_ivars(child)) == NULL) return (NULL); if (type == SYS_RES_IOPORT) type = SYS_RES_MEMORY; rle = resource_list_find(&di->rl, type, *rid); if (rle == NULL) { if (bootverbose) device_printf(bus, "no default resources for " "rid = %d, type = %d\n", *rid, type); return (NULL); } start = rle->start; end = rle->end; count = rle->count; } if (type == SYS_RES_MEMORY) { /* Remap through ranges property */ for (j = 0; j < sc->nranges; j++) { if (start >= sc->ranges[j].bus && end < sc->ranges[j].bus + sc->ranges[j].size) { start -= sc->ranges[j].bus; start += sc->ranges[j].host; end -= sc->ranges[j].bus; end += sc->ranges[j].host; break; } } if (j == sc->nranges && sc->nranges != 0) { if (bootverbose) device_printf(bus, "Could not map resource " "%#lx-%#lx\n", start, end); return (NULL); } } return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); } static int simplebus_print_res(struct simplebus_devinfo *di) { int rv; rv = 0; rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx"); rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld"); return (rv); } static void simplebus_probe_nomatch(device_t bus, device_t child) { const char *name, *type, *compat; if (!bootverbose) return; + compat = ofw_bus_get_compat(child); + if (compat == NULL) + return; name = ofw_bus_get_name(child); type = ofw_bus_get_type(child); - compat = ofw_bus_get_compat(child); device_printf(bus, "<%s>", name != NULL ? name : "unknown"); simplebus_print_res(device_get_ivars(child)); if (!ofw_bus_status_okay(child)) printf(" disabled"); if (type) printf(" type %s", type); - if (compat) - printf(" compat %s", compat); - printf(" (no driver attached)\n"); + printf(" compat %s (no driver attached)\n", compat); } static int simplebus_print_child(device_t bus, device_t child) { int rv; rv = bus_print_child_header(bus, child); rv += simplebus_print_res(device_get_ivars(child)); if (!ofw_bus_status_okay(child)) rv += printf(" disabled"); rv += bus_print_child_footer(bus, child); return (rv); } Index: stable/10/sys/dev/fdt/simplebus.h =================================================================== --- stable/10/sys/dev/fdt/simplebus.h (nonexistent) +++ stable/10/sys/dev/fdt/simplebus.h (revision 283477) @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2013 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FDT_SIMPLEBUS_H +#define _FDT_SIMPLEBUS_H + +#include + +/* FDT simplebus */ +DECLARE_CLASS(simplebus_driver); + +struct simplebus_range { + uint64_t bus; + uint64_t host; + uint64_t size; +}; + +/* devinfo and softc */ +struct simplebus_softc { + device_t dev; + phandle_t node; + + struct simplebus_range *ranges; + int nranges; + + pcell_t acells, scells; +}; + +struct simplebus_devinfo { + struct ofw_bus_devinfo obdinfo; + struct resource_list rl; +}; + +void simplebus_init(device_t dev, phandle_t node); +device_t simplebus_add_device(device_t dev, phandle_t node, u_int order, + const char *name, int unit, struct simplebus_devinfo *di); +struct simplebus_devinfo *simplebus_setup_dinfo(device_t dev, phandle_t node, + struct simplebus_devinfo *di); +#endif /* _FDT_SIMPLEBUS_H */ Property changes on: stable/10/sys/dev/fdt/simplebus.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/ofw/ofwbus.c =================================================================== --- stable/10/sys/dev/ofw/ofwbus.c (revision 283476) +++ stable/10/sys/dev/ofw/ofwbus.c (revision 283477) @@ -1,488 +1,276 @@ /*- * Copyright 1998 Massachusetts Institute of Technology * Copyright 2001 by Thomas Moestl . * Copyright 2006 by Marius Strobl . * All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that both the above copyright notice and this * permission notice appear in all copies, that both the above * copyright notice and this permission notice appear in all * supporting documentation, and that the name of M.I.T. not be used * in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. M.I.T. makes * no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include /* * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that * hang from the Open Firmware root node and adds them as devices to this bus * (except some special nodes which are excluded) so that drivers can be * attached to them. * */ -struct ofwbus_devinfo { - struct ofw_bus_devinfo ndi_obdinfo; - struct resource_list ndi_rl; -}; - struct ofwbus_softc { - uint32_t acells, scells; + struct simplebus_softc simplebus_sc; struct rman sc_intr_rman; struct rman sc_mem_rman; }; static device_identify_t ofwbus_identify; static device_probe_t ofwbus_probe; static device_attach_t ofwbus_attach; -static bus_print_child_t ofwbus_print_child; -static bus_add_child_t ofwbus_add_child; -static bus_probe_nomatch_t ofwbus_probe_nomatch; static bus_alloc_resource_t ofwbus_alloc_resource; static bus_adjust_resource_t ofwbus_adjust_resource; static bus_release_resource_t ofwbus_release_resource; -static bus_get_resource_list_t ofwbus_get_resource_list; -static ofw_bus_get_devinfo_t ofwbus_get_devinfo; -static int ofwbus_inlist(const char *, const char *const *); -static struct ofwbus_devinfo * ofwbus_setup_dinfo(device_t, phandle_t); -static void ofwbus_destroy_dinfo(struct ofwbus_devinfo *); -static int ofwbus_print_res(struct ofwbus_devinfo *); - static device_method_t ofwbus_methods[] = { /* Device interface */ DEVMETHOD(device_identify, ofwbus_identify), DEVMETHOD(device_probe, ofwbus_probe), DEVMETHOD(device_attach, ofwbus_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_print_child, ofwbus_print_child), - DEVMETHOD(bus_probe_nomatch, ofwbus_probe_nomatch), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), - DEVMETHOD(bus_add_child, ofwbus_add_child), - DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), DEVMETHOD(bus_release_resource, ofwbus_release_resource), - DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), - DEVMETHOD(bus_get_resource_list, ofwbus_get_resource_list), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_config_intr, bus_generic_config_intr), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_devinfo, ofwbus_get_devinfo), - DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), - DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), - DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), - DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), - DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), - DEVMETHOD_END }; -static driver_t ofwbus_driver = { - "ofwbus", - ofwbus_methods, - sizeof(struct ofwbus_softc) -}; +DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, + sizeof(struct ofwbus_softc), simplebus_driver); static devclass_t ofwbus_devclass; EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(ofwbus, 1); -static const char *const ofwbus_excl_name[] = { - "FJSV,system", - "aliases", - "associations", - "chosen", - "cmp", - "counter-timer", /* No separate device; handled by psycho/sbus */ - "failsafe", - "memory", - "openprom", - "options", - "packages", - "physical-memory", - "rsc", - "sgcn", - "todsg", - "virtual-memory", - NULL -}; - -static const char *const ofwbus_excl_type[] = { - "core", - "cpu", - NULL -}; - -static int -ofwbus_inlist(const char *name, const char *const *list) -{ - int i; - - if (name == NULL) - return (0); - for (i = 0; list[i] != NULL; i++) - if (strcmp(name, list[i]) == 0) - return (1); - return (0); -} - -#define OFWBUS_EXCLUDED(name, type) \ - (ofwbus_inlist((name), ofwbus_excl_name) || \ - ((type) != NULL && ofwbus_inlist((type), ofwbus_excl_type))) - static void ofwbus_identify(driver_t *driver, device_t parent) { /* Check if Open Firmware has been instantiated */ if (OF_peer(0) == -1) return; - + if (device_find_child(parent, "ofwbus", -1) == NULL) BUS_ADD_CHILD(parent, 0, "ofwbus", -1); } static int ofwbus_probe(device_t dev) { device_set_desc(dev, "Open Firmware Device Tree"); return (BUS_PROBE_NOWILDCARD); } static int ofwbus_attach(device_t dev) { - struct ofwbus_devinfo *ndi; struct ofwbus_softc *sc; - device_t cdev; phandle_t node; + struct ofw_bus_devinfo obd; sc = device_get_softc(dev); node = OF_peer(0); /* * If no Open Firmware, bail early */ if (node == -1) return (ENXIO); + /* + * ofwbus bus starts on unamed node in FDT, so we cannot make + * ofw_bus_devinfo from it. Pass node to simplebus_init directly. + */ + simplebus_init(dev, node); sc->sc_intr_rman.rm_type = RMAN_ARRAY; sc->sc_intr_rman.rm_descr = "Interrupts"; sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "Device Memory"; if (rman_init(&sc->sc_intr_rman) != 0 || rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) panic("%s: failed to set up rmans.", __func__); /* * Allow devices to identify. */ bus_generic_probe(dev); /* - * Some important numbers - */ - sc->acells = 2; - OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); - sc->scells = 1; - OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); - - /* * Now walk the OFW tree and attach top-level devices. */ for (node = OF_child(node); node > 0; node = OF_peer(node)) { - if ((ndi = ofwbus_setup_dinfo(dev, node)) == NULL) + if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) continue; - cdev = device_add_child(dev, NULL, -1); - if (cdev == NULL) { - device_printf(dev, "<%s>: device_add_child failed\n", - ndi->ndi_obdinfo.obd_name); - ofwbus_destroy_dinfo(ndi); - continue; - } - device_set_ivars(cdev, ndi); + simplebus_add_device(dev, node, 0, NULL, -1, NULL); } return (bus_generic_attach(dev)); } -static device_t -ofwbus_add_child(device_t dev, u_int order, const char *name, int unit) -{ - device_t cdev; - struct ofwbus_devinfo *ndi; - - cdev = device_add_child_ordered(dev, order, name, unit); - if (cdev == NULL) - return (NULL); - - ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); - ndi->ndi_obdinfo.obd_node = -1; - resource_list_init(&ndi->ndi_rl); - device_set_ivars(cdev, ndi); - - return (cdev); -} - -static int -ofwbus_print_child(device_t bus, device_t child) -{ - int rv; - - rv = bus_print_child_header(bus, child); - rv += ofwbus_print_res(device_get_ivars(child)); - rv += bus_print_child_footer(bus, child); - return (rv); -} - -static void -ofwbus_probe_nomatch(device_t bus, device_t child) -{ - const char *name, *type; - - if (!bootverbose) - return; - - name = ofw_bus_get_name(child); - type = ofw_bus_get_type(child); - - device_printf(bus, "<%s>", - name != NULL ? name : "unknown"); - ofwbus_print_res(device_get_ivars(child)); - printf(" type %s (no driver attached)\n", - type != NULL ? type : "unknown"); -} - static struct resource * ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct ofwbus_softc *sc; struct rman *rm; struct resource *rv; struct resource_list_entry *rle; int isdefault, passthrough; isdefault = (start == 0UL && end == ~0UL); passthrough = (device_get_parent(child) != bus); sc = device_get_softc(bus); rle = NULL; - if (!passthrough && isdefault) { rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), type, *rid); - if (rle == NULL) + if (rle == NULL) { + if (bootverbose) + device_printf(bus, "no default resources for " + "rid = %d, type = %d\n", *rid, type); return (NULL); - if (rle->res != NULL) - panic("%s: resource entry is busy", __func__); + } start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } switch (type) { case SYS_RES_IRQ: rm = &sc->sc_intr_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, *rid, rv) != 0) { rman_release_resource(rv); return (NULL); } if (!passthrough && rle != NULL) { rle->res = rv; rle->start = rman_get_start(rv); rle->end = rman_get_end(rv); rle->count = rle->end - rle->start + 1; } return (rv); } static int ofwbus_adjust_resource(device_t bus, device_t child __unused, int type, struct resource *r, u_long start, u_long end) { struct ofwbus_softc *sc; struct rman *rm; device_t ofwbus; ofwbus = bus; while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0) ofwbus = device_get_parent(ofwbus); sc = device_get_softc(ofwbus); switch (type) { case SYS_RES_IRQ: rm = &sc->sc_intr_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; break; default: return (EINVAL); } if (rm == NULL) return (ENXIO); if (rman_is_region_manager(r, rm) == 0) return (EINVAL); return (rman_adjust_resource(r, start, end)); } static int ofwbus_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { struct resource_list_entry *rle; int error; /* Clean resource list entry */ rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), type, rid); if (rle != NULL) rle->res = NULL; if ((rman_get_flags(r) & RF_ACTIVE) != 0) { error = bus_deactivate_resource(child, type, rid, r); if (error) return (error); } return (rman_release_resource(r)); } - -static struct resource_list * -ofwbus_get_resource_list(device_t bus __unused, device_t child) -{ - struct ofwbus_devinfo *ndi; - - ndi = device_get_ivars(child); - return (&ndi->ndi_rl); -} - -static const struct ofw_bus_devinfo * -ofwbus_get_devinfo(device_t bus __unused, device_t child) -{ - struct ofwbus_devinfo *ndi; - - ndi = device_get_ivars(child); - return (&ndi->ndi_obdinfo); -} - -static struct ofwbus_devinfo * -ofwbus_setup_dinfo(device_t dev, phandle_t node) -{ - struct ofwbus_softc *sc; - struct ofwbus_devinfo *ndi; - const char *nodename; - - sc = device_get_softc(dev); - - ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); - if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) { - free(ndi, M_DEVBUF); - return (NULL); - } - nodename = ndi->ndi_obdinfo.obd_name; - if (OFWBUS_EXCLUDED(nodename, ndi->ndi_obdinfo.obd_type)) { - ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); - free(ndi, M_DEVBUF); - return (NULL); - } - - resource_list_init(&ndi->ndi_rl); - ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->ndi_rl); - ofw_bus_intr_to_rl(dev, node, &ndi->ndi_rl); - - return (ndi); -} - -static void -ofwbus_destroy_dinfo(struct ofwbus_devinfo *ndi) -{ - - resource_list_free(&ndi->ndi_rl); - ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); - free(ndi, M_DEVBUF); -} - -static int -ofwbus_print_res(struct ofwbus_devinfo *ndi) -{ - int rv; - - rv = 0; - rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY, - "%#lx"); - rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ, - "%ld"); - return (rv); -} - Index: stable/10/sys/dev/ofw/openfirm.c =================================================================== --- stable/10/sys/dev/ofw/openfirm.c (revision 283476) +++ stable/10/sys/dev/ofw/openfirm.c (revision 283477) @@ -1,791 +1,791 @@ /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (C) 2000 Benno Rice. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include "ofw_if.h" static void OF_putchar(int c, void *arg); MALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties"); static ihandle_t stdout; static ofw_def_t *ofw_def_impl = NULL; static ofw_t ofw_obj; static struct ofw_kobj ofw_kernel_obj; static struct kobj_ops ofw_kernel_kops; struct xrefinfo { phandle_t xref; phandle_t node; device_t dev; SLIST_ENTRY(xrefinfo) next_entry; }; static SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist); static struct mtx xreflist_lock; static boolean_t xref_init_done; #define FIND_BY_XREF 0 #define FIND_BY_NODE 1 #define FIND_BY_DEV 2 /* * xref-phandle-device lookup helper routines. * * As soon as we are able to use malloc(), walk the node tree and build a list * of info that cross-references node handles, xref handles, and device_t * instances. This list exists primarily to allow association of a device_t * with an xref handle, but it is also used to speed up translation between xref * and node handles. Before malloc() is available we have to recursively search * the node tree each time we want to translate between a node and xref handle. * Afterwards we can do the translations by searching this much shorter list. */ static void xrefinfo_create(phandle_t node) { struct xrefinfo * xi; phandle_t child, xref; /* * Recursively descend from parent, looking for nodes with a property * named either "phandle", "ibm,phandle", or "linux,phandle". For each * such node found create an entry in the xreflist. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { xrefinfo_create(child); if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) == -1 && OF_getencprop(child, "ibm,phandle", &xref, sizeof(xref)) == -1 && OF_getencprop(child, "linux,phandle", &xref, sizeof(xref)) == -1) continue; xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO); xi->node = child; xi->xref = xref; SLIST_INSERT_HEAD(&xreflist, xi, next_entry); } } static void xrefinfo_init(void *unsed) { /* * There is no locking during this init because it runs much earlier * than any of the clients/consumers of the xref list data, but we do * initialize the mutex that will be used for access later. */ mtx_init(&xreflist_lock, "OF xreflist lock", NULL, MTX_DEF); xrefinfo_create(OF_peer(0)); xref_init_done = true; } SYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL); static struct xrefinfo * -xrefinfo_find(phandle_t phandle, int find_by) +xrefinfo_find(uintptr_t key, int find_by) { struct xrefinfo *rv, *xi; rv = NULL; mtx_lock(&xreflist_lock); SLIST_FOREACH(xi, &xreflist, next_entry) { - if ((find_by == FIND_BY_XREF && phandle == xi->xref) || - (find_by == FIND_BY_NODE && phandle == xi->node) || - (find_by == FIND_BY_DEV && phandle == (uintptr_t)xi->dev)) { + if ((find_by == FIND_BY_XREF && (phandle_t)key == xi->xref) || + (find_by == FIND_BY_NODE && (phandle_t)key == xi->node) || + (find_by == FIND_BY_DEV && key == (uintptr_t)xi->dev)) { rv = xi; break; } } mtx_unlock(&xreflist_lock); return (rv); } static struct xrefinfo * xrefinfo_add(phandle_t node, phandle_t xref, device_t dev) { struct xrefinfo *xi; xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK); xi->node = node; xi->xref = xref; xi->dev = dev; mtx_lock(&xreflist_lock); SLIST_INSERT_HEAD(&xreflist, xi, next_entry); mtx_unlock(&xreflist_lock); return (xi); } /* * OFW install routines. Highest priority wins, equal priority also * overrides allowing last-set to win. */ SET_DECLARE(ofw_set, ofw_def_t); boolean_t OF_install(char *name, int prio) { ofw_def_t *ofwp, **ofwpp; static int curr_prio = 0; /* * Try and locate the OFW kobj corresponding to the name. */ SET_FOREACH(ofwpp, ofw_set) { ofwp = *ofwpp; if (ofwp->name && !strcmp(ofwp->name, name) && prio >= curr_prio) { curr_prio = prio; ofw_def_impl = ofwp; return (TRUE); } } return (FALSE); } /* Initializer */ int OF_init(void *cookie) { phandle_t chosen; int rv; if (ofw_def_impl == NULL) return (-1); ofw_obj = &ofw_kernel_obj; /* * Take care of compiling the selected class, and * then statically initialize the OFW object. */ kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops); kobj_init_static((kobj_t)ofw_obj, ofw_def_impl); rv = OFW_INIT(ofw_obj, cookie); if ((chosen = OF_finddevice("/chosen")) != -1) if (OF_getencprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) stdout = -1; return (rv); } static void OF_putchar(int c, void *arg __unused) { char cbuf; if (c == '\n') { cbuf = '\r'; OF_write(stdout, &cbuf, 1); } cbuf = c; OF_write(stdout, &cbuf, 1); } void OF_printf(const char *fmt, ...) { va_list va; va_start(va, fmt); (void)kvprintf(fmt, OF_putchar, NULL, 10, va); va_end(va); } /* * Generic functions */ /* Test to see if a service exists. */ int OF_test(const char *name) { if (ofw_def_impl == NULL) return (-1); return (OFW_TEST(ofw_obj, name)); } int OF_interpret(const char *cmd, int nreturns, ...) { va_list ap; cell_t slots[16]; int i = 0; int status; if (ofw_def_impl == NULL) return (-1); status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots); if (status == -1) return (status); va_start(ap, nreturns); while (i < nreturns) *va_arg(ap, cell_t *) = slots[i++]; va_end(ap); return (status); } /* * Device tree functions */ /* Return the next sibling of this node or 0. */ phandle_t OF_peer(phandle_t node) { if (ofw_def_impl == NULL) return (0); return (OFW_PEER(ofw_obj, node)); } /* Return the first child of this node or 0. */ phandle_t OF_child(phandle_t node) { if (ofw_def_impl == NULL) return (0); return (OFW_CHILD(ofw_obj, node)); } /* Return the parent of this node or 0. */ phandle_t OF_parent(phandle_t node) { if (ofw_def_impl == NULL) return (0); return (OFW_PARENT(ofw_obj, node)); } /* Return the package handle that corresponds to an instance handle. */ phandle_t OF_instance_to_package(ihandle_t instance) { if (ofw_def_impl == NULL) return (-1); return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance)); } /* Get the length of a property of a package. */ ssize_t OF_getproplen(phandle_t package, const char *propname) { if (ofw_def_impl == NULL) return (-1); return (OFW_GETPROPLEN(ofw_obj, package, propname)); } /* Check existence of a property of a package. */ int OF_hasprop(phandle_t package, const char *propname) { return (OF_getproplen(package, propname) >= 0 ? 1 : 0); } /* Get the value of a property of a package. */ ssize_t OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen) { if (ofw_def_impl == NULL) return (-1); return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen)); } ssize_t OF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len) { ssize_t retval; int i; KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes")); retval = OF_getprop(node, propname, buf, len); for (i = 0; i < len/4; i++) buf[i] = be32toh(buf[i]); return (retval); } /* * Recursively search the node and its parent for the given property, working * downward from the node to the device tree root. Returns the value of the * first match. */ ssize_t OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len) { ssize_t rv; for (; node != 0; node = OF_parent(node)) if ((rv = OF_getprop(node, propname, buf, len)) != -1) return (rv); return (-1); } ssize_t OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len) { ssize_t rv; for (; node != 0; node = OF_parent(node)) if ((rv = OF_getencprop(node, propname, buf, len)) != -1) return (rv); return (-1); } /* * Store the value of a property of a package into newly allocated memory * (using the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a * single element, the number of elements is return in number. */ ssize_t OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf) { int len; *buf = NULL; if ((len = OF_getproplen(package, propname)) == -1 || len % elsz != 0) return (-1); *buf = malloc(len, M_OFWPROP, M_WAITOK); if (OF_getprop(package, propname, *buf, len) == -1) { free(*buf, M_OFWPROP); *buf = NULL; return (-1); } return (len / elsz); } ssize_t OF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf) { ssize_t retval; pcell_t *cell; int i; retval = OF_getprop_alloc(package, name, elsz, buf); if (retval == -1 || retval*elsz % 4 != 0) return (-1); cell = *buf; for (i = 0; i < retval*elsz/4; i++) cell[i] = be32toh(cell[i]); return (retval); } /* Get the next property of a package. */ int OF_nextprop(phandle_t package, const char *previous, char *buf, size_t size) { if (ofw_def_impl == NULL) return (-1); return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size)); } /* Set the value of a property of a package. */ int OF_setprop(phandle_t package, const char *propname, const void *buf, size_t len) { if (ofw_def_impl == NULL) return (-1); return (OFW_SETPROP(ofw_obj, package, propname, buf,len)); } /* Convert a device specifier to a fully qualified pathname. */ ssize_t OF_canon(const char *device, char *buf, size_t len) { if (ofw_def_impl == NULL) return (-1); return (OFW_CANON(ofw_obj, device, buf, len)); } /* Return a package handle for the specified device. */ phandle_t OF_finddevice(const char *device) { if (ofw_def_impl == NULL) return (-1); return (OFW_FINDDEVICE(ofw_obj, device)); } /* Return the fully qualified pathname corresponding to an instance. */ ssize_t OF_instance_to_path(ihandle_t instance, char *buf, size_t len) { if (ofw_def_impl == NULL) return (-1); return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len)); } /* Return the fully qualified pathname corresponding to a package. */ ssize_t OF_package_to_path(phandle_t package, char *buf, size_t len) { if (ofw_def_impl == NULL) return (-1); return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len)); } /* Look up effective phandle (see FDT/PAPR spec) */ static phandle_t OF_child_xref_phandle(phandle_t parent, phandle_t xref) { phandle_t child, rxref; /* * Recursively descend from parent, looking for a node with a property * named either "phandle", "ibm,phandle", or "linux,phandle" that * matches the xref we are looking for. */ for (child = OF_child(parent); child != 0; child = OF_peer(child)) { rxref = OF_child_xref_phandle(child, xref); if (rxref != -1) return (rxref); if (OF_getencprop(child, "phandle", &rxref, sizeof(rxref)) == -1 && OF_getencprop(child, "ibm,phandle", &rxref, sizeof(rxref)) == -1 && OF_getencprop(child, "linux,phandle", &rxref, sizeof(rxref)) == -1) continue; if (rxref == xref) return (child); } return (-1); } phandle_t OF_node_from_xref(phandle_t xref) { struct xrefinfo *xi; phandle_t node; if (xref_init_done) { if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) return (xref); return (xi->node); } if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1) return (xref); return (node); } phandle_t OF_xref_from_node(phandle_t node) { struct xrefinfo *xi; phandle_t xref; if (xref_init_done) { if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL) return (node); return (xi->xref); } if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == -1 && OF_getencprop(node, "ibm,phandle", &xref, sizeof(xref)) == -1 && OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1) return (node); return (xref); } device_t OF_device_from_xref(phandle_t xref) { struct xrefinfo *xi; if (xref_init_done) { if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) return (NULL); return (xi->dev); } panic("Attempt to find device before xreflist_init"); } phandle_t OF_xref_from_device(device_t dev) { struct xrefinfo *xi; if (xref_init_done) { if ((xi = xrefinfo_find((uintptr_t)dev, FIND_BY_DEV)) == NULL) return (0); return (xi->xref); } panic("Attempt to find xref before xreflist_init"); } int OF_device_register_xref(phandle_t xref, device_t dev) { struct xrefinfo *xi; /* * If the given xref handle doesn't already exist in the list then we * add a list entry. In theory this can only happen on a system where * nodes don't contain phandle properties and xref and node handles are * synonymous, so the xref handle is added as the node handle as well. */ if (xref_init_done) { if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) xrefinfo_add(xref, xref, dev); else xi->dev = dev; return (0); } panic("Attempt to register device before xreflist_init"); } /* Call the method in the scope of a given instance. */ int OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns, ...) { va_list ap; cell_t args_n_results[12]; int n, status; if (nargs > 6 || ofw_def_impl == NULL) return (-1); va_start(ap, nreturns); for (n = 0; n < nargs; n++) args_n_results[n] = va_arg(ap, cell_t); status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns, args_n_results); if (status != 0) return (status); for (; n < nargs + nreturns; n++) *va_arg(ap, cell_t *) = args_n_results[n]; va_end(ap); return (0); } /* * Device I/O functions */ /* Open an instance for a device. */ ihandle_t OF_open(const char *device) { if (ofw_def_impl == NULL) return (0); return (OFW_OPEN(ofw_obj, device)); } /* Close an instance. */ void OF_close(ihandle_t instance) { if (ofw_def_impl == NULL) return; OFW_CLOSE(ofw_obj, instance); } /* Read from an instance. */ ssize_t OF_read(ihandle_t instance, void *addr, size_t len) { if (ofw_def_impl == NULL) return (-1); return (OFW_READ(ofw_obj, instance, addr, len)); } /* Write to an instance. */ ssize_t OF_write(ihandle_t instance, const void *addr, size_t len) { if (ofw_def_impl == NULL) return (-1); return (OFW_WRITE(ofw_obj, instance, addr, len)); } /* Seek to a position. */ int OF_seek(ihandle_t instance, uint64_t pos) { if (ofw_def_impl == NULL) return (-1); return (OFW_SEEK(ofw_obj, instance, pos)); } /* * Memory functions */ /* Claim an area of memory. */ void * OF_claim(void *virt, size_t size, u_int align) { if (ofw_def_impl == NULL) return ((void *)-1); return (OFW_CLAIM(ofw_obj, virt, size, align)); } /* Release an area of memory. */ void OF_release(void *virt, size_t size) { if (ofw_def_impl == NULL) return; OFW_RELEASE(ofw_obj, virt, size); } /* * Control transfer functions */ /* Suspend and drop back to the Open Firmware interface. */ void OF_enter() { if (ofw_def_impl == NULL) return; OFW_ENTER(ofw_obj); } /* Shut down and drop back to the Open Firmware interface. */ void OF_exit() { if (ofw_def_impl == NULL) panic("OF_exit: Open Firmware not available"); /* Should not return */ OFW_EXIT(ofw_obj); for (;;) /* just in case */ ; } Index: stable/10 =================================================================== --- stable/10 (revision 283476) +++ stable/10 (revision 283477) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r279368,280772,280848