From 0bd794912485d57bb4c73066dea87086659bc75c Mon Sep 17 00:00:00 2001 From: Jan Sommer Date: Fri, 7 Feb 2020 12:40:11 +0100 Subject: i386: Add missing files from FreeBSD - Files needed to make rtems-libbsd build again for i386 --- freebsd/sys/i386/include/machine/bus.h | 6 + freebsd/sys/x86/include/machine/intr_machdep.h | 175 +++++++++++ freebsd/sys/x86/include/machine/legacyvar.h | 73 +++++ freebsd/sys/x86/include/machine/metadata.h | 57 ++++ freebsd/sys/x86/x86/legacy.c | 393 +++++++++++++++++++++++++ 5 files changed, 704 insertions(+) create mode 100644 freebsd/sys/i386/include/machine/bus.h create mode 100644 freebsd/sys/x86/include/machine/intr_machdep.h create mode 100644 freebsd/sys/x86/include/machine/legacyvar.h create mode 100644 freebsd/sys/x86/include/machine/metadata.h create mode 100644 freebsd/sys/x86/x86/legacy.c (limited to 'freebsd') diff --git a/freebsd/sys/i386/include/machine/bus.h b/freebsd/sys/i386/include/machine/bus.h new file mode 100644 index 00000000..f1af2cf6 --- /dev/null +++ b/freebsd/sys/i386/include/machine/bus.h @@ -0,0 +1,6 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ + +#include diff --git a/freebsd/sys/x86/include/machine/intr_machdep.h b/freebsd/sys/x86/include/machine/intr_machdep.h new file mode 100644 index 00000000..346a33a4 --- /dev/null +++ b/freebsd/sys/x86/include/machine/intr_machdep.h @@ -0,0 +1,175 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2003 John Baldwin + * + * 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 __X86_INTR_MACHDEP_H__ +#define __X86_INTR_MACHDEP_H__ + +#ifdef _KERNEL + +/* + * Values used in determining the allocation of IRQ values among + * different types of I/O interrupts. These values are used as + * indices into a interrupt source array to map I/O interrupts to a + * device interrupt source whether it be a pin on an interrupt + * controller or an MSI interrupt. The 16 ISA IRQs are assigned fixed + * IDT vectors, but all other device interrupts allocate IDT vectors + * on demand. Currently we have 191 IDT vectors available for device + * interrupts on each CPU. On many systems with I/O APICs, a lot of + * the IRQs are not used, so the total number of IRQ values reserved + * can exceed the number of available IDT slots. + * + * The first 16 IRQs (0 - 15) are reserved for ISA IRQs. Interrupt + * pins on I/O APICs for non-ISA interrupts use IRQ values starting at + * IRQ 17. This layout matches the GSI numbering used by ACPI so that + * IRQ values returned by ACPI methods such as _CRS can be used + * directly by the ACPI bus driver. + * + * MSI interrupts allocate a block of interrupts starting at the end + * of the I/O APIC range. When running under the Xen Hypervisor, an + * additional range of IRQ values are available for binding to event + * channel events. + */ +extern u_int first_msi_irq; +extern u_int num_io_irqs; +extern u_int num_msi_irqs; + +/* + * Default base address for MSI messages on x86 platforms. + */ +#define MSI_INTEL_ADDR_BASE 0xfee00000 + +#ifndef LOCORE + +typedef void inthand_t(void); + +#define IDTVEC(name) __CONCAT(X,name) + +struct intsrc; + +/* + * Methods that a PIC provides to mask/unmask a given interrupt source, + * "turn on" the interrupt on the CPU side by setting up an IDT entry, and + * return the vector associated with this source. + */ +struct pic { + void (*pic_register_sources)(struct pic *); + void (*pic_enable_source)(struct intsrc *); + void (*pic_disable_source)(struct intsrc *, int); + void (*pic_eoi_source)(struct intsrc *); + void (*pic_enable_intr)(struct intsrc *); + void (*pic_disable_intr)(struct intsrc *); + int (*pic_vector)(struct intsrc *); + int (*pic_source_pending)(struct intsrc *); + void (*pic_suspend)(struct pic *); + void (*pic_resume)(struct pic *, bool suspend_cancelled); + int (*pic_config_intr)(struct intsrc *, enum intr_trigger, + enum intr_polarity); + int (*pic_assign_cpu)(struct intsrc *, u_int apic_id); + void (*pic_reprogram_pin)(struct intsrc *); + TAILQ_ENTRY(pic) pics; +}; + +/* Flags for pic_disable_source() */ +enum { + PIC_EOI, + PIC_NO_EOI, +}; + +/* + * An interrupt source. The upper-layer code uses the PIC methods to + * control a given source. The lower-layer PIC drivers can store additional + * private data in a given interrupt source such as an interrupt pin number + * or an I/O APIC pointer. + */ +struct intsrc { + struct pic *is_pic; + struct intr_event *is_event; + u_long *is_count; + u_long *is_straycount; + u_int is_index; + u_int is_handlers; + u_int is_domain; + u_int is_cpu; +}; + +struct trapframe; + +#ifdef SMP +extern cpuset_t intr_cpus; +#endif +extern struct mtx icu_lock; +extern int elcr_found; +#ifdef SMP +extern int msix_disable_migration; +#endif + +#ifndef DEV_ATPIC +void atpic_reset(void); +#endif +/* XXX: The elcr_* prototypes probably belong somewhere else. */ +int elcr_probe(void); +enum intr_trigger elcr_read_trigger(u_int irq); +void elcr_resume(void); +void elcr_write_trigger(u_int irq, enum intr_trigger trigger); +#ifdef SMP +void intr_add_cpu(u_int cpu); +#endif +int intr_add_handler(const char *name, int vector, driver_filter_t filter, + driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep, + int domain); +#ifdef SMP +int intr_bind(u_int vector, u_char cpu); +#endif +int intr_config_intr(int vector, enum intr_trigger trig, + enum intr_polarity pol); +int intr_describe(u_int vector, void *ih, const char *descr); +void intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame); +u_int intr_next_cpu(int domain); +struct intsrc *intr_lookup_source(int vector); +int intr_register_pic(struct pic *pic); +int intr_register_source(struct intsrc *isrc); +int intr_remove_handler(void *cookie); +void intr_resume(bool suspend_cancelled); +void intr_suspend(void); +void intr_reprogram(void); +void intrcnt_add(const char *name, u_long **countp); +void nexus_add_irq(u_long irq); +int msi_alloc(device_t dev, int count, int maxcount, int *irqs); +void msi_init(void); +int msi_map(int irq, uint64_t *addr, uint32_t *data); +int msi_release(int *irqs, int count); +int msix_alloc(device_t dev, int *irq); +int msix_release(int irq); +#ifdef XENHVM +void xen_intr_alloc_irqs(void); +#endif + +#endif /* !LOCORE */ +#endif /* _KERNEL */ +#endif /* !__X86_INTR_MACHDEP_H__ */ diff --git a/freebsd/sys/x86/include/machine/legacyvar.h b/freebsd/sys/x86/include/machine/legacyvar.h new file mode 100644 index 00000000..f6e5814a --- /dev/null +++ b/freebsd/sys/x86/include/machine/legacyvar.h @@ -0,0 +1,73 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2000 Peter Wemm + * 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 _X86_LEGACYVAR_H_ +#define _X86_LEGACYVAR_H_ + +enum legacy_device_ivars { + LEGACY_IVAR_PCIDOMAIN, + LEGACY_IVAR_PCIBUS, + LEGACY_IVAR_PCISLOT, + LEGACY_IVAR_PCIFUNC +}; + +#define LEGACY_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(legacy, var, LEGACY, ivar, type) + +LEGACY_ACCESSOR(pcidomain, PCIDOMAIN, uint32_t) +LEGACY_ACCESSOR(pcibus, PCIBUS, uint32_t) +LEGACY_ACCESSOR(pcislot, PCISLOT, int) +LEGACY_ACCESSOR(pcifunc, PCIFUNC, int) + +#undef LEGACY_ACCESSOR + +int legacy_pcib_maxslots(device_t dev); +uint32_t legacy_pcib_read_config(device_t dev, u_int bus, u_int slot, + u_int func, u_int reg, int bytes); +int legacy_pcib_read_ivar(device_t dev, device_t child, int which, + uintptr_t *result); +void legacy_pcib_write_config(device_t dev, u_int bus, u_int slot, + u_int func, u_int reg, uint32_t data, int bytes); +int legacy_pcib_write_ivar(device_t dev, device_t child, int which, + uintptr_t value); +struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child, + int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, + u_int flags); +int legacy_pcib_adjust_resource(device_t dev, device_t child, int type, + struct resource *r, rman_res_t start, rman_res_t end); +int legacy_pcib_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r); +int legacy_pcib_alloc_msi(device_t pcib, device_t dev, int count, + int maxcount, int *irqs); +int legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq); +int legacy_pcib_map_msi(device_t pcib, device_t dev, int irq, + uint64_t *addr, uint32_t *data); + +#endif /* !_X86_LEGACYVAR_H_ */ diff --git a/freebsd/sys/x86/include/machine/metadata.h b/freebsd/sys/x86/include/machine/metadata.h new file mode 100644 index 00000000..e13eba0c --- /dev/null +++ b/freebsd/sys/x86/include/machine/metadata.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2003 Peter Wemm + * 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 _MACHINE_METADATA_H_ +#define _MACHINE_METADATA_H_ + +#define MODINFOMD_SMAP 0x1001 +#define MODINFOMD_SMAP_XATTR 0x1002 +#define MODINFOMD_DTBP 0x1003 +#define MODINFOMD_EFI_MAP 0x1004 +#define MODINFOMD_EFI_FB 0x1005 +#define MODINFOMD_MODULEP 0x1006 + +struct efi_map_header { + uint64_t memory_size; + uint64_t descriptor_size; + uint32_t descriptor_version; +}; + +struct efi_fb { + uint64_t fb_addr; + uint64_t fb_size; + uint32_t fb_height; + uint32_t fb_width; + uint32_t fb_stride; + uint32_t fb_mask_red; + uint32_t fb_mask_green; + uint32_t fb_mask_blue; + uint32_t fb_mask_reserved; +}; + +#endif /* !_MACHINE_METADATA_H_ */ diff --git a/freebsd/sys/x86/x86/legacy.c b/freebsd/sys/x86/x86/legacy.c new file mode 100644 index 00000000..4c2174ba --- /dev/null +++ b/freebsd/sys/x86/x86/legacy.c @@ -0,0 +1,393 @@ +#include + +/*- + * Copyright 1998 Massachusetts Institute of Technology + * + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * This code implements a system driver for legacy systems that do not + * support ACPI or when ACPI support is not present in the kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static MALLOC_DEFINE(M_LEGACYDEV, "legacydrv", "legacy system device"); +struct legacy_device { + int lg_pcibus; + int lg_pcislot; + int lg_pcifunc; +}; + +#define DEVTOAT(dev) ((struct legacy_device *)device_get_ivars(dev)) + +static int legacy_probe(device_t); +static int legacy_attach(device_t); +static int legacy_print_child(device_t, device_t); +static device_t legacy_add_child(device_t bus, u_int order, const char *name, + int unit); +static int legacy_read_ivar(device_t, device_t, int, uintptr_t *); +static int legacy_write_ivar(device_t, device_t, int, uintptr_t); + +static device_method_t legacy_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, legacy_probe), + DEVMETHOD(device_attach, legacy_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, legacy_print_child), + DEVMETHOD(bus_add_child, legacy_add_child), + DEVMETHOD(bus_read_ivar, legacy_read_ivar), + DEVMETHOD(bus_write_ivar, legacy_write_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_adjust_resource, bus_generic_adjust_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_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t legacy_driver = { + "legacy", + legacy_methods, + 1, /* no softc */ +}; +static devclass_t legacy_devclass; + +DRIVER_MODULE(legacy, nexus, legacy_driver, legacy_devclass, 0, 0); + +static int +legacy_probe(device_t dev) +{ + + device_set_desc(dev, "legacy system"); + device_quiet(dev); + return (0); +} + +/* + * Grope around in the PCI config space to see if this is a chipset + * that is capable of doing memory-mapped config cycles. This also + * implies that it can do PCIe extended config cycles. + */ +static void +legacy_pci_cfgregopen(device_t dev) +{ + uint64_t pciebar; + u_int16_t did, vid; + + if (cfgmech == CFGMECH_NONE || cfgmech == CFGMECH_PCIE) + return; + + /* Check for supported chipsets */ + vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); + did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); + switch (vid) { + case 0x8086: + switch (did) { + case 0x3590: + case 0x3592: + /* Intel 7520 or 7320 */ + pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; + pcie_cfgregopen(pciebar, 0, 255); + break; + case 0x2580: + case 0x2584: + case 0x2590: + /* Intel 915, 925, or 915GM */ + pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); + pcie_cfgregopen(pciebar, 0, 255); + break; + } + } + + if (bootverbose && cfgmech == CFGMECH_PCIE) + device_printf(dev, "Enabled ECAM PCIe accesses\n"); +} + +static int +legacy_attach(device_t dev) +{ + device_t child; + + legacy_pci_cfgregopen(dev); + + /* + * Let our child drivers identify any child devices that they + * can find. Once that is done attach any devices that we + * found. + */ + bus_generic_probe(dev); + bus_generic_attach(dev); + + /* + * If we didn't see ISA on a PCI bridge, add a top-level bus. + */ + if (!devclass_get_device(devclass_find("isa"), 0)) { + child = BUS_ADD_CHILD(dev, 0, "isa", 0); + if (child == NULL) + panic("legacy_attach isa"); + device_probe_and_attach(child); + } + + return 0; +} + +static int +legacy_print_child(device_t bus, device_t child) +{ + struct legacy_device *atdev = DEVTOAT(child); + int retval = 0; + + retval += bus_print_child_header(bus, child); + if (atdev->lg_pcibus != -1) + retval += printf(" pcibus %d", atdev->lg_pcibus); + retval += printf("\n"); + + return (retval); +} + +static device_t +legacy_add_child(device_t bus, u_int order, const char *name, int unit) +{ + device_t child; + struct legacy_device *atdev; + + atdev = malloc(sizeof(struct legacy_device), M_LEGACYDEV, + M_NOWAIT | M_ZERO); + if (atdev == NULL) + return(NULL); + atdev->lg_pcibus = -1; + atdev->lg_pcislot = -1; + atdev->lg_pcifunc = -1; + + child = device_add_child_ordered(bus, order, name, unit); + if (child == NULL) + free(atdev, M_LEGACYDEV); + else + /* should we free this in legacy_child_detached? */ + device_set_ivars(child, atdev); + + return (child); +} + +static int +legacy_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct legacy_device *atdev = DEVTOAT(child); + + switch (which) { + case LEGACY_IVAR_PCIDOMAIN: + *result = 0; + break; + case LEGACY_IVAR_PCIBUS: + *result = atdev->lg_pcibus; + break; + case LEGACY_IVAR_PCISLOT: + *result = atdev->lg_pcislot; + break; + case LEGACY_IVAR_PCIFUNC: + *result = atdev->lg_pcifunc; + break; + default: + return ENOENT; + } + return 0; +} + + +static int +legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct legacy_device *atdev = DEVTOAT(child); + + switch (which) { + case LEGACY_IVAR_PCIDOMAIN: + return EINVAL; + case LEGACY_IVAR_PCIBUS: + atdev->lg_pcibus = value; + break; + case LEGACY_IVAR_PCISLOT: + atdev->lg_pcislot = value; + break; + case LEGACY_IVAR_PCIFUNC: + atdev->lg_pcifunc = value; + break; + default: + return ENOENT; + } + return 0; +} + +/* + * Legacy CPU attachment when ACPI is not available. Drivers like + * cpufreq(4) hang off this. + */ +static void cpu_identify(driver_t *driver, device_t parent); +static int cpu_read_ivar(device_t dev, device_t child, int index, + uintptr_t *result); +static device_t cpu_add_child(device_t bus, u_int order, const char *name, + int unit); +static struct resource_list *cpu_get_rlist(device_t dev, device_t child); + +struct cpu_device { + struct resource_list cd_rl; + struct pcpu *cd_pcpu; +}; + +static device_method_t cpu_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, cpu_identify), + DEVMETHOD(device_probe, bus_generic_probe), + DEVMETHOD(device_attach, bus_generic_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, cpu_add_child), + DEVMETHOD(bus_read_ivar, cpu_read_ivar), + DEVMETHOD(bus_get_resource_list, cpu_get_rlist), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + DEVMETHOD_END +}; + +static driver_t cpu_driver = { + "cpu", + cpu_methods, + 1, /* no softc */ +}; +static devclass_t cpu_devclass; +DRIVER_MODULE(cpu, legacy, cpu_driver, cpu_devclass, 0, 0); + +static void +cpu_identify(driver_t *driver, device_t parent) +{ + device_t child; + int i; + + /* + * Attach a cpuX device for each CPU. We use an order of 150 + * so that these devices are attached after the Host-PCI + * bridges (which are added at order 100). + */ + CPU_FOREACH(i) { + child = BUS_ADD_CHILD(parent, 150, "cpu", i); + if (child == NULL) + panic("legacy_attach cpu"); + } +} + +static device_t +cpu_add_child(device_t bus, u_int order, const char *name, int unit) +{ + struct cpu_device *cd; + device_t child; + struct pcpu *pc; + + if ((cd = malloc(sizeof(*cd), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) + return (NULL); + + resource_list_init(&cd->cd_rl); + pc = pcpu_find(device_get_unit(bus)); + cd->cd_pcpu = pc; + + child = device_add_child_ordered(bus, order, name, unit); + if (child != NULL) { + pc->pc_device = child; + device_set_ivars(child, cd); + } else + free(cd, M_DEVBUF); + return (child); +} + +static struct resource_list * +cpu_get_rlist(device_t dev, device_t child) +{ + struct cpu_device *cpdev; + + cpdev = device_get_ivars(child); + return (&cpdev->cd_rl); +} + +static int +cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct cpu_device *cpdev; + + switch (index) { + case CPU_IVAR_PCPU: + cpdev = device_get_ivars(child); + *result = (uintptr_t)cpdev->cd_pcpu; + break; + case CPU_IVAR_NOMINAL_MHZ: + if (tsc_is_invariant) { + *result = (uintptr_t)(atomic_load_acq_64(&tsc_freq) / + 1000000); + break; + } + /* FALLTHROUGH */ + default: + return (ENOENT); + } + return (0); +} -- cgit v1.2.3