LCOV - code coverage report
Current view: top level - dev/pci - pci_map.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 159 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: pci_map.c,v 1.31 2015/03/14 03:38:48 jsg Exp $     */
       2             : /*      $NetBSD: pci_map.c,v 1.7 2000/05/10 16:58:42 thorpej Exp $      */
       3             : 
       4             : /*-
       5             :  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
       6             :  * All rights reserved.
       7             :  *
       8             :  * This code is derived from software contributed to The NetBSD Foundation
       9             :  * by Charles M. Hannum; by William R. Studenmund; by Jason R. Thorpe.
      10             :  *
      11             :  * Redistribution and use in source and binary forms, with or without
      12             :  * modification, are permitted provided that the following conditions
      13             :  * are met:
      14             :  * 1. Redistributions of source code must retain the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      21             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      22             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      23             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      24             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      25             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      26             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      27             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      28             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      29             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      30             :  * POSSIBILITY OF SUCH DAMAGE.
      31             :  */
      32             : 
      33             : /*
      34             :  * PCI device mapping.
      35             :  */
      36             : 
      37             : #include <sys/param.h>
      38             : #include <sys/systm.h>
      39             : 
      40             : #include <dev/pci/pcireg.h>
      41             : #include <dev/pci/pcivar.h>
      42             : 
      43             : #ifndef PCI_IO_START
      44             : #define PCI_IO_START    0
      45             : #endif
      46             : 
      47             : #ifndef PCI_IO_END
      48             : #define PCI_IO_END      0xffffffff
      49             : #endif
      50             : 
      51             : #ifndef PCI_MEM_START
      52             : #define PCI_MEM_START   0
      53             : #endif
      54             : 
      55             : #ifndef PCI_MEM_END
      56             : #define PCI_MEM_END     0xffffffff
      57             : #endif
      58             : 
      59             : 
      60             : int obsd_pci_io_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
      61             :     bus_addr_t *, bus_size_t *, int *);
      62             : int obsd_pci_mem_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
      63             :     bus_addr_t *, bus_size_t *, int *);
      64             : 
      65             : int
      66           0 : obsd_pci_io_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
      67             :     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
      68             : {
      69             :         pcireg_t address, mask, csr;
      70             :         int s;
      71             : 
      72           0 :         if (reg < PCI_MAPREG_START ||
      73             : #if 0
      74             :             /*
      75             :              * Can't do this check; some devices have mapping registers
      76             :              * way out in left field.
      77             :              */
      78             :             reg >= PCI_MAPREG_END ||
      79             : #endif
      80           0 :             (reg & 3))
      81           0 :                 panic("pci_io_find: bad request");
      82             : 
      83             :         /*
      84             :          * Section 6.2.5.1, `Address Maps', tells us that:
      85             :          *
      86             :          * 1) The builtin software should have already mapped the device in a
      87             :          * reasonable way.
      88             :          *
      89             :          * 2) A device which wants 2^n bytes of memory will hardwire the bottom
      90             :          * n bits of the address to 0.  As recommended, we write all 1s while
      91             :          * the device is disabled and see what we get back.
      92             :          */
      93           0 :         s = splhigh();
      94           0 :         csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
      95           0 :         if (csr & PCI_COMMAND_IO_ENABLE)
      96           0 :                 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
      97           0 :                     csr & ~PCI_COMMAND_IO_ENABLE);
      98           0 :         address = pci_conf_read(pc, tag, reg);
      99           0 :         pci_conf_write(pc, tag, reg, 0xffffffff);
     100           0 :         mask = pci_conf_read(pc, tag, reg);
     101           0 :         pci_conf_write(pc, tag, reg, address);
     102           0 :         if (csr & PCI_COMMAND_IO_ENABLE)
     103           0 :                 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
     104           0 :         splx(s);
     105             : 
     106           0 :         if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
     107             : #ifdef DEBUG
     108             :                 printf("pci_io_find: expected type i/o, found mem\n");
     109             : #endif
     110           0 :                 return (EINVAL);
     111             :         }
     112             : 
     113           0 :         if (PCI_MAPREG_IO_SIZE(mask) == 0) {
     114             : #ifdef DEBUG
     115             :                 printf("pci_io_find: void region\n");
     116             : #endif
     117           0 :                 return (ENOENT);
     118             :         }
     119             : 
     120           0 :         if (basep != 0)
     121           0 :                 *basep = PCI_MAPREG_IO_ADDR(address);
     122           0 :         if (sizep != 0)
     123           0 :                 *sizep = PCI_MAPREG_IO_SIZE(mask);
     124           0 :         if (flagsp != 0)
     125           0 :                 *flagsp = 0;
     126             : 
     127           0 :         return (0);
     128           0 : }
     129             : 
     130             : int
     131           0 : obsd_pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
     132             :     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
     133             : {
     134             :         pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff, csr;
     135             :         u_int64_t waddress, wmask;
     136             :         int s, is64bit;
     137             : 
     138           0 :         is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
     139             : 
     140           0 :         if (reg < PCI_MAPREG_START ||
     141             : #if 0
     142             :             /*
     143             :              * Can't do this check; some devices have mapping registers
     144             :              * way out in left field.
     145             :              */
     146             :             reg >= PCI_MAPREG_END ||
     147             : #endif
     148           0 :             (reg & 3))
     149           0 :                 panic("pci_mem_find: bad request");
     150             : 
     151           0 :         if (is64bit && (reg + 4) >= PCI_MAPREG_END)
     152           0 :                 panic("pci_mem_find: bad 64-bit request");
     153             : 
     154             :         /*
     155             :          * Section 6.2.5.1, `Address Maps', tells us that:
     156             :          *
     157             :          * 1) The builtin software should have already mapped the device in a
     158             :          * reasonable way.
     159             :          *
     160             :          * 2) A device which wants 2^n bytes of memory will hardwire the bottom
     161             :          * n bits of the address to 0.  As recommended, we write all 1s while
     162             :          * the device is disabled and see what we get back.
     163             :          */
     164           0 :         s = splhigh();
     165           0 :         csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
     166           0 :         if (csr & PCI_COMMAND_MEM_ENABLE)
     167           0 :                 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
     168           0 :                     csr & ~PCI_COMMAND_MEM_ENABLE);
     169           0 :         address = pci_conf_read(pc, tag, reg);
     170           0 :         pci_conf_write(pc, tag, reg, PCI_MAPREG_MEM_ADDR_MASK);
     171           0 :         mask = pci_conf_read(pc, tag, reg);
     172           0 :         pci_conf_write(pc, tag, reg, address);
     173           0 :         if (is64bit) {
     174           0 :                 address1 = pci_conf_read(pc, tag, reg + 4);
     175           0 :                 pci_conf_write(pc, tag, reg + 4, 0xffffffff);
     176           0 :                 mask1 = pci_conf_read(pc, tag, reg + 4);
     177           0 :                 pci_conf_write(pc, tag, reg + 4, address1);
     178           0 :         }
     179           0 :         if (csr & PCI_COMMAND_MEM_ENABLE)
     180           0 :                 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
     181           0 :         splx(s);
     182             : 
     183           0 :         if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
     184             : #ifdef DEBUG
     185             :                 printf("pci_mem_find: expected type mem, found i/o\n");
     186             : #endif
     187           0 :                 return (EINVAL);
     188             :         }
     189           0 :         if (type != -1 && 
     190           0 :             PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
     191             : #ifdef DEBUG
     192             :                 printf("pci_mem_find: expected mem type %08x, found %08x\n",
     193             :                     PCI_MAPREG_MEM_TYPE(type),
     194             :                     PCI_MAPREG_MEM_TYPE(address));
     195             : #endif
     196           0 :                 return (EINVAL);
     197             :         }
     198             : 
     199           0 :         waddress = (u_int64_t)address1 << 32UL | address;
     200           0 :         wmask = (u_int64_t)mask1 << 32UL | mask;
     201             : 
     202           0 :         if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) ||
     203           0 :             (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) {
     204             : #ifdef DEBUG
     205             :                 printf("pci_mem_find: void region\n");
     206             : #endif
     207           0 :                 return (ENOENT);
     208             :         }
     209             : 
     210           0 :         switch (PCI_MAPREG_MEM_TYPE(address)) {
     211             :         case PCI_MAPREG_MEM_TYPE_32BIT:
     212             :         case PCI_MAPREG_MEM_TYPE_32BIT_1M:
     213             :                 break;
     214             :         case PCI_MAPREG_MEM_TYPE_64BIT:
     215             :                 /*
     216             :                  * Handle the case of a 64-bit memory register on a
     217             :                  * platform with 32-bit addressing.  Make sure that
     218             :                  * the address assigned and the device's memory size
     219             :                  * fit in 32 bits.  We implicitly assume that if
     220             :                  * bus_addr_t is 64-bit, then so is bus_size_t.
     221             :                  */
     222             :                 if (sizeof(u_int64_t) > sizeof(bus_addr_t) &&
     223             :                     (address1 != 0 || mask1 != 0xffffffff)) {
     224             : #ifdef DEBUG
     225             :                         printf("pci_mem_find: 64-bit memory map which is "
     226             :                             "inaccessible on a 32-bit platform\n");
     227             : #endif
     228             :                         return (EINVAL);
     229             :                 }
     230             :                 break;
     231             :         default:
     232             : #ifdef DEBUG
     233             :                 printf("pci_mem_find: reserved mapping register type\n");
     234             : #endif
     235           0 :                 return (EINVAL);
     236             :         }
     237             : 
     238             :         if (sizeof(u_int64_t) > sizeof(bus_addr_t)) {
     239             :                 if (basep != 0)
     240             :                         *basep = PCI_MAPREG_MEM_ADDR(address);
     241             :                 if (sizep != 0)
     242             :                         *sizep = PCI_MAPREG_MEM_SIZE(mask);
     243             :         } else {
     244           0 :                 if (basep != 0)
     245           0 :                         *basep = PCI_MAPREG_MEM64_ADDR(waddress);
     246           0 :                 if (sizep != 0)
     247           0 :                         *sizep = PCI_MAPREG_MEM64_SIZE(wmask);
     248             :         }
     249           0 :         if (flagsp != 0)
     250           0 :                 *flagsp =
     251           0 :                     PCI_MAPREG_MEM_PREFETCHABLE(address) ?
     252             :                       BUS_SPACE_MAP_PREFETCHABLE : 0;
     253             : 
     254           0 :         return (0);
     255           0 : }
     256             : 
     257             : int
     258           0 : pci_io_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
     259             :     bus_addr_t *iobasep, bus_size_t *iosizep)
     260             : {
     261           0 :         return (obsd_pci_io_find(pc, pcitag, reg, 0, iobasep, iosizep, 0));
     262             : }
     263             : 
     264             : int
     265           0 : pci_mem_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
     266             :     bus_addr_t *membasep, bus_size_t *memsizep, int *cacheablep)
     267             : {
     268           0 :         return (obsd_pci_mem_find(pc, pcitag, reg, -1, membasep, memsizep,
     269             :                                   cacheablep));
     270             : }
     271             : 
     272             : pcireg_t
     273           0 : pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg)
     274             : {
     275           0 :         return (_PCI_MAPREG_TYPEBITS(pci_conf_read(pc, tag, reg)));
     276             : }
     277             : 
     278             : int
     279           0 : pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
     280             : {
     281             :         pcireg_t address, mask, csr;
     282             :         int s;
     283             :         
     284           0 :         s = splhigh();
     285           0 :         csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
     286           0 :         if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
     287           0 :                 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
     288             :                     ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));
     289           0 :         address = pci_conf_read(pc, tag, reg);
     290           0 :         pci_conf_write(pc, tag, reg, 0xffffffff);
     291           0 :         mask = pci_conf_read(pc, tag, reg);
     292           0 :         pci_conf_write(pc, tag, reg, address);
     293           0 :         if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
     294           0 :                 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
     295           0 :         splx(s);
     296             : 
     297           0 :         if (mask == 0) /* unimplemented mapping register */
     298           0 :                 return (0);
     299             : 
     300           0 :         if (typep)
     301           0 :                 *typep = _PCI_MAPREG_TYPEBITS(address);
     302           0 :         return (1);
     303           0 : }
     304             : 
     305             : int
     306           0 : pci_mapreg_info(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
     307             :     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
     308             : {
     309             : 
     310           0 :         if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
     311           0 :                 return (obsd_pci_io_find(pc, tag, reg, type, basep, sizep,
     312             :                     flagsp));
     313             :         else
     314           0 :                 return (obsd_pci_mem_find(pc, tag, reg, type, basep, sizep,
     315             :                     flagsp));
     316           0 : }
     317             : 
     318             : int
     319           0 : pci_mapreg_map(struct pci_attach_args *pa, int reg, pcireg_t type, int flags,
     320             :     bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep,
     321             :     bus_size_t *sizep, bus_size_t maxsize)
     322             : {
     323             :         bus_space_tag_t tag;
     324           0 :         bus_space_handle_t handle;
     325           0 :         bus_addr_t base;
     326           0 :         bus_size_t size;
     327             :         pcireg_t csr;
     328             :         int rv;
     329             : 
     330           0 :         if ((rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type,
     331           0 :             &base, &size, NULL)) != 0)
     332           0 :                 return (rv);
     333             : #if !defined(__sparc64__)
     334           0 :         if (base == 0) {
     335             :                 struct extent *ex;
     336             :                 bus_addr_t start, end;
     337             : 
     338           0 :                 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
     339           0 :                         ex = pa->pa_ioex;
     340           0 :                         if (ex != NULL) {
     341           0 :                                 start = max(PCI_IO_START, ex->ex_start);
     342           0 :                                 end = min(PCI_IO_END, ex->ex_end);
     343           0 :                         }
     344             :                 } else {
     345           0 :                         ex = pa->pa_memex;
     346           0 :                         if (ex != NULL) {
     347           0 :                                 start = max(PCI_MEM_START, ex->ex_start);
     348           0 :                                 end = min(PCI_MEM_END, ex->ex_end);
     349           0 :                         }
     350             :                 }
     351             : 
     352           0 :                 if (ex == NULL || extent_alloc_subregion(ex, start, end,
     353           0 :                     size, size, 0, 0, 0, &base))
     354           0 :                         return (EINVAL); /* disabled because of invalid BAR */
     355             : 
     356           0 :                 pci_conf_write(pa->pa_pc, pa->pa_tag, reg, base);
     357           0 :                 if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT)
     358           0 :                         pci_conf_write(pa->pa_pc, pa->pa_tag, reg + 4,
     359           0 :                             (u_int64_t)base >> 32);
     360           0 :         }
     361             : #endif
     362             : 
     363           0 :         csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
     364           0 :         if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
     365           0 :                 csr |= PCI_COMMAND_IO_ENABLE;
     366             :         else
     367           0 :                 csr |= PCI_COMMAND_MEM_ENABLE;
     368             :         /* XXX Should this only be done for devices that do DMA?  */
     369           0 :         csr |= PCI_COMMAND_MASTER_ENABLE;
     370           0 :         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
     371             : 
     372           0 :         if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
     373           0 :                 if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0)
     374           0 :                         return (EINVAL);
     375           0 :                 tag = pa->pa_iot;
     376           0 :         } else {
     377           0 :                 if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) == 0)
     378           0 :                         return (EINVAL);
     379           0 :                 tag = pa->pa_memt;
     380             :         }
     381             : 
     382             :         /* The caller can request limitation of the mapping's size. */
     383           0 :         if (maxsize != 0 && size > maxsize) {
     384             : #ifdef DEBUG
     385             :                 printf("pci_mapreg_map: limited PCI mapping from %lx to %lx\n",
     386             :                     (u_long)size, (u_long)maxsize);
     387             : #endif
     388           0 :                 size = maxsize;
     389           0 :         }
     390             : 
     391           0 :         if (bus_space_map(tag, base, size, flags, &handle))
     392           0 :                 return (1);
     393             : 
     394           0 :         if (tagp != NULL)
     395           0 :                 *tagp = tag;
     396           0 :         if (handlep != NULL)
     397           0 :                 *handlep = handle;
     398           0 :         if (basep != NULL)
     399           0 :                 *basep = base;
     400           0 :         if (sizep != NULL)
     401           0 :                 *sizep = size;
     402             : 
     403           0 :         return (0);
     404           0 : }

Generated by: LCOV version 1.13