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/mips/adm5120/admpci.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 /* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2007 David Young.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or
    7  * without modification, are permitted provided that the following
    8  * conditions 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
   12  *    copyright notice, this list of conditions and the following
   13  *    disclaimer in the documentation and/or other materials provided
   14  *    with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote
   16  *    products derived from this software without specific prior
   17  *    written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
   20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   22  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   24  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
   26  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
   28  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
   30  * OF SUCH DAMAGE.
   31  */
   32 /*-
   33  * Copyright (c) 2006 Itronix Inc.
   34  * All rights reserved.
   35  *
   36  * Written by Garrett D'Amore for Itronix Inc.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 3. The name of Itronix Inc. may not be used to endorse
   47  *    or promote products derived from this software without specific
   48  *    prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   54  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   55  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   56  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   57  * ON ANY THEORY OF LIABILITY, WHETHER IN
   58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   60  * POSSIBILITY OF SUCH DAMAGE.
   61  */ 
   62 
   63 #include <sys/cdefs.h>
   64 __FBSDID("$FreeBSD: releng/11.0/sys/mips/adm5120/admpci.c 295880 2016-02-22 09:02:20Z skra $");
   65 
   66 #include <sys/param.h>
   67 #include <sys/systm.h>
   68 
   69 #include <sys/bus.h>
   70 #include <sys/interrupt.h>
   71 #include <sys/malloc.h>
   72 #include <sys/kernel.h>
   73 #include <sys/module.h>
   74 #include <sys/rman.h>
   75 
   76 #include <vm/vm.h>
   77 #include <vm/pmap.h>
   78 #include <vm/vm_extern.h>
   79 
   80 #include <machine/bus.h>
   81 #include <machine/cpu.h>
   82 
   83 #include <dev/pci/pcivar.h>
   84 #include <dev/pci/pcireg.h>
   85 
   86 #include <dev/pci/pcib_private.h>
   87 #include "pcib_if.h"
   88 
   89 #include <mips/adm5120/adm5120reg.h>
   90 
   91 #ifdef ADMPCI_DEBUG
   92 int admpci_debug = 1;
   93 #define ADMPCI_DPRINTF(__fmt, ...)              \
   94 do {                                            \
   95         if (admpci_debug)                       \
   96                 printf((__fmt), __VA_ARGS__);   \
   97 } while (/*CONSTCOND*/0)
   98 #else /* !ADMPCI_DEBUG */
   99 #define ADMPCI_DPRINTF(__fmt, ...)      do { } while (/*CONSTCOND*/0)
  100 #endif /* ADMPCI_DEBUG */
  101 
  102 #define ADMPCI_TAG_BUS_MASK             __BITS(23, 16)
  103 /* Bit 11 is reserved.  It selects the AHB-PCI bridge.  Let device 0
  104  * be the bridge.  For all other device numbers, let bit[11] == 0.
  105  */
  106 #define ADMPCI_TAG_DEVICE_MASK          __BITS(15, 11)
  107 #define ADMPCI_TAG_DEVICE_SUBMASK       __BITS(15, 12)
  108 #define ADMPCI_TAG_DEVICE_BRIDGE        __BIT(11)
  109 #define ADMPCI_TAG_FUNCTION_MASK        __BITS(10, 8)
  110 #define ADMPCI_TAG_REGISTER_MASK        __BITS(7, 0)
  111 
  112 #define ADMPCI_MAX_DEVICE
  113 
  114 struct admpci_softc {
  115         device_t                sc_dev;
  116         bus_space_tag_t         sc_st;
  117 
  118         /* Access to PCI config registers */
  119         bus_space_handle_t      sc_addrh;
  120         bus_space_handle_t      sc_datah;
  121 
  122         int                     sc_busno;
  123         struct rman             sc_mem_rman;
  124         struct rman             sc_io_rman;
  125         struct rman             sc_irq_rman;
  126         uint32_t                sc_mem;
  127         uint32_t                sc_io;
  128 };
  129 
  130 static int
  131 admpci_probe(device_t dev)
  132 {
  133 
  134         return (0);
  135 }
  136 
  137 static int
  138 admpci_attach(device_t dev)
  139 {
  140         int busno = 0;
  141         struct admpci_softc *sc = device_get_softc(dev);
  142 
  143         sc->sc_dev = dev;
  144         sc->sc_busno = busno;
  145 
  146         /* Use KSEG1 to access IO ports for it is uncached */
  147         sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO);
  148         sc->sc_io_rman.rm_type = RMAN_ARRAY;
  149         sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports";
  150         if (rman_init(&sc->sc_io_rman) != 0 ||
  151                 rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
  152                 panic("admpci_attach: failed to set up I/O rman");
  153         }
  154 
  155         /* Use KSEG1 to access PCI memory for it is uncached */
  156         sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM);
  157         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
  158         sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory";
  159         if (rman_init(&sc->sc_mem_rman) != 0 ||
  160             rman_manage_region(&sc->sc_mem_rman, 
  161             sc->sc_mem, sc->sc_mem + 0x100000) != 0) {
  162                 panic("admpci_attach: failed to set up memory rman");
  163         }
  164 
  165         sc->sc_irq_rman.rm_type = RMAN_ARRAY;
  166         sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs";
  167         if (rman_init(&sc->sc_irq_rman) != 0 ||
  168             rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
  169                 panic("admpci_attach: failed to set up IRQ rman");
  170 
  171         if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0, 
  172             &sc->sc_addrh) != 0) {
  173                 device_printf(sc->sc_dev, "unable to address space\n");
  174                 panic("bus_space_map failed");
  175         }
  176 
  177         if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0, 
  178             &sc->sc_datah) != 0) {
  179                 device_printf(sc->sc_dev, "unable to address space\n");
  180                 panic("bus_space_map failed");
  181         }
  182 
  183         device_add_child(dev, "pci", -1);
  184         return (bus_generic_attach(dev));
  185 }
  186 
  187 static int
  188 admpci_maxslots(device_t dev)
  189 {
  190 
  191         return (PCI_SLOTMAX);
  192 }
  193 
  194 static uint32_t
  195 admpci_make_addr(int bus, int slot, int func, int reg)
  196 {
  197 
  198         return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg);
  199 }
  200 
  201 static uint32_t
  202 admpci_read_config(device_t dev, int bus, int slot, int func, int reg,
  203     int bytes)
  204 {
  205         struct admpci_softc *sc = device_get_softc(dev);
  206         uint32_t data;
  207         uint32_t shift, mask;
  208         bus_addr_t addr;
  209 
  210         ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 
  211                         (void *)sc, bus, slot, func, reg);
  212 
  213         addr = admpci_make_addr(bus, slot, func, reg);
  214 
  215         ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
  216             (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
  217 
  218         bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
  219         data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0);
  220 
  221         switch (reg % 4) {
  222         case 3:
  223                 shift = 24;
  224                 break;
  225         case 2:
  226                 shift = 16;
  227                 break;
  228         case 1:
  229                 shift = 8;
  230                 break;
  231         default:
  232                 shift = 0;
  233                 break;
  234         }       
  235 
  236         switch (bytes) {
  237         case 1:
  238                 mask = 0xff;
  239                 data = (data >> shift) & mask;
  240                 break;
  241         case 2:
  242                 mask = 0xffff;
  243                 if (reg % 4 == 0)
  244                         data = data & mask;
  245                 else
  246                         data = (data >> 16) & mask;
  247                 break;
  248         case 4:
  249                 break;
  250         default:
  251                 panic("%s: wrong bytes count", __func__);
  252                 break;
  253         }
  254 
  255         ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
  256         return (data);
  257 }
  258 
  259 static void
  260 admpci_write_config(device_t dev, int bus, int slot, int func, int reg,
  261     uint32_t data, int bytes)
  262 {
  263         struct admpci_softc *sc = device_get_softc(dev);
  264         bus_addr_t addr;
  265         uint32_t reg_data;
  266         uint32_t shift, mask;
  267 
  268         ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 
  269                         (void *)sc, bus, slot, func, reg);
  270 
  271         if (bytes != 4) {
  272                 reg_data = admpci_read_config(dev, bus, slot, func, reg, 4);
  273 
  274                 switch (reg % 4) {
  275                 case 3:
  276                         shift = 24;
  277                         break;
  278                 case 2:
  279                         shift = 16;
  280                         break;
  281                 case 1:
  282                         shift = 8;
  283                         break;
  284                 default:
  285                         shift = 0;
  286                         break;
  287                 }       
  288 
  289                 switch (bytes) {
  290                 case 1:
  291                         mask = 0xff;
  292                         data = (reg_data & ~ (mask << shift)) | (data << shift);
  293                         break;
  294                 case 2:
  295                         mask = 0xffff;
  296                         if (reg % 4 == 0)
  297                                 data = (reg_data & ~mask) | data;
  298                         else
  299                                 data = (reg_data & ~ (mask << shift)) | 
  300                                     (data << shift);
  301                         break;
  302                 case 4:
  303                         break;
  304                 default:
  305                         panic("%s: wrong bytes count", __func__);
  306                         break;
  307                 }
  308         }
  309 
  310         addr = admpci_make_addr(bus, slot, func, reg);
  311 
  312         ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
  313             (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
  314 
  315         bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
  316         bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data);
  317 }
  318 
  319 static int
  320 admpci_route_interrupt(device_t pcib, device_t dev, int pin)
  321 {
  322         /* TODO: implement */
  323         return (0);
  324 }
  325 
  326 static int
  327 admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
  328 {
  329         struct admpci_softc *sc = device_get_softc(dev);
  330 
  331         switch (which) {
  332         case PCIB_IVAR_DOMAIN:
  333                 *result = 0;
  334                 return (0);
  335         case PCIB_IVAR_BUS:
  336                 *result = sc->sc_busno;
  337                 return (0);
  338         }
  339 
  340         return (ENOENT);
  341 }
  342 
  343 static int
  344 admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
  345 {
  346         struct admpci_softc * sc = device_get_softc(dev);
  347 
  348         switch (which) {
  349         case PCIB_IVAR_BUS:
  350                 sc->sc_busno = result;
  351                 return (0);
  352         }
  353         return (ENOENT);
  354 }
  355 
  356 static struct resource *
  357 admpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
  358     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  359 {
  360 
  361         return (NULL);
  362 #if 0
  363         struct admpci_softc *sc = device_get_softc(bus);        
  364         struct resource *rv = NULL;
  365         struct rman *rm;
  366         bus_space_handle_t bh = 0;
  367 
  368         switch (type) {
  369         case SYS_RES_IRQ:
  370                 rm = &sc->sc_irq_rman;
  371                 break;
  372         case SYS_RES_MEMORY:
  373                 rm = &sc->sc_mem_rman;
  374                 bh = sc->sc_mem;
  375                 break;
  376         case SYS_RES_IOPORT:
  377                 rm = &sc->sc_io_rman;
  378                 bh = sc->sc_io;
  379                 break;
  380         default:
  381                 return (NULL);
  382         }
  383 
  384         rv = rman_reserve_resource(rm, start, end, count, flags, child);
  385         if (rv == NULL)
  386                 return (NULL);
  387         rman_set_rid(rv, *rid);
  388         if (type != SYS_RES_IRQ) {
  389                 bh += (rman_get_start(rv));
  390 
  391                 rman_set_bustag(rv, sc->sc_st);
  392                 rman_set_bushandle(rv, bh);
  393                 if (flags & RF_ACTIVE) {
  394                         if (bus_activate_resource(child, type, *rid, rv)) {
  395                                 rman_release_resource(rv);
  396                                 return (NULL);
  397                         }
  398                 } 
  399         }
  400         return (rv);
  401 #endif
  402 }
  403 
  404 static int
  405 admpci_activate_resource(device_t bus, device_t child, int type, int rid,
  406     struct resource *r)
  407 {
  408         bus_space_handle_t p;
  409         int error;
  410         
  411         if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
  412                 error = bus_space_map(rman_get_bustag(r),
  413                     rman_get_bushandle(r), rman_get_size(r), 0, &p);
  414                 if (error) 
  415                         return (error);
  416                 rman_set_bushandle(r, p);
  417         }
  418         return (rman_activate_resource(r));
  419 }
  420 
  421 static int
  422 admpci_setup_intr(device_t dev, device_t child, struct resource *ires, 
  423                 int flags, driver_filter_t *filt, driver_intr_t *handler, 
  424                 void *arg, void **cookiep)
  425 {
  426 
  427 #if 0
  428         struct admpci_softc *sc = device_get_softc(dev);
  429         struct intr_event *event;
  430         int irq, error;
  431 
  432         irq = rman_get_start(ires);
  433         if (irq >= ICU_LEN || irq == 2)
  434                 panic("%s: bad irq or type", __func__);
  435 
  436         event = sc->sc_eventstab[irq];
  437         if (event == NULL) {
  438                 error = intr_event_create(&event, (void *)irq, 0,
  439                     (void (*)(void *))NULL, "admpci intr%d:", irq);
  440                 if (error)
  441                         return 0;
  442                 sc->sc_eventstab[irq] = event;
  443         }
  444 
  445         intr_event_add_handler(event, device_get_nameunit(child), filt, 
  446             handler, arg, intr_priority(flags), flags, cookiep);
  447 
  448         /* Enable it, set trigger mode. */
  449         sc->sc_imask &= ~(1 << irq);
  450         sc->sc_elcr &= ~(1 << irq);
  451 
  452         admpci_set_icus(sc);
  453 #endif
  454 
  455         return (0);
  456 }
  457 
  458 static int
  459 admpci_teardown_intr(device_t dev, device_t child, struct resource *res,
  460     void *cookie)
  461 {
  462 
  463         return (intr_event_remove_handler(cookie));
  464 }
  465 
  466 static device_method_t admpci_methods[] = {
  467         /* Device interface */
  468         DEVMETHOD(device_probe,         admpci_probe),
  469         DEVMETHOD(device_attach,        admpci_attach),
  470         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  471         DEVMETHOD(device_suspend,       bus_generic_suspend),
  472         DEVMETHOD(device_resume,        bus_generic_resume),
  473 
  474         /* Bus interface */
  475         DEVMETHOD(bus_read_ivar,        admpci_read_ivar),
  476         DEVMETHOD(bus_write_ivar,       admpci_write_ivar),
  477         DEVMETHOD(bus_alloc_resource,   admpci_alloc_resource),
  478         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
  479         DEVMETHOD(bus_activate_resource, admpci_activate_resource),
  480         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  481         DEVMETHOD(bus_setup_intr,       admpci_setup_intr),
  482         DEVMETHOD(bus_teardown_intr,    admpci_teardown_intr),
  483 
  484         /* pcib interface */
  485         DEVMETHOD(pcib_maxslots,        admpci_maxslots),
  486         DEVMETHOD(pcib_read_config,     admpci_read_config),
  487         DEVMETHOD(pcib_write_config,    admpci_write_config),
  488         DEVMETHOD(pcib_route_interrupt, admpci_route_interrupt),
  489 
  490         DEVMETHOD_END
  491 };
  492 
  493 static driver_t admpci_driver = {
  494         "pcib",
  495         admpci_methods,
  496         sizeof(struct admpci_softc),
  497 };
  498 
  499 static devclass_t admpci_devclass;
  500 
  501 DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0);

Cache object: e9c703d5df916c80d1bf10055680d457


[ 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.