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

          Line data    Source code
       1             : /*      $OpenBSD: amas.c,v 1.5 2014/06/15 11:43:24 sf Exp $     */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2009 Ariane van der Steldt <ariane@stack.nl>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Device: amas (AMD memory access/address switch).
      21             :  *
      22             :  * Driver for the amd athlon/opteron 64 address map.
      23             :  * This device is integrated in 64-bit Athlon and Opteron cpus
      24             :  * and contains mappings for memory to processor nodes.
      25             :  */
      26             : 
      27             : #include <dev/pci/amas.h>
      28             : 
      29             : #include <sys/param.h>
      30             : #include <sys/systm.h>
      31             : #include <sys/device.h>
      32             : 
      33             : #include <dev/pci/pcivar.h>
      34             : #include <dev/pci/pcireg.h>
      35             : #include <dev/pci/pcidevs.h>
      36             : 
      37             : int amas_match(struct device*, void*, void*);
      38             : void amas_attach(struct device*, struct device*, void*);
      39             : 
      40             : /*
      41             :  * Amas device layout:
      42             :  *
      43             :  * - base/limit registers (on 0x0f, 0x10, 0x11)
      44             :  * - extended base/limit registers (on 0x10)
      45             :  *
      46             :  * 0x0f, 0x10 support up to 8 nodes
      47             :  * 0x11 supports up to 1 nodes
      48             :  *
      49             :  * base/limit registers use bits [31..16] to indicate address [39..24]
      50             :  * extended base/limit registers use bits [7..0] to indicate address [47..40]
      51             :  * base/limit addresses need to be shifted <<24 for memory address
      52             :  * extended base/limit addresses need to be shifted <<40 for memory address
      53             :  */
      54             : 
      55             : #define AMAS_REG_BASE(node)     (0x0040 + 0x08 * (node))
      56             : #define AMAS_REG_LIMIT(node)    (0x0044 + 0x08 * (node))
      57             : #define AMAS_REG_EXTBASE(node)  (0x0140 + 0x08 * (node))
      58             : #define AMAS_REG_EXTLIMIT(node) (0x0144 + 0x08 * (node))
      59             : 
      60             : #define AMAS_REG_BL_ADDR(reg)   (((reg) >> 16) & 0xffff)
      61             : #define AMAS_REG_EBL_ADDR(ereg) ((ereg) & 0xff)
      62             : 
      63             : #define AMAS_REG_BL_SHIFT       (24)
      64             : #define AMAS_REG_EBL_SHIFT      (40)
      65             : 
      66             : #define AMAS_REG_BL_PGSHIFT     (AMAS_REG_BL_SHIFT - PAGE_SHIFT)
      67             : #define AMAS_REG_EBL_PGSHIFT    (AMAS_REG_EBL_SHIFT - PAGE_SHIFT)
      68             : 
      69             : /*
      70             :  * Convert an address in amas to a page number.
      71             :  *
      72             :  * The device uses an inclusive mapping, where the upper bound address
      73             :  * must be all 1's after shifting.
      74             :  * The device driver uses C-style array indices, hence the +1 in the _LIMIT
      75             :  * macro.
      76             :  */
      77             : #define AMAS_ADDR2PAGE_BASE(base, ebase)                                \
      78             :     (((base) << AMAS_REG_BL_PGSHIFT) | ((ebase) << AMAS_REG_EBL_PGSHIFT))
      79             : #define AMAS_ADDR2PAGE_LIMIT(base, ebase)                               \
      80             :     (((base + 1) << AMAS_REG_BL_PGSHIFT) | ((ebase) << AMAS_REG_EBL_PGSHIFT))
      81             : 
      82             : /*
      83             :  * Node and interleave description.
      84             :  * - base contains node selection [10..8] (on 0x0f, 0x10)
      85             :  * - limit contains node selection bitmask [10..8] (on 0x0f, 0x10)
      86             :  * - limit contains destination node [2..0] (on 0x0f, 0x10)
      87             :  */
      88             : #define AMAS_DST_NODE(base, limit)      ((limit) & 0x07)
      89             : #define AMAS_INTL_ENABLE(base, limit)   (((base) >> 8) & 0x07)
      90             : #define AMAS_INTL_SELECTOR(base, limit) (((limit) >> 8) & 0x07)
      91             : 
      92             : /*
      93             :  * Defines for family.
      94             :  * Corresponds to the amas_feature[] constant below.
      95             :  */
      96             : #define AMAS_FAM_0Fh            (0)
      97             : #define AMAS_FAM_10h            (1)
      98             : #define AMAS_FAM_11h            (2)
      99             : 
     100             : /*
     101             :  * Feature tests.
     102             :  *
     103             :  * 0x11 supports at max 1 node, 0x0f and 0x10 support up to 8 nodes.
     104             :  * 0x11 has extended address registers.
     105             :  * 0x0f, 0x10 can interleave memory.
     106             :  */
     107             : struct amas_feature_t {
     108             :         int maxnodes;
     109             :         int can_intl;
     110             :         int has_extended_bl;
     111             : };
     112             : static const struct amas_feature_t amas_feature[] = {
     113             :         /* Family 0x0f */
     114             :         { 8, 1, 0 },
     115             :         /* Family 0x10 */
     116             :         { 8, 1, 1 },
     117             :         /* Family 0x11 */
     118             :         { 1, 0, 0 },
     119             : };
     120             : 
     121             : /* Probe code. */
     122             : struct cfattach amas_ca = {
     123             :         sizeof(struct amas_softc),
     124             :         amas_match,
     125             :         amas_attach
     126             : };
     127             : 
     128             : struct cfdriver amas_cd = {
     129             :         NULL,
     130             :         "amas",
     131             :         DV_DULL
     132             : };
     133             : 
     134             : const struct pci_matchid amas_devices[] = {
     135             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_AMD64_0F_ADDR },
     136             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_AMD64_10_ADDR },
     137             :         { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_AMD64_11_ADDR },
     138             : };
     139             : 
     140             : int
     141           0 : amas_match(struct device *parent, void *match, void *aux)
     142             : {
     143           0 :         struct pci_attach_args* pa = aux;
     144             : 
     145           0 :         if (pci_matchbyid(pa, amas_devices, nitems(amas_devices)))
     146           0 :                 return 2; /* override pchb */
     147           0 :         return 0;
     148           0 : }
     149             : 
     150             : void
     151           0 : amas_attach(struct device *parent, struct device *self, void *aux)
     152             : {
     153           0 :         struct pci_attach_args *pa = aux;
     154           0 :         struct amas_softc *amas = (struct amas_softc*)self;
     155             : #ifdef DEBUG
     156             :         paddr_t start_pg, end_pg;
     157             :         int nodes, i;
     158             : #endif /* DEBUG */
     159             : 
     160           0 :         amas->pa_tag = pa->pa_tag;
     161           0 :         amas->pa_pc = pa->pa_pc;
     162             : 
     163           0 :         switch (PCI_PRODUCT(pa->pa_id)) {
     164             :         case PCI_PRODUCT_AMD_AMD64_0F_ADDR:
     165           0 :                 amas->family = AMAS_FAM_0Fh;
     166           0 :                 break;
     167             :         case PCI_PRODUCT_AMD_AMD64_10_ADDR:
     168           0 :                 amas->family = AMAS_FAM_10h;
     169           0 :                 break;
     170             :         case PCI_PRODUCT_AMD_AMD64_11_ADDR:
     171           0 :                 amas->family = AMAS_FAM_11h;
     172           0 :                 break;
     173             :         }
     174             : 
     175             : #ifdef DEBUG
     176             :         nodes = amas_intl_nodes(amas);
     177             : 
     178             :         printf(":");
     179             :         if (nodes != 0) {
     180             :                 printf(" interleaved");
     181             :         } else {
     182             :                 for (i = 0; i < AMAS_MAX_NODES; i++) {
     183             :                         amas_get_pagerange(amas, i, &start_pg, &end_pg);
     184             : 
     185             :                         if (!(start_pg == 0 && end_pg == 0))
     186             :                                 printf(" [%#lx, %#lx]", start_pg, end_pg);
     187             :                 }
     188             :         }
     189             : #endif /* DEBUG */
     190           0 :         printf("\n");
     191             : 
     192             :         return;
     193           0 : }
     194             : 
     195             : /*
     196             :  * Returns the number of nodes across which the memory is interleaved.
     197             :  * Returns 0 if the memory is not interleaved.
     198             :  */
     199             : int
     200           0 : amas_intl_nodes(struct amas_softc *amas)
     201             : {
     202             :         pcireg_t base_reg, limit_reg;
     203             :         int mask;
     204             : 
     205           0 :         if (!amas_feature[amas->family].can_intl)
     206           0 :                 return 0;
     207             : 
     208             :         /*
     209             :          * Use node 0 on amas device to find interleave information.
     210             :          * Node 0 is always present.
     211             :          */
     212             : 
     213           0 :         base_reg = pci_conf_read(amas->pa_pc, amas->pa_tag, AMAS_REG_BASE(0));
     214           0 :         limit_reg = pci_conf_read(amas->pa_pc, amas->pa_tag, AMAS_REG_LIMIT(0));
     215           0 :         mask = AMAS_INTL_ENABLE(base_reg, limit_reg);
     216             : 
     217           0 :         return mask == 0 ? 0 : mask + 1;
     218           0 : }
     219             : 
     220             : /*
     221             :  * Returns the range of memory that is contained on the given node.
     222             :  * If the memory is interleaved, the result is undefined.
     223             :  *
     224             :  * The range is written in {start,end}_pg_idx.
     225             :  * Note that these are page numbers and that these use array indices:
     226             :  * pages are in this range if start <= pg_no < end.
     227             :  *
     228             :  * This device supports at most 8 nodes.
     229             :  */
     230             : void
     231           0 : amas_get_pagerange(struct amas_softc *amas, int node,
     232             :     paddr_t *start_pg_idx, paddr_t *end_pg_idx)
     233             : {
     234             :         pcireg_t base, ebase, limit, elimit;
     235             :         paddr_t base_addr, ebase_addr, limit_addr, elimit_addr;
     236             : 
     237             :         /* Sanity check: max AMAS_MAX_NODES supported. */
     238           0 :         KASSERT(node >= 0 && node < AMAS_MAX_NODES);
     239             : 
     240           0 :         if (node >= amas_feature[amas->family].maxnodes) {
     241             :                 /* Unsupported node: bail out early. */
     242           0 :                 *start_pg_idx = 0;
     243           0 :                 *end_pg_idx = 0;
     244           0 :                 return;
     245             :         }
     246             : 
     247           0 :         base = pci_conf_read(amas->pa_pc, amas->pa_tag,
     248           0 :             AMAS_REG_BASE(node));
     249           0 :         limit = pci_conf_read(amas->pa_pc, amas->pa_tag,
     250           0 :             AMAS_REG_LIMIT(node));
     251           0 :         base_addr = AMAS_REG_BL_ADDR(base);
     252           0 :         limit_addr = AMAS_REG_BL_ADDR(limit);
     253             : 
     254             :         ebase = 0;
     255             :         elimit = 0;
     256             :         ebase_addr = 0;
     257             :         elimit_addr = 0;
     258             : #if 0 /* Needs extended pci registers. */
     259             :         if (amas_feature[amas->family].has_extended_bl) {
     260             :                 ebase = pci_conf_read(amas->pa_pc, amas->pa_tag,
     261             :                     AMAS_REG_EXTBASE(node));
     262             :                 elimit = pci_conf_read(amas->pa_pc, amas->pa_tag,
     263             :                     AMAS_REG_EXTLIMIT(node));
     264             :                 ebase_addr = AMAS_REG_EBL_ADDR(ebase);
     265             :                 elimit_addr = AMAS_REG_EBL_ADDR(elimit);
     266             :         }
     267             : #endif /* 0 */
     268             : 
     269           0 :         if (ebase_addr > elimit_addr ||
     270           0 :             (ebase_addr == elimit_addr && base_addr >= limit_addr)) {
     271             :                 /* no memory present */
     272           0 :                 *start_pg_idx = 0;
     273           0 :                 *end_pg_idx = 0;
     274           0 :                 return;
     275             :         }
     276             : 
     277             :         /* Guaranteed by spec. */
     278           0 :         KASSERT(node == AMAS_DST_NODE(base, limit));
     279             : 
     280           0 :         *start_pg_idx = AMAS_ADDR2PAGE_BASE(base_addr, ebase_addr);
     281           0 :         *end_pg_idx = AMAS_ADDR2PAGE_LIMIT(limit_addr, elimit_addr);
     282           0 :         return;
     283           0 : }

Generated by: LCOV version 1.13