1139790Simp/*- 284124Sdfr * Copyright 1998 Massachusetts Institute of Technology 384124Sdfr * 484124Sdfr * Permission to use, copy, modify, and distribute this software and 584124Sdfr * its documentation for any purpose and without fee is hereby 684124Sdfr * granted, provided that both the above copyright notice and this 784124Sdfr * permission notice appear in all copies, that both the above 884124Sdfr * copyright notice and this permission notice appear in all 984124Sdfr * supporting documentation, and that the name of M.I.T. not be used 1084124Sdfr * in advertising or publicity pertaining to distribution of the 1184124Sdfr * software without specific, written prior permission. M.I.T. makes 1284124Sdfr * no representations about the suitability of this software for any 1384124Sdfr * purpose. It is provided "as is" without express or implied 1484124Sdfr * warranty. 1584124Sdfr * 1684124Sdfr * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1784124Sdfr * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1884124Sdfr * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1984124Sdfr * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2084124Sdfr * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2184124Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2284124Sdfr * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2384124Sdfr * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2484124Sdfr * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2584124Sdfr * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2684124Sdfr * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2784124Sdfr * SUCH DAMAGE. 2884124Sdfr * 2984124Sdfr * $FreeBSD: releng/10.3/sys/ia64/ia64/nexus.c 270296 2014-08-21 19:51:07Z emaste $ 3084124Sdfr */ 3184124Sdfr 3284124Sdfr/* 3384124Sdfr * This code implements a `root nexus' for Intel Architecture 3484124Sdfr * machines. The function of the root nexus is to serve as an 3584124Sdfr * attachment point for both processors and buses, and to manage 3684124Sdfr * resources which are common to all of them. In particular, 3784124Sdfr * this code implements the core resource managers for interrupt 3884124Sdfr * requests, DMA requests (which rightfully should be a part of the 3984124Sdfr * ISA code but it's easier to do it here for now), I/O port addresses, 4084124Sdfr * and I/O memory address space. 4184124Sdfr */ 4284124Sdfr 4384124Sdfr#include <sys/param.h> 4484124Sdfr#include <sys/systm.h> 4584124Sdfr#include <sys/bus.h> 46178222Smarcel#include <sys/clock.h> 47270296Semaste#include <sys/efi.h> 4884124Sdfr#include <sys/kernel.h> 4984124Sdfr#include <sys/malloc.h> 5084124Sdfr#include <sys/module.h> 5184124Sdfr#include <machine/bus.h> 5284124Sdfr#include <sys/rman.h> 5384124Sdfr#include <sys/interrupt.h> 54205726Smarcel#include <sys/pcpu.h> 5584124Sdfr 5684124Sdfr#include <vm/vm.h> 5784124Sdfr#include <vm/pmap.h> 5884124Sdfr 59119970Smarcel#include <machine/intr.h> 60119970Smarcel#include <machine/pmap.h> 6184124Sdfr#include <machine/resource.h> 62119970Smarcel#include <machine/vmparam.h> 6384124Sdfr 64193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 65193530Sjkim 66177157Sjhb#include <dev/acpica/acpivar.h> 67177157Sjhb 68178222Smarcel#include "clock_if.h" 69178222Smarcel 7084124Sdfrstatic MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); 7184124Sdfrstruct nexus_device { 7284124Sdfr struct resource_list nx_resources; 7384124Sdfr}; 7484124Sdfr 7584124Sdfr#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) 7684124Sdfr 77204904Smarcelstatic struct rman irq_rman, port_rman, mem_rman; 7884124Sdfr 7984124Sdfrstatic int nexus_probe(device_t); 8084124Sdfrstatic int nexus_attach(device_t); 8184124Sdfrstatic int nexus_print_child(device_t, device_t); 82212413Savgstatic device_t nexus_add_child(device_t bus, u_int order, const char *name, 8384124Sdfr int unit); 8484124Sdfrstatic struct resource *nexus_alloc_resource(device_t, device_t, int, int *, 8584124Sdfr u_long, u_long, u_long, u_int); 86224184Sjhbstatic int nexus_adjust_resource(device_t, device_t, int, struct resource *, 87224184Sjhb u_long, u_long); 8884124Sdfrstatic int nexus_activate_resource(device_t, device_t, int, int, 8984124Sdfr struct resource *); 9084124Sdfrstatic int nexus_deactivate_resource(device_t, device_t, int, int, 9184124Sdfr struct resource *); 9284124Sdfrstatic int nexus_release_resource(device_t, device_t, int, int, 9384124Sdfr struct resource *); 9484124Sdfrstatic int nexus_setup_intr(device_t, device_t, struct resource *, int flags, 95166901Spiso driver_filter_t filter, void (*)(void *), void *, 96166901Spiso void **); 9784124Sdfrstatic int nexus_teardown_intr(device_t, device_t, struct resource *, 9884124Sdfr void *); 99134263Snjlstatic struct resource_list *nexus_get_reslist(device_t dev, device_t child); 10084124Sdfrstatic int nexus_set_resource(device_t, device_t, int, int, u_long, u_long); 101119970Smarcelstatic int nexus_get_resource(device_t, device_t, int, int, u_long *, 102119970Smarcel u_long *); 10384124Sdfrstatic void nexus_delete_resource(device_t, device_t, int, int); 104205726Smarcelstatic int nexus_bind_intr(device_t, device_t, struct resource *, int); 105119970Smarcelstatic int nexus_config_intr(device_t, int, enum intr_trigger, 106119970Smarcel enum intr_polarity); 10784124Sdfr 108178222Smarcelstatic int nexus_gettime(device_t, struct timespec *); 109178222Smarcelstatic int nexus_settime(device_t, struct timespec *); 110178222Smarcel 11184124Sdfrstatic device_method_t nexus_methods[] = { 11284124Sdfr /* Device interface */ 11384124Sdfr DEVMETHOD(device_probe, nexus_probe), 11484124Sdfr DEVMETHOD(device_attach, nexus_attach), 11584124Sdfr DEVMETHOD(device_detach, bus_generic_detach), 11684124Sdfr DEVMETHOD(device_shutdown, bus_generic_shutdown), 11784124Sdfr DEVMETHOD(device_suspend, bus_generic_suspend), 11884124Sdfr DEVMETHOD(device_resume, bus_generic_resume), 11984124Sdfr 12084124Sdfr /* Bus interface */ 12184124Sdfr DEVMETHOD(bus_print_child, nexus_print_child), 12284124Sdfr DEVMETHOD(bus_add_child, nexus_add_child), 12384124Sdfr DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), 124224184Sjhb DEVMETHOD(bus_adjust_resource, nexus_adjust_resource), 12584124Sdfr DEVMETHOD(bus_release_resource, nexus_release_resource), 12684124Sdfr DEVMETHOD(bus_activate_resource, nexus_activate_resource), 12784124Sdfr DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), 12884124Sdfr DEVMETHOD(bus_setup_intr, nexus_setup_intr), 12984124Sdfr DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), 130134263Snjl DEVMETHOD(bus_get_resource_list, nexus_get_reslist), 13184124Sdfr DEVMETHOD(bus_set_resource, nexus_set_resource), 13284124Sdfr DEVMETHOD(bus_get_resource, nexus_get_resource), 13384124Sdfr DEVMETHOD(bus_delete_resource, nexus_delete_resource), 134205726Smarcel DEVMETHOD(bus_bind_intr, nexus_bind_intr), 135119970Smarcel DEVMETHOD(bus_config_intr, nexus_config_intr), 13684124Sdfr 137178222Smarcel /* Clock interface */ 138178222Smarcel DEVMETHOD(clock_gettime, nexus_gettime), 139178222Smarcel DEVMETHOD(clock_settime, nexus_settime), 140178222Smarcel 14184124Sdfr { 0, 0 } 14284124Sdfr}; 14384124Sdfr 14484124Sdfrstatic driver_t nexus_driver = { 14584124Sdfr "nexus", 14684124Sdfr nexus_methods, 14784124Sdfr 1, /* no softc */ 14884124Sdfr}; 14984124Sdfrstatic devclass_t nexus_devclass; 15084124Sdfr 15184124SdfrDRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0); 15284124Sdfr 15384124Sdfrstatic int 15484124Sdfrnexus_probe(device_t dev) 15584124Sdfr{ 15684124Sdfr 15784124Sdfr device_quiet(dev); /* suppress attach message for neatness */ 15884124Sdfr 15984124Sdfr irq_rman.rm_type = RMAN_ARRAY; 16084124Sdfr irq_rman.rm_descr = "Interrupt request lines"; 161205234Smarcel irq_rman.rm_start = 0; 162205234Smarcel irq_rman.rm_end = IA64_NXIVS - 1; 16384124Sdfr if (rman_init(&irq_rman) 16484124Sdfr || rman_manage_region(&irq_rman, 16584124Sdfr irq_rman.rm_start, irq_rman.rm_end)) 16684124Sdfr panic("nexus_probe irq_rman"); 16784124Sdfr 16884124Sdfr port_rman.rm_start = 0; 16984124Sdfr port_rman.rm_end = 0xffff; 17084124Sdfr port_rman.rm_type = RMAN_ARRAY; 17184124Sdfr port_rman.rm_descr = "I/O ports"; 17284124Sdfr if (rman_init(&port_rman) 17384124Sdfr || rman_manage_region(&port_rman, 0, 0xffff)) 17484124Sdfr panic("nexus_probe port_rman"); 17584124Sdfr 17684124Sdfr mem_rman.rm_start = 0; 177221218Sjhb mem_rman.rm_end = ~0ul; 17884124Sdfr mem_rman.rm_type = RMAN_ARRAY; 17984124Sdfr mem_rman.rm_descr = "I/O memory addresses"; 18084124Sdfr if (rman_init(&mem_rman) 18184124Sdfr || rman_manage_region(&mem_rman, 0, ~0)) 18284124Sdfr panic("nexus_probe mem_rman"); 18384124Sdfr 18484124Sdfr return bus_generic_probe(dev); 18584124Sdfr} 18684124Sdfr 18784124Sdfrstatic int 18884124Sdfrnexus_attach(device_t dev) 18984124Sdfr{ 190177157Sjhb 191177157Sjhb if (acpi_identify() == 0) 192177157Sjhb BUS_ADD_CHILD(dev, 10, "acpi", 0); 193178222Smarcel clock_register(dev, 1000); 19484124Sdfr bus_generic_attach(dev); 19584124Sdfr return 0; 19684124Sdfr} 19784124Sdfr 19884124Sdfrstatic int 199163619Smarcelnexus_print_child(device_t bus, device_t child) 20084124Sdfr{ 201163619Smarcel struct nexus_device *ndev = DEVTONX(child); 20284124Sdfr struct resource_list *rl = &ndev->nx_resources; 20384124Sdfr int retval = 0; 20484124Sdfr 20584124Sdfr retval += bus_print_child_header(bus, child); 206163619Smarcel retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 207163619Smarcel retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 208163619Smarcel retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 209136521Snjl if (device_get_flags(child)) 210136521Snjl retval += printf(" flags %#x", device_get_flags(child)); 21184124Sdfr retval += printf(" on motherboard\n"); /* XXX "motherboard", ick */ 21284124Sdfr 21384124Sdfr return (retval); 21484124Sdfr} 21584124Sdfr 21684124Sdfrstatic device_t 217212413Savgnexus_add_child(device_t bus, u_int order, const char *name, int unit) 21884124Sdfr{ 21984124Sdfr device_t child; 22084124Sdfr struct nexus_device *ndev; 22184124Sdfr 22284124Sdfr ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO); 22384124Sdfr if (!ndev) 22484124Sdfr return(0); 22584124Sdfr resource_list_init(&ndev->nx_resources); 22684124Sdfr 22784124Sdfr child = device_add_child_ordered(bus, order, name, unit); 22884124Sdfr 22984124Sdfr /* should we free this in nexus_child_detached? */ 23084124Sdfr device_set_ivars(child, ndev); 23184124Sdfr 23284124Sdfr return(child); 23384124Sdfr} 23484124Sdfr 235224184Sjhbstatic struct rman * 236224184Sjhbnexus_rman(int type) 237224184Sjhb{ 238224184Sjhb switch (type) { 239224184Sjhb case SYS_RES_IRQ: 240224184Sjhb return (&irq_rman); 241224184Sjhb case SYS_RES_IOPORT: 242224184Sjhb return (&port_rman); 243224184Sjhb case SYS_RES_MEMORY: 244224184Sjhb return (&mem_rman); 245224184Sjhb default: 246224184Sjhb return (NULL); 247224184Sjhb } 248224184Sjhb} 24984124Sdfr 25084124Sdfr/* 25184124Sdfr * Allocate a resource on behalf of child. NB: child is usually going to be a 25284124Sdfr * child of one of our descendants, not a direct child of nexus0. 25384124Sdfr * (Exceptions include npx.) 25484124Sdfr */ 25584124Sdfrstatic struct resource * 25684124Sdfrnexus_alloc_resource(device_t bus, device_t child, int type, int *rid, 25784124Sdfr u_long start, u_long end, u_long count, u_int flags) 25884124Sdfr{ 25984124Sdfr struct nexus_device *ndev = DEVTONX(child); 26084124Sdfr struct resource *rv; 26184124Sdfr struct resource_list_entry *rle; 26284124Sdfr struct rman *rm; 26384124Sdfr int needactivate = flags & RF_ACTIVE; 26484124Sdfr 26584124Sdfr /* 26684124Sdfr * If this is an allocation of the "default" range for a given RID, and 26784124Sdfr * we know what the resources for this device are (ie. they aren't maintained 26884124Sdfr * by a child bus), then work out the start/end values. 26984124Sdfr */ 27084124Sdfr if ((start == 0UL) && (end == ~0UL) && (count == 1)) { 27184124Sdfr if (ndev == NULL) 27284124Sdfr return(NULL); 27384124Sdfr rle = resource_list_find(&ndev->nx_resources, type, *rid); 27484124Sdfr if (rle == NULL) 27584124Sdfr return(NULL); 27684124Sdfr start = rle->start; 27784124Sdfr end = rle->end; 27884124Sdfr count = rle->count; 27984124Sdfr } 28084124Sdfr 28184124Sdfr flags &= ~RF_ACTIVE; 282224184Sjhb rm = nexus_rman(type); 283224184Sjhb if (rm == NULL) 284224184Sjhb return (NULL); 28584124Sdfr 28684124Sdfr rv = rman_reserve_resource(rm, start, end, count, flags, child); 28784124Sdfr if (rv == 0) 28884124Sdfr return 0; 289157894Simp rman_set_rid(rv, *rid); 29084124Sdfr 29184124Sdfr if (needactivate) { 29284124Sdfr if (bus_activate_resource(child, type, *rid, rv)) { 29384124Sdfr rman_release_resource(rv); 29484124Sdfr return 0; 29584124Sdfr } 29684124Sdfr } 29784124Sdfr 29884124Sdfr return rv; 29984124Sdfr} 30084124Sdfr 30184124Sdfrstatic int 302224184Sjhbnexus_adjust_resource(device_t bus, device_t child, int type, 303224184Sjhb struct resource *r, u_long start, u_long end) 304224184Sjhb{ 305224184Sjhb struct rman *rm; 306224184Sjhb 307224184Sjhb rm = nexus_rman(type); 308224184Sjhb if (rm == NULL) 309224184Sjhb return (ENXIO); 310224184Sjhb if (!rman_is_region_manager(r, rm)) 311224184Sjhb return (EINVAL); 312224184Sjhb return (rman_adjust_resource(r, start, end)); 313224184Sjhb} 314224184Sjhb 315224184Sjhbstatic int 31684124Sdfrnexus_activate_resource(device_t bus, device_t child, int type, int rid, 317201269Smarcel struct resource *r) 31884124Sdfr{ 319201269Smarcel vm_paddr_t paddr; 320167767Sjhb void *vaddr; 321167767Sjhb 322201269Smarcel paddr = rman_get_start(r); 323201269Smarcel 324167767Sjhb switch (type) { 325167767Sjhb case SYS_RES_IOPORT: 326167767Sjhb rman_set_bustag(r, IA64_BUS_SPACE_IO); 327201269Smarcel rman_set_bushandle(r, paddr); 328167767Sjhb break; 329167767Sjhb case SYS_RES_MEMORY: 330201269Smarcel vaddr = pmap_mapdev(paddr, rman_get_size(r)); 331201269Smarcel rman_set_bustag(r, IA64_BUS_SPACE_MEM); 332201269Smarcel rman_set_bushandle(r, (bus_space_handle_t) vaddr); 33384124Sdfr rman_set_virtual(r, vaddr); 334167767Sjhb break; 33584124Sdfr } 33684124Sdfr return (rman_activate_resource(r)); 33784124Sdfr} 33884124Sdfr 33984124Sdfrstatic int 34084124Sdfrnexus_deactivate_resource(device_t bus, device_t child, int type, int rid, 34184124Sdfr struct resource *r) 34284124Sdfr{ 34384124Sdfr 34484124Sdfr return (rman_deactivate_resource(r)); 34584124Sdfr} 34684124Sdfr 34784124Sdfrstatic int 34884124Sdfrnexus_release_resource(device_t bus, device_t child, int type, int rid, 34984124Sdfr struct resource *r) 35084124Sdfr{ 35184124Sdfr if (rman_get_flags(r) & RF_ACTIVE) { 35284124Sdfr int error = bus_deactivate_resource(child, type, rid, r); 35384124Sdfr if (error) 35484124Sdfr return error; 35584124Sdfr } 35684124Sdfr return (rman_release_resource(r)); 35784124Sdfr} 35884124Sdfr 35984124Sdfr/* 36084124Sdfr * Currently this uses the really grody interface from kern/kern_intr.c 36184124Sdfr * (which really doesn't belong in kern/anything.c). Eventually, all of 36284124Sdfr * the code in kern_intr.c and machdep_intr.c should get moved here, since 36384124Sdfr * this is going to be the official interface. 36484124Sdfr */ 36584124Sdfrstatic int 36684124Sdfrnexus_setup_intr(device_t bus, device_t child, struct resource *irq, 367166901Spiso int flags, driver_filter_t filter, void (*ihand)(void *), 368166901Spiso void *arg, void **cookiep) 36984124Sdfr{ 37084124Sdfr driver_t *driver; 37184124Sdfr int error; 37284124Sdfr 37384124Sdfr /* somebody tried to setup an irq that failed to allocate! */ 37484124Sdfr if (irq == NULL) 37584124Sdfr panic("nexus_setup_intr: NULL irq resource!"); 37684124Sdfr 37784124Sdfr *cookiep = 0; 378151006Sphk if ((rman_get_flags(irq) & RF_SHAREABLE) == 0) 37984124Sdfr flags |= INTR_EXCL; 38084124Sdfr 38184124Sdfr driver = device_get_driver(child); 38284124Sdfr 38384124Sdfr /* 38484124Sdfr * We depend here on rman_activate_resource() being idempotent. 38584124Sdfr */ 38684124Sdfr error = rman_activate_resource(irq); 38784124Sdfr if (error) 38884124Sdfr return (error); 38984124Sdfr 390151006Sphk error = ia64_setup_intr(device_get_nameunit(child), 391171664Smarcel rman_get_start(irq), filter, ihand, arg, flags, cookiep); 39284124Sdfr 39384124Sdfr return (error); 39484124Sdfr} 39584124Sdfr 39684124Sdfrstatic int 397157941Smarcelnexus_teardown_intr(device_t dev, device_t child, struct resource *ires, 398157941Smarcel void *cookie) 39984124Sdfr{ 400157941Smarcel 401157941Smarcel return (ia64_teardown_intr(cookie)); 40284124Sdfr} 40384124Sdfr 404134263Snjlstatic struct resource_list * 405134263Snjlnexus_get_reslist(device_t dev, device_t child) 406134263Snjl{ 407134263Snjl struct nexus_device *ndev = DEVTONX(child); 408134263Snjl 409134263Snjl return (&ndev->nx_resources); 410134263Snjl} 411134263Snjl 41284124Sdfrstatic int 413201269Smarcelnexus_set_resource(device_t dev, device_t child, int type, int rid, 414201269Smarcel u_long start, u_long count) 41584124Sdfr{ 41684124Sdfr struct nexus_device *ndev = DEVTONX(child); 41784124Sdfr struct resource_list *rl = &ndev->nx_resources; 41884124Sdfr 419201269Smarcel if (type == SYS_RES_IOPORT && start > (0x10000 - count)) { 420201269Smarcel /* 421201269Smarcel * Work around a firmware bug in the HP rx2660, where in ACPI 422201269Smarcel * an I/O port is really a memory mapped I/O address. The bug 423201269Smarcel * is in the GAS that describes the address and in particular 424201269Smarcel * the SpaceId field. The field should not say the address is 425201269Smarcel * an I/O port when it is in fact an I/O memory address. 426201269Smarcel */ 427201269Smarcel if (bootverbose) 428201269Smarcel printf("%s: invalid port range (%#lx-%#lx); " 429201269Smarcel "assuming I/O memory range.\n", __func__, start, 430201269Smarcel start + count - 1); 431201269Smarcel type = SYS_RES_MEMORY; 432201269Smarcel } 433201269Smarcel 43484124Sdfr /* XXX this should return a success/failure indicator */ 43584124Sdfr resource_list_add(rl, type, rid, start, start + count - 1, count); 43684124Sdfr return(0); 43784124Sdfr} 43884124Sdfr 43984124Sdfrstatic int 44084124Sdfrnexus_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp) 44184124Sdfr{ 44284124Sdfr struct nexus_device *ndev = DEVTONX(child); 44384124Sdfr struct resource_list *rl = &ndev->nx_resources; 44484124Sdfr struct resource_list_entry *rle; 44584124Sdfr 44684124Sdfr rle = resource_list_find(rl, type, rid); 44784124Sdfr device_printf(child, "type %d rid %d startp %p countp %p - got %p\n", 44884124Sdfr type, rid, startp, countp, rle); 44984124Sdfr if (!rle) 45084124Sdfr return(ENOENT); 45184124Sdfr if (startp) 45284124Sdfr *startp = rle->start; 45384124Sdfr if (countp) 45484124Sdfr *countp = rle->count; 45584124Sdfr return(0); 45684124Sdfr} 45784124Sdfr 45884124Sdfrstatic void 45984124Sdfrnexus_delete_resource(device_t dev, device_t child, int type, int rid) 46084124Sdfr{ 46184124Sdfr struct nexus_device *ndev = DEVTONX(child); 46284124Sdfr struct resource_list *rl = &ndev->nx_resources; 46384124Sdfr 46484124Sdfr resource_list_delete(rl, type, rid); 46584124Sdfr} 46684124Sdfr 467119970Smarcelstatic int 468119970Smarcelnexus_config_intr(device_t dev, int irq, enum intr_trigger trig, 469119970Smarcel enum intr_polarity pol) 470119970Smarcel{ 471119970Smarcel 472119970Smarcel return (sapic_config_intr(irq, trig, pol)); 473119970Smarcel} 474119970Smarcel 475178222Smarcelstatic int 476205726Smarcelnexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu) 477205726Smarcel{ 478205726Smarcel struct pcpu *pc; 479205726Smarcel 480205726Smarcel pc = cpuid_to_pcpu[cpu]; 481205726Smarcel if (pc == NULL) 482205726Smarcel return (EINVAL); 483205726Smarcel return (sapic_bind_intr(rman_get_start(irq), pc)); 484205726Smarcel} 485205726Smarcel 486205726Smarcelstatic int 487178222Smarcelnexus_gettime(device_t dev, struct timespec *ts) 488178222Smarcel{ 489178222Smarcel struct clocktime ct; 490178222Smarcel struct efi_tm tm; 49184124Sdfr 492178222Smarcel efi_get_time(&tm); 49384124Sdfr 494178222Smarcel /* 495178222Smarcel * This code was written in 2005, so logically EFI cannot return 496178222Smarcel * a year smaller than that. Assume the EFI clock is out of whack 497178222Smarcel * in that case and reset the EFI clock. 498178222Smarcel */ 499178222Smarcel if (tm.tm_year < 2005) 500178222Smarcel return (EINVAL); 501178222Smarcel 502178222Smarcel ct.nsec = tm.tm_nsec; 503178222Smarcel ct.sec = tm.tm_sec; 504178222Smarcel ct.min = tm.tm_min; 505178222Smarcel ct.hour = tm.tm_hour; 506178222Smarcel ct.day = tm.tm_mday; 507178222Smarcel ct.mon = tm.tm_mon; 508178222Smarcel ct.year = tm.tm_year; 509178222Smarcel ct.dow = -1; 510178222Smarcel return (clock_ct_to_ts(&ct, ts)); 51184124Sdfr} 51284124Sdfr 51384124Sdfrstatic int 514178222Smarcelnexus_settime(device_t dev, struct timespec *ts) 51584124Sdfr{ 516178222Smarcel struct clocktime ct; 517178222Smarcel struct efi_tm tm; 51884124Sdfr 519178222Smarcel efi_get_time(&tm); 52084124Sdfr 521178222Smarcel clock_ts_to_ct(ts, &ct); 522178222Smarcel tm.tm_nsec = ts->tv_nsec; 523178222Smarcel tm.tm_sec = ct.sec; 524178222Smarcel tm.tm_min = ct.min; 525178222Smarcel tm.tm_hour = ct.hour; 526178222Smarcel tm.tm_year = ct.year; 527178222Smarcel tm.tm_mon = ct.mon; 528178222Smarcel tm.tm_mday = ct.day; 529178222Smarcel return (efi_set_time(&tm)); 530178222Smarcel} 531