root/dev/cardbus/cardbus_map.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cardbus_mapreg_probe
  2. cardbus_io_find
  3. cardbus_mem_find
  4. cardbus_mapreg_map
  5. cardbus_mapreg_unmap
  6. cardbus_save_bar
  7. cardbus_restore_bar

    1 /*      $OpenBSD: cardbus_map.c,v 1.7 2006/07/31 11:06:27 mickey Exp $  */
    2 /*      $NetBSD: cardbus_map.c,v 1.10 2000/03/07 00:31:46 mycroft Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1999 and 2000
    6  *      HAYAKAWA Koichi.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by HAYAKAWA Koichi.
   19  * 4. The name of the author may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   26  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33  * POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/device.h>
   40 
   41 #include <machine/bus.h>
   42 
   43 #include <dev/cardbus/cardbusvar.h>
   44 
   45 #include <dev/pci/pcireg.h>     /* XXX */
   46 
   47 #if defined DEBUG && !defined CARDBUS_MAP_DEBUG
   48 #define CARDBUS_MAP_DEBUG
   49 #endif
   50 
   51 #if defined CARDBUS_MAP_DEBUG
   52 #define STATIC
   53 #define DPRINTF(a) printf a
   54 #else
   55 #define STATIC static
   56 #define DPRINTF(a)
   57 #endif
   58 
   59 
   60 static int cardbus_io_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
   61                cardbustag_t, int, cardbusreg_t, bus_addr_t *, bus_size_t *,
   62                int *);
   63 static int cardbus_mem_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
   64                cardbustag_t, int, cardbusreg_t, bus_addr_t *, bus_size_t *,
   65                int *);
   66 
   67 int
   68 cardbus_mapreg_probe(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf,
   69     cardbustag_t tag, int reg, pcireg_t *typep)
   70 {
   71         pcireg_t address, mask;
   72         int s;
   73 
   74         s = splhigh();
   75         address = cardbus_conf_read(cc, cf, tag, reg);
   76         cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
   77         mask = cardbus_conf_read(cc, cf, tag, reg);
   78         cardbus_conf_write(cc, cf, tag, reg, address);
   79         splx(s);
   80 
   81         if (mask == 0) /* unimplemented mapping register */
   82                 return (0);
   83 
   84         if (typep)
   85                 *typep = _PCI_MAPREG_TYPEBITS(address);
   86         return (1);
   87 }
   88 
   89 /*
   90  * static int cardbus_io_find(cardbus_chipset_tag_t cc,
   91  *                            cardbus_function_tag_t cf, cardbustag_t tag,
   92  *                            int reg, cardbusreg_t type, bus_addr_t *basep,
   93  *                            bus_size_t *sizep, int *flagsp)
   94  * This code is stolen from sys/dev/pci_map.c.
   95  */
   96 static int
   97 cardbus_io_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf,
   98     cardbustag_t tag, int reg, cardbusreg_t type, bus_addr_t *basep,
   99     bus_size_t *sizep, int *flagsp)
  100 {
  101         cardbusreg_t address, mask;
  102         int s;
  103 
  104         /* EXT ROM is able to map on memory space ONLY. */
  105         if (reg == CARDBUS_ROM_REG)
  106                 return (1);
  107 
  108         if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
  109                 panic("cardbus_io_find: bad request");
  110         }
  111 
  112         /*
  113          * Section 6.2.5.1, `Address Maps', tells us that:
  114          *
  115          * 1) The builtin software should have already mapped the device in a
  116          * reasonable way.
  117          *
  118          * 2) A device which wants 2^n bytes of memory will hardwire the bottom
  119          * n bits of the address to 0.  As recommended, we write all 1s and see
  120          * what we get back.
  121          */
  122         s = splhigh();
  123         address = cardbus_conf_read(cc, cf, tag, reg);
  124         cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
  125         mask = cardbus_conf_read(cc, cf, tag, reg);
  126         cardbus_conf_write(cc, cf, tag, reg, address);
  127         splx(s);
  128 
  129         if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
  130                 printf("cardbus_io_find: expected type i/o, found mem\n");
  131                 return (1);
  132         }
  133 
  134         if (PCI_MAPREG_IO_SIZE(mask) == 0) {
  135                 printf("cardbus_io_find: void region\n");
  136                 return (1);
  137         }
  138 
  139         if (basep != 0)
  140                 *basep = PCI_MAPREG_IO_ADDR(address);
  141         if (sizep != 0)
  142                 *sizep = PCI_MAPREG_IO_SIZE(mask);
  143         if (flagsp != 0)
  144                 *flagsp = 0;
  145 
  146         return (0);
  147 }
  148 
  149 /*
  150  * static int cardbus_mem_find(cardbus_chipset_tag_t cc,
  151  *                             cardbus_function_tag_t cf, cardbustag_t tag,
  152  *                             int reg, cardbusreg_t type, bus_addr_t *basep,
  153  *                             bus_size_t *sizep, int *flagsp)
  154  * This code is stolen from sys/dev/pci_map.c.
  155  */
  156 static int
  157 cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf,
  158     cardbustag_t tag, int reg, cardbusreg_t type, bus_addr_t *basep,
  159     bus_size_t *sizep, int *flagsp)
  160 {
  161         cardbusreg_t address, mask;
  162         int s;
  163 
  164         if (reg != CARDBUS_ROM_REG &&
  165             (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
  166                 panic("cardbus_mem_find: bad request");
  167         }
  168 
  169         /*
  170          * Section 6.2.5.1, `Address Maps', tells us that:
  171          *
  172          * 1) The builtin software should have already mapped the device in a
  173          * reasonable way.
  174          *
  175          * 2) A device which wants 2^n bytes of memory will hardwire the bottom
  176          * n bits of the address to 0.  As recommended, we write all 1s and see
  177          * what we get back.
  178          */
  179         s = splhigh();
  180         address = cardbus_conf_read(cc, cf, tag, reg);
  181         cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
  182         mask = cardbus_conf_read(cc, cf, tag, reg);
  183         cardbus_conf_write(cc, cf, tag, reg, address);
  184         splx(s);
  185 
  186         if (reg != CARDBUS_ROM_REG) {
  187                 /* memory space BAR */
  188 
  189                 if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
  190                         printf("cardbus_mem_find: expected type mem, "
  191                             "found i/o\n");
  192                         return (1);
  193                 }
  194                 if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
  195                         printf("cardbus_mem_find: expected mem type %08x, "
  196                             "found %08x\n", PCI_MAPREG_MEM_TYPE(type),
  197                             PCI_MAPREG_MEM_TYPE(address));
  198                         return (1);
  199                 }
  200         }
  201 
  202         if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
  203                 printf("cardbus_mem_find: void region\n");
  204                 return (1);
  205         }
  206 
  207         switch (PCI_MAPREG_MEM_TYPE(address)) {
  208         case PCI_MAPREG_MEM_TYPE_32BIT:
  209         case PCI_MAPREG_MEM_TYPE_32BIT_1M:
  210                 break;
  211         case PCI_MAPREG_MEM_TYPE_64BIT:
  212                 printf("cardbus_mem_find: 64-bit memory mapping register\n");
  213                 return (1);
  214         default:
  215                 printf("cardbus_mem_find: reserved mapping register type\n");
  216                 return (1);
  217         }
  218 
  219         if (basep != 0)
  220                 *basep = PCI_MAPREG_MEM_ADDR(address);
  221         if (sizep != 0)
  222                 *sizep = PCI_MAPREG_MEM_SIZE(mask);
  223         if (flagsp != 0) {
  224                 *flagsp =
  225 #ifdef BUS_SPACE_MAP_PREFETCHABLE
  226                     PCI_MAPREG_MEM_PREFETCHABLE(address) ?
  227                       BUS_SPACE_MAP_PREFETCHABLE :
  228 #endif
  229                 0;
  230         }
  231 
  232         return (0);
  233 }
  234 
  235 /*
  236  * int cardbus_mapreg_map(struct cardbus_softc *, int, int, cardbusreg_t,
  237  *                        int bus_space_tag_t *, bus_space_handle_t *,
  238  *                        bus_addr_t *, bus_size_t *)
  239  *    This function maps bus-space on the value of Base Address
  240  *   Register (BAR) indexed by the argument `reg' (the second argument).
  241  *   When the value of the BAR is not valid, such as 0x00000000, a new
  242  *   address should be allocated for the BAR and new address values is
  243  *   written on the BAR.
  244  */
  245 int
  246 cardbus_mapreg_map(struct cardbus_softc *sc, int func, int reg,
  247     cardbusreg_t type, int busflags, bus_space_tag_t *tagp,
  248     bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep)
  249 {
  250         cardbus_chipset_tag_t cc = sc->sc_cc;
  251         cardbus_function_tag_t cf = sc->sc_cf;
  252         bus_space_tag_t bustag;
  253         rbus_tag_t rbustag;
  254         bus_space_handle_t handle;
  255         bus_addr_t base;
  256         bus_size_t size;
  257         int flags;
  258         int status = 0;
  259 
  260         cardbustag_t tag = cardbus_make_tag(cc, cf, sc->sc_bus,
  261             sc->sc_device, func);
  262 
  263         DPRINTF(("cardbus_mapreg_map called: %s %x\n", sc->sc_dev.dv_xname,
  264            type));
  265 
  266         if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
  267                 if (cardbus_io_find(cc, cf, tag, reg, type, &base, &size,
  268                     &flags))
  269                         status = 1;
  270                 bustag = sc->sc_iot;
  271                 rbustag = sc->sc_rbus_iot;
  272         } else {
  273                 if (cardbus_mem_find(cc, cf, tag, reg, type, &base, &size,
  274                     &flags))
  275                         status = 1;
  276                 bustag = sc->sc_memt;
  277                 rbustag = sc->sc_rbus_memt;
  278         }
  279         if (status == 0) {
  280                 bus_addr_t mask = size - 1;
  281                 if (base != 0)
  282                         mask = 0xffffffff;
  283                 if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
  284                     size, busflags | flags, &base, &handle)) {
  285                         panic("io alloc");
  286                 }
  287         }
  288         cardbus_conf_write(cc, cf, tag, reg, base);
  289 
  290         DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", (unsigned long)base));
  291 
  292         if (tagp != 0)
  293                 *tagp = bustag;
  294         if (handlep != 0)
  295                 *handlep = handle;
  296         if (basep != 0)
  297                 *basep = base;
  298         if (sizep != 0)
  299                 *sizep = size;
  300         cardbus_free_tag(cc, cf, tag);
  301 
  302         return (0);
  303 }
  304 
  305 /*
  306  * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
  307  *                          bus_space_tag_t tag, bus_space_handle_t handle,
  308  *                          bus_size_t size)
  309  *
  310  *   This function releases bus-space region and close memory or io
  311  *   window on the bridge.
  312  *
  313  *  Arguments:
  314  *   struct cardbus_softc *sc; the pointer to the device structure of cardbus.
  315  *   int func; the number of function on the device.
  316  *   int reg; the offset of BAR register.
  317  */
  318 int
  319 cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
  320     bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
  321 {
  322         cardbus_chipset_tag_t cc = sc->sc_cc;
  323         cardbus_function_tag_t cf = sc->sc_cf;
  324         int st = 1;
  325         cardbustag_t cardbustag;
  326         rbus_tag_t rbustag;
  327 
  328         if (sc->sc_iot == tag) {
  329                 /* bus space is io space */
  330                 DPRINTF(("%s: unmap i/o space\n", sc->sc_dev.dv_xname));
  331                 rbustag = sc->sc_rbus_iot;
  332         } else if (sc->sc_memt == tag) {
  333                 /* bus space is memory space */
  334                 DPRINTF(("%s: unmap mem space\n", sc->sc_dev.dv_xname));
  335                 rbustag = sc->sc_rbus_memt;
  336         } else
  337                 return (1);
  338 
  339         cardbustag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, func);
  340 
  341         cardbus_conf_write(cc, cf, cardbustag, reg, 0);
  342 
  343         (*cf->cardbus_space_free)(cc, rbustag, handle, size);
  344 
  345         cardbus_free_tag(cc, cf, cardbustag);
  346 
  347         return (st);
  348 }
  349 
  350 /*
  351  * int cardbus_save_bar(cardbus_devfunc_t);
  352  *
  353  *   This function saves the Base Address Registers at the CardBus
  354  *   function denoted by the argument.
  355  */
  356 int
  357 cardbus_save_bar(cardbus_devfunc_t ct)
  358 {
  359         cardbustag_t tag = Cardbus_make_tag(ct);
  360         cardbus_chipset_tag_t cc = ct->ct_cc;
  361         cardbus_function_tag_t cf = ct->ct_cf;
  362 
  363         ct->ct_bar[0] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE0_REG);
  364         ct->ct_bar[1] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE1_REG);
  365         ct->ct_bar[2] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE2_REG);
  366         ct->ct_bar[3] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE3_REG);
  367         ct->ct_bar[4] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE4_REG);
  368         ct->ct_bar[5] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE5_REG);
  369 
  370         DPRINTF(("cardbus_save_bar: %x %x\n", ct->ct_bar[0], ct->ct_bar[1]));
  371 
  372         Cardbus_free_tag(ct, tag);
  373 
  374         return (0);
  375 }
  376 
  377 /*
  378  * int cardbus_restore_bar(cardbus_devfunc_t);
  379  *
  380  *   This function saves the Base Address Registers at the CardBus
  381  *   function denoted by the argument.
  382  */
  383 int
  384 cardbus_restore_bar(cardbus_devfunc_t ct)
  385 {
  386         cardbustag_t tag = Cardbus_make_tag(ct);
  387         cardbus_chipset_tag_t cc = ct->ct_cc;
  388         cardbus_function_tag_t cf = ct->ct_cf;
  389 
  390         cardbus_conf_write(cc, cf, tag, CARDBUS_BASE0_REG, ct->ct_bar[0]);
  391         cardbus_conf_write(cc, cf, tag, CARDBUS_BASE1_REG, ct->ct_bar[1]);
  392         cardbus_conf_write(cc, cf, tag, CARDBUS_BASE2_REG, ct->ct_bar[2]);
  393         cardbus_conf_write(cc, cf, tag, CARDBUS_BASE3_REG, ct->ct_bar[3]);
  394         cardbus_conf_write(cc, cf, tag, CARDBUS_BASE4_REG, ct->ct_bar[4]);
  395         cardbus_conf_write(cc, cf, tag, CARDBUS_BASE5_REG, ct->ct_bar[5]);
  396 
  397         Cardbus_free_tag(ct, tag);
  398 
  399         return (0);
  400 }

/* [<][>][^][v][top][bottom][index][help] */