From owner-svn-src-all@FreeBSD.ORG Mon Oct 21 21:13:02 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id A16556B4; Mon, 21 Oct 2013 21:13:02 +0000 (UTC) (envelope-from brooks@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 8DDDD2686; Mon, 21 Oct 2013 21:13:02 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r9LLD2mm060006; Mon, 21 Oct 2013 21:13:02 GMT (envelope-from brooks@svn.freebsd.org) Received: (from brooks@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r9LLD1ZB059998; Mon, 21 Oct 2013 21:13:01 GMT (envelope-from brooks@svn.freebsd.org) Message-Id: <201310212113.r9LLD1ZB059998@svn.freebsd.org> From: Brooks Davis Date: Mon, 21 Oct 2013 21:13:01 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r256861 - in head/sys: conf dev/fdt X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Oct 2013 21:13:02 -0000 Author: brooks Date: Mon Oct 21 21:13:01 2013 New Revision: 256861 URL: http://svnweb.freebsd.org/changeset/base/256861 Log: MFP4: 223121 (FDT infrastructure portion) Implement support for interrupt-parent nodes in simplebus. The current implementation requires that device declarations have an interrupt-parent node and that it point to a device that has registered itself as a interrupt controller in fdt_ic_list_head and implements the fdt_ic interface. Sponsored by: DARPA/AFRL Added: head/sys/dev/fdt/fdt_ic_if.m (contents, props changed) - copied, changed from r256860, head/sys/kern/bus_if.m Modified: head/sys/conf/files head/sys/dev/fdt/fdt_common.c head/sys/dev/fdt/fdt_common.h head/sys/dev/fdt/simplebus.c Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Mon Oct 21 20:51:08 2013 (r256860) +++ head/sys/conf/files Mon Oct 21 21:13:01 2013 (r256861) @@ -1401,6 +1401,7 @@ dev/exca/exca.c optional cbb dev/fatm/if_fatm.c optional fatm pci dev/fb/splash.c optional splash dev/fdt/fdt_common.c optional fdt +dev/fdt/fdt_ic_if.m optional fdt dev/fdt/fdt_pci.c optional fdt pci dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ Modified: head/sys/dev/fdt/fdt_common.c ============================================================================== --- head/sys/dev/fdt/fdt_common.c Mon Oct 21 20:51:08 2013 (r256860) +++ head/sys/dev/fdt/fdt_common.c Mon Oct 21 21:13:01 2013 (r256861) @@ -63,6 +63,8 @@ vm_paddr_t fdt_immr_pa; vm_offset_t fdt_immr_va; vm_offset_t fdt_immr_size; +struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); + int fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) { Modified: head/sys/dev/fdt/fdt_common.h ============================================================================== --- head/sys/dev/fdt/fdt_common.h Mon Oct 21 20:51:08 2013 (r256860) +++ head/sys/dev/fdt/fdt_common.h Mon Oct 21 21:13:01 2013 (r256861) @@ -70,6 +70,13 @@ struct fdt_fixup_entry { }; extern struct fdt_fixup_entry fdt_fixup_table[]; +extern SLIST_HEAD(fdt_ic_list, fdt_ic) fdt_ic_list_head; +struct fdt_ic { + SLIST_ENTRY(fdt_ic) fdt_ics; + ihandle_t iph; + device_t dev; +}; + extern vm_paddr_t fdt_immr_pa; extern vm_offset_t fdt_immr_va; extern vm_offset_t fdt_immr_size; Copied and modified: head/sys/dev/fdt/fdt_ic_if.m (from r256860, head/sys/kern/bus_if.m) ============================================================================== --- head/sys/kern/bus_if.m Mon Oct 21 20:51:08 2013 (r256860, copy source) +++ head/sys/dev/fdt/fdt_ic_if.m Mon Oct 21 21:13:01 2013 (r256861) @@ -1,4 +1,5 @@ #- +# Copyright (c) 2013 SRI International # Copyright (c) 1998-2004 Doug Rabson # All rights reserved. # @@ -31,327 +32,79 @@ #include /** - * @defgroup BUS bus - KObj methods for drivers of devices with children - * @brief A set of methods required device drivers that support - * child devices. + * @defgroup FST_IC fdt_ic - KObj methods for interrupt controllers + * @brief A set of methods required device drivers that are interrupt + * controllers. Derived from sys/kern/bus_if.m. * @{ */ -INTERFACE bus; - -# -# Default implementations of some methods. -# -CODE { - static struct resource * - null_alloc_resource(device_t dev, device_t child, - int type, int *rid, u_long start, u_long end, - u_long count, u_int flags) - { - return (0); - } - - static int - null_remap_intr(device_t bus, device_t dev, u_int irq) - { - - if (dev != NULL) - return (BUS_REMAP_INTR(dev, NULL, irq)); - return (ENXIO); - } - - static device_t - null_add_child(device_t bus, int order, const char *name, - int unit) - { - - panic("bus_add_child is not implemented"); - } -}; - -/** - * @brief Print a description of a child device - * - * This is called from system code which prints out a description of a - * device. It should describe the attachment that the child has with - * the parent. For instance the TurboLaser bus prints which node the - * device is attached to. See bus_generic_print_child() for more - * information. - * - * @param _dev the device whose child is being printed - * @param _child the child device to describe - * - * @returns the number of characters output. - */ -METHOD int print_child { - device_t _dev; - device_t _child; -} DEFAULT bus_generic_print_child; - -/** - * @brief Print a notification about an unprobed child device. - * - * Called for each child device that did not succeed in probing for a - * driver. - * - * @param _dev the device whose child was being probed - * @param _child the child device which failed to probe - */ -METHOD void probe_nomatch { - device_t _dev; - device_t _child; -}; - -/** - * @brief Read the value of a bus-specific attribute of a device - * - * This method, along with BUS_WRITE_IVAR() manages a bus-specific set - * of instance variables of a child device. The intention is that - * each different type of bus defines a set of appropriate instance - * variables (such as ports and irqs for ISA bus etc.) - * - * This information could be given to the child device as a struct but - * that makes it hard for a bus to add or remove variables without - * forcing an edit and recompile for all drivers which may not be - * possible for vendor supplied binary drivers. - * - * This method copies the value of an instance variable to the - * location specified by @p *_result. - * - * @param _dev the device whose child was being examined - * @param _child the child device whose instance variable is - * being read - * @param _index the instance variable to read - * @param _result a loction to recieve the instance variable - * value - * - * @retval 0 success - * @retval ENOENT no such instance variable is supported by @p - * _dev - */ -METHOD int read_ivar { - device_t _dev; - device_t _child; - int _index; - uintptr_t *_result; -}; - -/** - * @brief Write the value of a bus-specific attribute of a device - * - * This method sets the value of an instance variable to @p _value. - * - * @param _dev the device whose child was being updated - * @param _child the child device whose instance variable is - * being written - * @param _index the instance variable to write - * @param _value the value to write to that instance variable - * - * @retval 0 success - * @retval ENOENT no such instance variable is supported by @p - * _dev - * @retval EINVAL the instance variable was recognised but - * contains a read-only value - */ -METHOD int write_ivar { - device_t _dev; - device_t _child; - int _indx; - uintptr_t _value; -}; +INTERFACE fdt_ic; /** - * @brief Notify a bus that a child was deleted + * @brief Allocate an interrupt resource * - * Called at the beginning of device_delete_child() to allow the parent - * to teardown any bus-specific state for the child. - * - * @param _dev the device whose child is being deleted - * @param _child the child device which is being deleted - */ -METHOD void child_deleted { - device_t _dev; - device_t _child; -}; - -/** - * @brief Notify a bus that a child was detached + * This method is called by child devices of an interrupt controller to + * allocate an interrup. The meaning of the resource-ID field varies + * from bus to bus and is opaque to the interrupt controller. If a + * resource was allocated and the caller did not use the RF_ACTIVE + * to specify that it should be activated immediately, the caller is + * responsible for calling FDT_IC_ACTIVATE_INTR() when it actually uses + * the interupt. * - * Called after the child's DEVICE_DETACH() method to allow the parent - * to reclaim any resources allocated on behalf of the child. - * - * @param _dev the device whose child changed state - * @param _child the child device which changed state - */ -METHOD void child_detached { - device_t _dev; - device_t _child; -}; - -/** - * @brief Notify a bus that a new driver was added - * - * Called when a new driver is added to the devclass which owns this - * bus. The generic implementation of this method attempts to probe and - * attach any un-matched children of the bus. - * - * @param _dev the device whose devclass had a new driver - * added to it - * @param _driver the new driver which was added - */ -METHOD void driver_added { - device_t _dev; - driver_t *_driver; -} DEFAULT bus_generic_driver_added; - -/** - * @brief Create a new child device - * - * For busses which use use drivers supporting DEVICE_IDENTIFY() to - * enumerate their devices, this method is used to create new - * device instances. The new device will be added after the last - * existing child with the same order. - * - * @param _dev the bus device which will be the parent of the - * new child device - * @param _order a value which is used to partially sort the - * children of @p _dev - devices created using - * lower values of @p _order appear first in @p - * _dev's list of children - * @param _name devclass name for new device or @c NULL if not - * specified - * @param _unit unit number for new device or @c -1 if not - * specified - */ -METHOD device_t add_child { - device_t _dev; - u_int _order; - const char *_name; - int _unit; -} DEFAULT null_add_child; - -/** - * @brief Allocate a system resource - * - * This method is called by child devices of a bus to allocate resources. - * The types are defined in ; the meaning of the - * resource-ID field varies from bus to bus (but @p *rid == 0 is always - * valid if the resource type is). If a resource was allocated and the - * caller did not use the RF_ACTIVE to specify that it should be - * activated immediately, the caller is responsible for calling - * BUS_ACTIVATE_RESOURCE() when it actually uses the resource. - * - * @param _dev the parent device of @p _child + * @param _dev the interrupt-parent device of @p _child * @param _child the device which is requesting an allocation - * @param _type the type of resource to allocate * @param _rid a pointer to the resource identifier - * @param _start hint at the start of the resource range - pass - * @c 0UL for any start address - * @param _end hint at the end of the resource range - pass - * @c ~0UL for any end address - * @param _count hint at the size of range required - pass @c 1 - * for any size + * @param _irq interrupt source to allocate * @param _flags any extra flags to control the resource * allocation - see @c RF_XXX flags in * for details * - * @returns the resource which was allocated or @c NULL if no + * @returns the interrupt which was allocated or @c NULL if no * resource could be allocated */ -METHOD struct resource * alloc_resource { +METHOD struct resource * alloc_intr { device_t _dev; device_t _child; - int _type; int *_rid; - u_long _start; - u_long _end; - u_long _count; + u_long _irq; u_int _flags; -} DEFAULT null_alloc_resource; - -/** - * @brief Activate a resource - * - * Activate a resource previously allocated with - * BUS_ALLOC_RESOURCE(). This may for instance map a memory region - * into the kernel's virtual address space. - * - * @param _dev the parent device of @p _child - * @param _child the device which allocated the resource - * @param _type the type of resource - * @param _rid the resource identifier - * @param _r the resource to activate - */ -METHOD int activate_resource { - device_t _dev; - device_t _child; - int _type; - int _rid; - struct resource *_r; }; /** - * @brief Deactivate a resource + * @brief Activate an interrupt * - * Deactivate a resource previously allocated with - * BUS_ALLOC_RESOURCE(). This may for instance unmap a memory region - * from the kernel's virtual address space. + * Activate an interrupt previously allocated with FDT_IC_ALLOC_INTR(). * * @param _dev the parent device of @p _child - * @param _child the device which allocated the resource - * @param _type the type of resource - * @param _rid the resource identifier - * @param _r the resource to deactivate + * @param _r interrupt to activate */ -METHOD int deactivate_resource { +METHOD int activate_intr { device_t _dev; - device_t _child; - int _type; - int _rid; struct resource *_r; }; /** - * @brief Adjust a resource + * @brief Deactivate an interrupt * - * Adjust the start and/or end of a resource allocated by - * BUS_ALLOC_RESOURCE. At least part of the new address range must overlap - * with the existing address range. If the successful, the resource's range - * will be adjusted to [start, end] on return. + * Deactivate a resource previously allocated with FDT_IC_ALLOC_INTR(). * * @param _dev the parent device of @p _child - * @param _child the device which allocated the resource - * @param _type the type of resource - * @param _res the resource to adjust - * @param _start the new starting address of the resource range - * @param _end the new ending address of the resource range + * @param _r the interrupt to deactivate */ -METHOD int adjust_resource { +METHOD int deactivate_intr { device_t _dev; - device_t _child; - int _type; - struct resource *_res; - u_long _start; - u_long _end; + struct resource *_r; }; /** - * @brief Release a resource + * @brief Release an interrupt * - * Free a resource allocated by the BUS_ALLOC_RESOURCE. The @p _rid - * value must be the same as the one returned by BUS_ALLOC_RESOURCE() - * (which is not necessarily the same as the one the client passed). + * Free an interupt allocated by the FDT_IC_ALLOC_INTR. * * @param _dev the parent device of @p _child - * @param _child the device which allocated the resource - * @param _type the type of resource - * @param _rid the resource identifier * @param _r the resource to release */ -METHOD int release_resource { +METHOD int release_intr { device_t _dev; - device_t _child; - int _type; - int _rid; struct resource *_res; }; @@ -363,9 +116,9 @@ METHOD int release_resource { * will be called with the value of @p _arg as its single * argument. The value returned in @p *_cookiep is used to cancel the * interrupt handler - the caller should save this value to use in a - * future call to BUS_TEARDOWN_INTR(). + * future call to FDT_IC_TEARDOWN_INTR(). * - * @param _dev the parent device of @p _child + * @param _dev the interrupt-parent device of @p _child * @param _child the device which allocated the resource * @param _irq the resource representing the interrupt * @param _flags a set of bits from enum intr_type specifying @@ -394,9 +147,9 @@ METHOD int setup_intr { * * This method is used to disassociate an interrupt handler function * with an irq resource. The value of @p _cookie must be the value - * returned from a previous call to BUS_SETUP_INTR(). + * returned from a previous call to FDT_IC_SETUP_INTR(). * - * @param _dev the parent device of @p _child + * @param _dev the interrupt-parent device of @p _child * @param _child the device which allocated the resource * @param _irq the resource representing the interrupt * @param _cookie the cookie value returned when the interrupt @@ -410,151 +163,10 @@ METHOD int teardown_intr { }; /** - * @brief Define a resource which can be allocated with - * BUS_ALLOC_RESOURCE(). - * - * This method is used by some busses (typically ISA) to allow a - * driver to describe a resource range that it would like to - * allocate. The resource defined by @p _type and @p _rid is defined - * to start at @p _start and to include @p _count indices in its - * range. - * - * @param _dev the parent device of @p _child - * @param _child the device which owns the resource - * @param _type the type of resource - * @param _rid the resource identifier - * @param _start the start of the resource range - * @param _count the size of the resource range - */ -METHOD int set_resource { - device_t _dev; - device_t _child; - int _type; - int _rid; - u_long _start; - u_long _count; -}; - -/** - * @brief Describe a resource - * - * This method allows a driver to examine the range used for a given - * resource without actually allocating it. - * - * @param _dev the parent device of @p _child - * @param _child the device which owns the resource - * @param _type the type of resource - * @param _rid the resource identifier - * @param _start the address of a location to recieve the start - * index of the resource range - * @param _count the address of a location to recieve the size - * of the resource range - */ -METHOD int get_resource { - device_t _dev; - device_t _child; - int _type; - int _rid; - u_long *_startp; - u_long *_countp; -}; - -/** - * @brief Delete a resource. - * - * Use this to delete a resource (possibly one previously added with - * BUS_SET_RESOURCE()). - * - * @param _dev the parent device of @p _child - * @param _child the device which owns the resource - * @param _type the type of resource - * @param _rid the resource identifier - */ -METHOD void delete_resource { - device_t _dev; - device_t _child; - int _type; - int _rid; -}; - -/** - * @brief Return a struct resource_list. - * - * Used by drivers which use bus_generic_rl_alloc_resource() etc. to - * implement their resource handling. It should return the resource - * list of the given child device. - * - * @param _dev the parent device of @p _child - * @param _child the device which owns the resource list - */ -METHOD struct resource_list * get_resource_list { - device_t _dev; - device_t _child; -} DEFAULT bus_generic_get_resource_list; - -/** - * @brief Is the hardware described by @p _child still attached to the - * system? - * - * This method should return 0 if the device is not present. It - * should return -1 if it is present. Any errors in determining - * should be returned as a normal errno value. Client drivers are to - * assume that the device is present, even if there is an error - * determining if it is there. Busses are to try to avoid returning - * errors, but newcard will return an error if the device fails to - * implement this method. - * - * @param _dev the parent device of @p _child - * @param _child the device which is being examined - */ -METHOD int child_present { - device_t _dev; - device_t _child; -} DEFAULT bus_generic_child_present; - -/** - * @brief Returns the pnp info for this device. - * - * Return it as a string. If the string is insufficient for the - * storage, then return EOVERFLOW. - * - * @param _dev the parent device of @p _child - * @param _child the device which is being examined - * @param _buf the address of a buffer to receive the pnp - * string - * @param _buflen the size of the buffer pointed to by @p _buf - */ -METHOD int child_pnpinfo_str { - device_t _dev; - device_t _child; - char *_buf; - size_t _buflen; -}; - -/** - * @brief Returns the location for this device. - * - * Return it as a string. If the string is insufficient for the - * storage, then return EOVERFLOW. - * - * @param _dev the parent device of @p _child - * @param _child the device which is being examined - * @param _buf the address of a buffer to receive the location - * string - * @param _buflen the size of the buffer pointed to by @p _buf - */ -METHOD int child_location_str { - device_t _dev; - device_t _child; - char *_buf; - size_t _buflen; -}; - -/** * @brief Allow drivers to request that an interrupt be bound to a specific * CPU. * - * @param _dev the parent device of @p _child + * @param _dev the interrupt-parent device of @p _child * @param _child the device which allocated the resource * @param _irq the resource representing the interrupt * @param _cpu the CPU to bind the interrupt to @@ -564,13 +176,13 @@ METHOD int bind_intr { device_t _child; struct resource *_irq; int _cpu; -} DEFAULT bus_generic_bind_intr; +}; /** - * @brief Allow (bus) drivers to specify the trigger mode and polarity + * @brief Allow drivers to specify the trigger mode and polarity * of the specified interrupt. * - * @param _dev the bus device + * @param _dev the interrupt-parent device * @param _irq the interrupt number to modify * @param _trig the trigger mode required * @param _pol the interrupt polarity required @@ -580,13 +192,13 @@ METHOD int config_intr { int _irq; enum intr_trigger _trig; enum intr_polarity _pol; -} DEFAULT bus_generic_config_intr; +}; /** * @brief Allow drivers to associate a description with an active * interrupt handler. * - * @param _dev the parent device of @p _child + * @param _dev the interrupt-parent device of @p _child * @param _child the device which allocated the resource * @param _irq the resource representing the interrupt * @param _cookie the cookie value returned when the interrupt @@ -599,74 +211,56 @@ METHOD int describe_intr { struct resource *_irq; void *_cookie; const char *_descr; -} DEFAULT bus_generic_describe_intr; - -/** - * @brief Notify a (bus) driver about a child that the hints mechanism - * believes it has discovered. - * - * The bus is responsible for then adding the child in the right order - * and discovering other things about the child. The bus driver is - * free to ignore this hint, to do special things, etc. It is all up - * to the bus driver to interpret. - * - * This method is only called in response to the parent bus asking for - * hinted devices to be enumerated. - * - * @param _dev the bus device - * @param _dname the name of the device w/o unit numbers - * @param _dunit the unit number of the device - */ -METHOD void hinted_child { - device_t _dev; - const char *_dname; - int _dunit; }; /** - * @brief Returns bus_dma_tag_t for use w/ devices on the bus. + * @brief Notify an ic that specified child's IRQ should be remapped. * - * @param _dev the parent device of @p _child - * @param _child the device to which the tag will belong + * @param _dev the interrupt-parent device + * @param _child the child device + * @param _irq the irq number */ -METHOD bus_dma_tag_t get_dma_tag { +METHOD int remap_intr { device_t _dev; device_t _child; -} DEFAULT bus_generic_get_dma_tag; + u_int _irq; +}; /** - * @brief Allow the bus to determine the unit number of a device. + * @brief Enable an IPI source. * - * @param _dev the parent device of @p _child - * @param _child the device whose unit is to be wired - * @param _name the name of the device's new devclass - * @param _unitp a pointer to the device's new unit value + * @param _dev the interrupt controller + * @param _tid the thread ID (relative to the interrupt controller) + * to enable IPIs for + * @param _ipi_irq hardware IRQ to send IPIs to */ -METHOD void hint_device_unit { +METHOD void setup_ipi { device_t _dev; - device_t _child; - const char *_name; - int *_unitp; + u_int _tid; + u_int _irq; }; /** - * @brief Notify a bus that the bus pass level has been changed + * @brief Send an IPI to the specified thread. * - * @param _dev the bus device + * @param _dev the interrupt controller + * @param _tid the thread ID (relative to the interrupt controller) + * to send IPIs to */ -METHOD void new_pass { +METHOD void send_ipi { device_t _dev; -} DEFAULT bus_generic_new_pass; + u_int _tid; +}; /** - * @brief Notify a bus that specified child's IRQ should be remapped. + * @brief Clear the IPI on the specfied thread. Only call with the + * local hardware thread or interrupts may be lost! * - * @param _dev the bus device - * @param _child the child device - * @param _irq the irq number + * @param _dev the interrupt controller + * @param _tid the thread ID (relative to the interrupt controller) + * to clear the IPI on */ -METHOD int remap_intr { +METHOD void clear_ipi { device_t _dev; - device_t _child; - u_int _irq; -} DEFAULT null_remap_intr; + u_int _tid; +}; Modified: head/sys/dev/fdt/simplebus.c ============================================================================== --- head/sys/dev/fdt/simplebus.c Mon Oct 21 20:51:08 2013 (r256860) +++ head/sys/dev/fdt/simplebus.c Mon Oct 21 21:13:01 2013 (r256861) @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include "fdt_common.h" +#include "fdt_ic_if.h" #include "ofw_bus_if.h" #ifdef DEBUG @@ -80,9 +81,18 @@ static int simplebus_attach(device_t); static int simplebus_print_child(device_t, device_t); static int simplebus_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); +static int simplebus_teardown_intr(device_t, device_t, struct resource *, + void *); +static int simplebus_activate_resource(device_t, device_t, int, int, + struct resource *); static struct resource *simplebus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); +static int simplebus_deactivate_resource(device_t, device_t, int, int, + struct resource *); +static int simplebus_release_resource(device_t, device_t, int, int, + struct resource *); +static device_t simplebus_get_interrupt_parent(device_t); static struct resource_list *simplebus_get_resource_list(device_t, device_t); static ofw_bus_get_devinfo_t simplebus_get_devinfo; @@ -102,11 +112,11 @@ static device_method_t simplebus_methods /* Bus interface */ DEVMETHOD(bus_print_child, simplebus_print_child), 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_release_resource, simplebus_release_resource), + DEVMETHOD(bus_activate_resource, simplebus_activate_resource), + DEVMETHOD(bus_deactivate_resource, simplebus_deactivate_resource), DEVMETHOD(bus_setup_intr, simplebus_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_teardown_intr, simplebus_teardown_intr), DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list), /* OFW bus interface */ @@ -217,6 +227,7 @@ simplebus_attach(device_t dev) static int simplebus_print_child(device_t dev, device_t child) { + device_t ip; struct simplebus_devinfo *di; struct resource_list *rl; int rv; @@ -228,6 +239,8 @@ simplebus_print_child(device_t dev, devi rv += bus_print_child_header(dev, child); rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); + if ((ip = simplebus_get_interrupt_parent(child)) != NULL) + rv += printf(" (%s)", device_get_nameunit(ip)); rv += bus_print_child_footer(dev, child); return (rv); @@ -237,6 +250,7 @@ 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) { + device_t ic; struct simplebus_devinfo *di; struct resource_list_entry *rle; @@ -263,10 +277,53 @@ simplebus_alloc_resource(device_t bus, d count = rle->count; } + if (type == SYS_RES_IRQ && + (ic = simplebus_get_interrupt_parent(child)) != NULL) + return(FDT_IC_ALLOC_INTR(ic, child, rid, start, flags)); + return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); } +static int +simplebus_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + device_t ic; + + if (type == SYS_RES_IRQ && + (ic = simplebus_get_interrupt_parent(child)) != NULL) + return (FDT_IC_ACTIVATE_INTR(ic, r)); + + return (bus_generic_activate_resource(dev, child, type, rid, r)); +} + +static int +simplebus_deactivate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + device_t ic; + + if (type == SYS_RES_IRQ && + (ic = simplebus_get_interrupt_parent(child)) != NULL) + return (FDT_IC_DEACTIVATE_INTR(ic, r)); + + return (bus_generic_deactivate_resource(dev, child, type, rid, r)); +} + +static int +simplebus_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + device_t ic; + + if (type == SYS_RES_IRQ && + (ic = simplebus_get_interrupt_parent(child)) != NULL) + return (FDT_IC_RELEASE_INTR(ic, r)); + + return (bus_generic_release_resource(dev, child, type, rid, r)); +} + static struct resource_list * simplebus_get_resource_list(device_t bus, device_t child) { @@ -276,15 +333,45 @@ simplebus_get_resource_list(device_t bus return (&di->di_res); } +static device_t +simplebus_get_interrupt_parent(device_t dev) +{ + struct simplebus_devinfo *di; + struct fdt_ic *ic; + device_t ip; + ihandle_t iph; + phandle_t ph; + + ip = NULL; + + di = device_get_ivars(dev); + if (di == NULL) + return (NULL); + + if (OF_getprop(di->di_ofw.obd_node, "interrupt-parent", &iph, + sizeof(iph)) > 0) { + iph = fdt32_to_cpu(iph); + ph = OF_instance_to_package(iph); + SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) { + if (ic->iph == ph) { + ip = ic->dev; + break; + } + } + } + return (ip); +} + static int simplebus_setup_intr(device_t bus, device_t child, struct resource *res, int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep) { struct simplebus_devinfo *di; + device_t ic; enum intr_trigger trig; enum intr_polarity pol; - int error, rid; + int error, irq, rid; di = device_get_ivars(child); if (di == NULL) @@ -297,20 +384,41 @@ simplebus_setup_intr(device_t bus, devic if (rid >= DI_MAX_INTR_NUM) return (ENOENT); + ic = simplebus_get_interrupt_parent(child); + trig = di->di_intr_sl[rid].trig; pol = di->di_intr_sl[rid].pol; if (trig != INTR_TRIGGER_CONFORM || pol != INTR_POLARITY_CONFORM) { - error = bus_generic_config_intr(bus, rman_get_start(res), - trig, pol); + irq = rman_get_start(res); + if (ic != NULL) + error = FDT_IC_CONFIG_INTR(ic, irq, trig, pol); + else + error = bus_generic_config_intr(bus, irq, trig, pol); if (error) return (error); } - error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand, - arg, cookiep); + if (ic != NULL) + error = FDT_IC_SETUP_INTR(ic, child, res, flags, filter, + ihand, arg, cookiep); + else + error = bus_generic_setup_intr(bus, child, res, flags, filter, + ihand, arg, cookiep); return (error); } +static int +simplebus_teardown_intr(device_t bus, device_t child, struct resource *res, + void *cookie) +{ + device_t ic; + + if ((ic = simplebus_get_interrupt_parent(child)) != NULL) + return (FDT_IC_TEARDOWN_INTR(ic, child, res, cookie)); + + return (bus_generic_teardown_intr(bus, child, res, cookie)); +} + static const struct ofw_bus_devinfo * simplebus_get_devinfo(device_t bus, device_t child) {