The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/sparc64/isa/isa.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1998 Doug Rabson
    3  * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  *      from: FreeBSD: src/sys/alpha/isa/isa.c,v 1.26 2001/07/11
   28  *
   29  * $FreeBSD: src/sys/sparc64/isa/isa.c,v 1.13 2004/08/12 17:41:32 marius Exp $
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 
   36 #include <machine/bus.h>
   37 
   38 #include <sys/rman.h>
   39 
   40 #include <isa/isareg.h>
   41 #include <isa/isavar.h>
   42 #include <isa/isa_common.h>
   43 
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/openfirm.h>
   46 
   47 #include <machine/resource.h>
   48 
   49 #include <dev/pci/pcireg.h>
   50 #include <dev/pci/pcivar.h>
   51 
   52 #include <sparc64/pci/ofw_pci.h>
   53 #include <sparc64/isa/ofw_isa.h>
   54 
   55 /* There can be only one ISA bus, so it is safe to use globals. */
   56 bus_space_tag_t isa_io_bt = NULL;
   57 bus_space_handle_t isa_io_hdl;
   58 bus_space_tag_t isa_mem_bt = NULL;
   59 bus_space_handle_t isa_mem_hdl;
   60 
   61 static u_int64_t isa_io_base;
   62 static u_int64_t isa_io_limit;
   63 static u_int64_t isa_mem_base;
   64 static u_int64_t isa_mem_limit;
   65 
   66 device_t isa_bus_device;
   67 
   68 static phandle_t isab_node;
   69 static ofw_pci_intr_t isa_ino[8];
   70 struct ofw_bus_iinfo isa_iinfo;
   71 
   72 /*
   73  * XXX: This is really partly partly PCI-specific, but unfortunately is
   74  * differently enough to have to duplicate it here...
   75  */
   76 #define ISAB_RANGE_PHYS(r)                                              \
   77         (((u_int64_t)(r)->phys_mid << 32) | (u_int64_t)(r)->phys_lo)
   78 #define ISAB_RANGE_SPACE(r)     (((r)->phys_hi >> 24) & 0x03)
   79 
   80 #define ISAR_SPACE_IO           0x01
   81 #define ISAR_SPACE_MEM          0x02
   82 
   83 #define INRANGE(x, start, end)  ((x) >= (start) && (x) <= (end))
   84 
   85 static int isa_route_intr_res(device_t, u_long, u_long);
   86 
   87 intrmask_t
   88 isa_irq_pending(void)
   89 {
   90         intrmask_t pending;
   91         int i;
   92 
   93         /* XXX: Is this correct? */
   94         for (i = 7, pending = 0; i >= 0; i--) {
   95                 pending <<= 1;
   96                 if (isa_ino[i] != PCI_INVALID_IRQ) {
   97                         pending |= (OFW_PCI_INTR_PENDING(isa_bus_device,
   98                             isa_ino[i]) == 0) ? 0 : 1;
   99                 }
  100         }
  101         return (pending);
  102 }
  103 
  104 void
  105 isa_init(device_t dev)
  106 {
  107         device_t bridge;
  108         phandle_t node;
  109         ofw_isa_intr_t ino;
  110         struct isa_ranges *br;
  111         int nbr, i;
  112 
  113         /* The parent of the bus must be a PCI-ISA bridge. */
  114         bridge = device_get_parent(dev);
  115         isab_node = ofw_bus_get_node(bridge);
  116         nbr = OF_getprop_alloc(isab_node, "ranges", sizeof(*br), (void **)&br);
  117         if (nbr <= 0)
  118                 panic("isa_init: cannot get bridge range property");
  119 
  120         ofw_bus_setup_iinfo(isab_node, &isa_iinfo, sizeof(ofw_isa_intr_t));
  121 
  122         /*
  123          * This is really a bad kludge; however, it is needed to provide
  124          * isa_irq_pending(), which is unfortunately still used by some
  125          * drivers.
  126          */
  127         for (i = 0; i < 8; i++)
  128                 isa_ino[i] = PCI_INVALID_IRQ;
  129         for (node = OF_child(isab_node); node != 0; node = OF_peer(node)) {
  130                 if (OF_getprop(node, "interrupts", &ino, sizeof(ino)) == -1)
  131                         continue;
  132                 if (ino > 7)
  133                         panic("isa_init: XXX: ino too large");
  134                 isa_ino[ino] = ofw_isa_route_intr(bridge, node, &isa_iinfo,
  135                     ino);
  136         }
  137 
  138         for (nbr -= 1; nbr >= 0; nbr--) {
  139                 switch(ISAB_RANGE_SPACE(br + nbr)) {
  140                 case ISAR_SPACE_IO:
  141                         /* This is probably always 0. */
  142                         isa_io_base = ISAB_RANGE_PHYS(&br[nbr]);
  143                         isa_io_limit = br[nbr].size;
  144                         isa_io_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
  145                             SYS_RES_IOPORT, isa_io_base, &isa_io_bt);
  146                         break;
  147                 case ISAR_SPACE_MEM:
  148                         /* This is probably always 0. */
  149                         isa_mem_base = ISAB_RANGE_PHYS(&br[nbr]);
  150                         isa_mem_limit = br[nbr].size;
  151                         isa_mem_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
  152                             SYS_RES_MEMORY, isa_mem_base, &isa_mem_bt);
  153                         break;
  154                 }
  155         }
  156         free(br, M_OFWPROP);
  157 }
  158 
  159 static int
  160 isa_route_intr_res(device_t bus, u_long start, u_long end)
  161 {
  162         int res;
  163 
  164         if (start != end) {
  165                 panic("isa_route_intr_res: allocation of interrupt range not "
  166                     "supported (0x%lx - 0x%lx)", start, end);
  167         }
  168         if (start > 7)
  169                 panic("isa_route_intr_res: start out of isa range");
  170         res = isa_ino[start];
  171         if (res == PCI_INVALID_IRQ)
  172                 device_printf(bus, "could not map interrupt %d\n", res);
  173         return (res);
  174 }
  175 
  176 struct resource *
  177 isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
  178                    u_long start, u_long end, u_long count, u_int flags)
  179 {
  180         /*
  181          * Consider adding a resource definition.
  182          */
  183         int passthrough = (device_get_parent(child) != bus);
  184         int isdefault = (start == 0UL && end == ~0UL);
  185         struct isa_device* idev = DEVTOISA(child);
  186         struct resource_list *rl = &idev->id_resources;
  187         struct resource_list_entry *rle;
  188         u_long base, limit;
  189 
  190         if (!passthrough && !isdefault) {
  191                 rle = resource_list_find(rl, type, *rid);
  192                 if (!rle) {
  193                         if (*rid < 0)
  194                                 return 0;
  195                         switch (type) {
  196                         case SYS_RES_IRQ:
  197                                 if (*rid >= ISA_NIRQ)
  198                                         return 0;
  199                                 break;
  200                         case SYS_RES_DRQ:
  201                                 if (*rid >= ISA_NDRQ)
  202                                         return 0;
  203                                 break;
  204                         case SYS_RES_MEMORY:
  205                                 if (*rid >= ISA_NMEM)
  206                                         return 0;
  207                                 break;
  208                         case SYS_RES_IOPORT:
  209                                 if (*rid >= ISA_NPORT)
  210                                         return 0;
  211                                 break;
  212                         default:
  213                                 return 0;
  214                         }
  215                         resource_list_add(rl, type, *rid, start, end, count);
  216                 }
  217         }
  218 
  219         /*
  220          * Add the base, change default allocations to be between base and
  221          * limit, and reject allocations if a resource type is not enabled.
  222          */
  223         base = limit = 0;
  224         switch(type) {
  225         case SYS_RES_MEMORY:
  226                 if (isa_mem_bt == NULL)
  227                         return (NULL);
  228                 base = isa_mem_base;
  229                 limit = base + isa_mem_limit;
  230                 break;
  231         case SYS_RES_IOPORT:
  232                 if (isa_io_bt == NULL)
  233                         return (NULL);
  234                 base = isa_io_base;
  235                 limit = base + isa_io_limit;
  236                 break;
  237         case SYS_RES_IRQ:
  238                 if (isdefault && passthrough)
  239                         panic("isa_alloc_resource: cannot pass through default "
  240                             "irq allocation");
  241                 if (!isdefault) {
  242                         start = end = isa_route_intr_res(bus, start, end);
  243                         if (start == PCI_INVALID_IRQ)
  244                                 return (NULL);
  245                 }
  246                 break;
  247         default:
  248                 panic("isa_alloc_resource: unsupported resource type %d", type);
  249         }
  250         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
  251                 start = ulmin(start + base, limit);
  252                 end = ulmin(end + base, limit);
  253         }
  254 
  255         /*
  256          * This inlines a modified resource_list_alloc(); this is needed
  257          * because the resources need to have offsets added to them, which
  258          * cannot be done beforehand without patching the resource list entries
  259          * (which is ugly).
  260          */
  261         if (passthrough) {
  262                 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
  263                     type, rid, start, end, count, flags));
  264         }
  265 
  266         rle = resource_list_find(rl, type, *rid);
  267         if (rle == NULL)
  268                 return (NULL);          /* no resource of that type/rid */
  269 
  270         if (rle->res != NULL)
  271                 panic("isa_alloc_resource: resource entry is busy");
  272 
  273         if (isdefault) {
  274                 start = rle->start;
  275                 count = ulmax(count, rle->count);
  276                 end = ulmax(rle->end, start + count - 1);
  277                 switch (type) {
  278                 case SYS_RES_MEMORY:
  279                 case SYS_RES_IOPORT:
  280                         start += base;
  281                         end += base;
  282                         if (!INRANGE(start, base, limit) ||
  283                             !INRANGE(end, base, limit))
  284                                 return (NULL);
  285                         break;
  286                 case SYS_RES_IRQ:
  287                         start = end = isa_route_intr_res(bus, start, end);
  288                         if (start == PCI_INVALID_IRQ)
  289                                 return (NULL);
  290                         break;
  291                 }
  292         }
  293 
  294         rle->res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
  295             type, rid, start, end, count, flags);
  296 
  297         /*
  298          * Record the new range.
  299          */
  300         if (rle->res != NULL) {
  301                 rle->start = rman_get_start(rle->res) - base;
  302                 rle->end = rman_get_end(rle->res) - base;
  303                 rle->count = count;
  304         }
  305 
  306         return (rle->res);
  307 }
  308 
  309 int
  310 isa_release_resource(device_t bus, device_t child, int type, int rid,
  311                      struct resource *res)
  312 {
  313         struct isa_device* idev = DEVTOISA(child);
  314         struct resource_list *rl = &idev->id_resources;
  315 
  316         return (resource_list_release(rl, bus, child, type, rid, res));
  317 }
  318 
  319 int
  320 isa_setup_intr(device_t dev, device_t child,
  321                struct resource *irq, int flags,
  322                driver_intr_t *intr, void *arg, void **cookiep)
  323 {
  324 
  325         /*
  326          * Just pass through. This is going to be handled by either one of
  327          * the parent PCI buses or the nexus device.
  328          * The interrupt was routed at allocation time.
  329          */
  330         return (BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, intr,
  331             arg, cookiep));
  332 }
  333 
  334 int
  335 isa_teardown_intr(device_t dev, device_t child,
  336                   struct resource *irq, void *cookie)
  337 {
  338 
  339         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie));
  340 }

Cache object: 9a39cde409d38a9794aad3de47b2e468


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.