| File: | dev/pci/amas.c |
| Warning: | line 254, column 2 Value stored to 'ebase' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: amas.c,v 1.7 2022/03/11 18:00:45 mpi 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)) (0x0040 + 0x08 * (node)) |
| 56 | #define AMAS_REG_LIMIT(node)(0x0044 + 0x08 * (node)) (0x0044 + 0x08 * (node)) |
| 57 | #define AMAS_REG_EXTBASE(node)(0x0140 + 0x08 * (node)) (0x0140 + 0x08 * (node)) |
| 58 | #define AMAS_REG_EXTLIMIT(node)(0x0144 + 0x08 * (node)) (0x0144 + 0x08 * (node)) |
| 59 | |
| 60 | #define AMAS_REG_BL_ADDR(reg)(((reg) >> 16) & 0xffff) (((reg) >> 16) & 0xffff) |
| 61 | #define AMAS_REG_EBL_ADDR(ereg)((ereg) & 0xff) ((ereg) & 0xff) |
| 62 | |
| 63 | #define AMAS_REG_BL_SHIFT(24) (24) |
| 64 | #define AMAS_REG_EBL_SHIFT(40) (40) |
| 65 | |
| 66 | #define AMAS_REG_BL_PGSHIFT((24) - 12) (AMAS_REG_BL_SHIFT(24) - PAGE_SHIFT12) |
| 67 | #define AMAS_REG_EBL_PGSHIFT((40) - 12) (AMAS_REG_EBL_SHIFT(40) - PAGE_SHIFT12) |
| 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)(((base) << ((24) - 12)) | ((ebase) << ((40) - 12 ))) \ |
| 78 | (((base) << AMAS_REG_BL_PGSHIFT((24) - 12)) | ((ebase) << AMAS_REG_EBL_PGSHIFT((40) - 12))) |
| 79 | #define AMAS_ADDR2PAGE_LIMIT(base, ebase)(((base + 1) << ((24) - 12)) | ((ebase) << ((40) - 12))) \ |
| 80 | (((base + 1) << AMAS_REG_BL_PGSHIFT((24) - 12)) | ((ebase) << AMAS_REG_EBL_PGSHIFT((40) - 12))) |
| 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) ((limit) & 0x07) |
| 89 | #define AMAS_INTL_ENABLE(base, limit)(((base) >> 8) & 0x07) (((base) >> 8) & 0x07) |
| 90 | #define AMAS_INTL_SELECTOR(base, limit)(((limit) >> 8) & 0x07) (((limit) >> 8) & 0x07) |
| 91 | |
| 92 | /* |
| 93 | * Defines for family. |
| 94 | * Corresponds to the amas_feature[] constant below. |
| 95 | */ |
| 96 | #define AMAS_FAM_0Fh(0) (0) |
| 97 | #define AMAS_FAM_10h(1) (1) |
| 98 | #define AMAS_FAM_11h(2) (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 | const struct cfattach amas_ca = { |
| 123 | sizeof(struct amas_softc), |
| 124 | amas_match, |
| 125 | amas_attach |
| 126 | }; |
| 127 | |
| 128 | struct cfdriver amas_cd = { |
| 129 | NULL((void *)0), |
| 130 | "amas", |
| 131 | DV_DULL |
| 132 | }; |
| 133 | |
| 134 | const struct pci_matchid amas_devices[] = { |
| 135 | { PCI_VENDOR_AMD0x1022, PCI_PRODUCT_AMD_0F_ADDR0x1101 }, |
| 136 | { PCI_VENDOR_AMD0x1022, PCI_PRODUCT_AMD_10_ADDR0x1201 }, |
| 137 | { PCI_VENDOR_AMD0x1022, PCI_PRODUCT_AMD_11_ADDR0x1301 }, |
| 138 | }; |
| 139 | |
| 140 | int |
| 141 | amas_match(struct device *parent, void *match, void *aux) |
| 142 | { |
| 143 | struct pci_attach_args* pa = aux; |
| 144 | |
| 145 | if (pci_matchbyid(pa, amas_devices, nitems(amas_devices)(sizeof((amas_devices)) / sizeof((amas_devices)[0])))) |
| 146 | return 2; /* override pchb */ |
| 147 | return 0; |
| 148 | } |
| 149 | |
| 150 | void |
| 151 | amas_attach(struct device *parent, struct device *self, void *aux) |
| 152 | { |
| 153 | struct pci_attach_args *pa = aux; |
| 154 | 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 | amas->pa_tag = pa->pa_tag; |
| 161 | amas->pa_pc = pa->pa_pc; |
| 162 | |
| 163 | switch (PCI_PRODUCT(pa->pa_id)(((pa->pa_id) >> 16) & 0xffff)) { |
| 164 | case PCI_PRODUCT_AMD_0F_ADDR0x1101: |
| 165 | amas->family = AMAS_FAM_0Fh(0); |
| 166 | break; |
| 167 | case PCI_PRODUCT_AMD_10_ADDR0x1201: |
| 168 | amas->family = AMAS_FAM_10h(1); |
| 169 | break; |
| 170 | case PCI_PRODUCT_AMD_11_ADDR0x1301: |
| 171 | amas->family = AMAS_FAM_11h(2); |
| 172 | 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(8); 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 | printf("\n"); |
| 191 | |
| 192 | return; |
| 193 | } |
| 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 | amas_intl_nodes(struct amas_softc *amas) |
| 201 | { |
| 202 | pcireg_t base_reg, limit_reg; |
| 203 | int mask; |
| 204 | |
| 205 | if (!amas_feature[amas->family].can_intl) |
| 206 | return 0; |
| 207 | |
| 208 | /* |
| 209 | * Use node 0 on amas device to find interleave information. |
| 210 | * Node 0 is always present. |
| 211 | */ |
| 212 | |
| 213 | base_reg = pci_conf_read(amas->pa_pc, amas->pa_tag, AMAS_REG_BASE(0)(0x0040 + 0x08 * (0))); |
| 214 | limit_reg = pci_conf_read(amas->pa_pc, amas->pa_tag, AMAS_REG_LIMIT(0)(0x0044 + 0x08 * (0))); |
| 215 | mask = AMAS_INTL_ENABLE(base_reg, limit_reg)(((base_reg) >> 8) & 0x07); |
| 216 | |
| 217 | return mask == 0 ? 0 : mask + 1; |
| 218 | } |
| 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 | 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 | KASSERT(node >= 0 && node < AMAS_MAX_NODES)((node >= 0 && node < (8)) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/dev/pci/amas.c", 238, "node >= 0 && node < AMAS_MAX_NODES" )); |
| 239 | |
| 240 | if (node >= amas_feature[amas->family].maxnodes) { |
| 241 | /* Unsupported node: bail out early. */ |
| 242 | *start_pg_idx = 0; |
| 243 | *end_pg_idx = 0; |
| 244 | return; |
| 245 | } |
| 246 | |
| 247 | base = pci_conf_read(amas->pa_pc, amas->pa_tag, |
| 248 | AMAS_REG_BASE(node)(0x0040 + 0x08 * (node))); |
| 249 | limit = pci_conf_read(amas->pa_pc, amas->pa_tag, |
| 250 | AMAS_REG_LIMIT(node)(0x0044 + 0x08 * (node))); |
| 251 | base_addr = AMAS_REG_BL_ADDR(base)(((base) >> 16) & 0xffff); |
| 252 | limit_addr = AMAS_REG_BL_ADDR(limit)(((limit) >> 16) & 0xffff); |
| 253 | |
| 254 | ebase = 0; |
Value stored to 'ebase' is never read | |
| 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)(0x0140 + 0x08 * (node))); |
| 262 | elimit = pci_conf_read(amas->pa_pc, amas->pa_tag, |
| 263 | AMAS_REG_EXTLIMIT(node)(0x0144 + 0x08 * (node))); |
| 264 | ebase_addr = AMAS_REG_EBL_ADDR(ebase)((ebase) & 0xff); |
| 265 | elimit_addr = AMAS_REG_EBL_ADDR(elimit)((elimit) & 0xff); |
| 266 | } |
| 267 | #endif /* 0 */ |
| 268 | |
| 269 | if (ebase_addr > elimit_addr || |
| 270 | (ebase_addr == elimit_addr && base_addr >= limit_addr)) { |
| 271 | /* no memory present */ |
| 272 | *start_pg_idx = 0; |
| 273 | *end_pg_idx = 0; |
| 274 | return; |
| 275 | } |
| 276 | |
| 277 | /* Guaranteed by spec. */ |
| 278 | KASSERT(node == AMAS_DST_NODE(base, limit))((node == ((limit) & 0x07)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pci/amas.c", 278, "node == AMAS_DST_NODE(base, limit)" )); |
| 279 | |
| 280 | *start_pg_idx = AMAS_ADDR2PAGE_BASE(base_addr, ebase_addr)(((base_addr) << ((24) - 12)) | ((ebase_addr) << ( (40) - 12))); |
| 281 | *end_pg_idx = AMAS_ADDR2PAGE_LIMIT(limit_addr, elimit_addr)(((limit_addr + 1) << ((24) - 12)) | ((elimit_addr) << ((40) - 12))); |
| 282 | return; |
| 283 | } |