1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Starfire Memory Controller specific routines. 31 */ 32 33 #include <sys/debug.h> 34 #include <sys/types.h> 35 #include <sys/errno.h> 36 #include <sys/dditypes.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/sunndi.h> 41 #include <sys/ddi_impldefs.h> 42 #include <sys/promif.h> 43 #include <sys/machsystm.h> 44 45 #include <sys/starfire.h> 46 47 struct mc_dimm_table { 48 int mc_type; 49 int mc_module_size; /* module size in MB */ 50 }; 51 52 static struct mc_dimm_table dimmsize_table[] = { 53 { 4, 8 }, 54 { 6, 8 }, 55 { 11, 32 }, 56 { 15, 128 }, 57 { 0, 0 } 58 }; 59 60 #define MC_MB(mb) ((mb) * 1048576ull) 61 62 struct mc_seg_size { 63 uint_t seg_mask; 64 uint64_t seg_size; 65 }; 66 67 struct mc_seg_size mc_seg_table[] = { 68 { 0x7f, MC_MB(64) }, 69 { 0x7e, MC_MB(128) }, 70 { 0x7c, MC_MB(256) }, 71 { 0x78, MC_MB(512) }, 72 { 0x70, MC_MB(1024) }, 73 { 0x60, MC_MB(2048) }, 74 { 0x40, MC_MB(4096) }, 75 { 0, 0 } 76 }; 77 78 /* 79 * Alignment of memory between MC's. 80 */ 81 uint64_t 82 mc_get_mem_alignment() 83 { 84 return (STARFIRE_MC_MEMBOARD_ALIGNMENT); 85 } 86 87 uint64_t 88 mc_get_asr_addr(pnode_t nodeid) 89 { 90 int rlen; 91 uint64_t psi_addr; 92 struct sf_memunit_regspec reg; 93 94 rlen = prom_getproplen(nodeid, "reg"); 95 if (rlen != sizeof (struct sf_memunit_regspec)) 96 return ((uint64_t)-1); 97 98 if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) 99 return ((uint64_t)-1); 100 101 psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; 102 psi_addr |= (uint64_t)reg.regspec_addr_lo; 103 104 return (STARFIRE_MC_ASR_ADDR(psi_addr)); 105 } 106 107 uint64_t 108 mc_get_idle_addr(pnode_t nodeid) 109 { 110 int rlen; 111 uint64_t psi_addr; 112 struct sf_memunit_regspec reg; 113 114 rlen = prom_getproplen(nodeid, "reg"); 115 if (rlen != sizeof (struct sf_memunit_regspec)) 116 return ((uint64_t)-1); 117 118 if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) 119 return ((uint64_t)-1); 120 121 psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; 122 psi_addr |= (uint64_t)reg.regspec_addr_lo; 123 124 return (STARFIRE_MC_IDLE_ADDR(psi_addr)); 125 } 126 127 int 128 mc_get_dimm_size(pnode_t nodeid) 129 { 130 uint64_t psi_addr; 131 uint_t dimmtype; 132 int i, rlen; 133 struct sf_memunit_regspec reg; 134 135 rlen = prom_getproplen(nodeid, "reg"); 136 if (rlen != sizeof (struct sf_memunit_regspec)) 137 return (-1); 138 139 if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) 140 return (-1); 141 142 psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; 143 psi_addr |= (uint64_t)reg.regspec_addr_lo; 144 psi_addr = STARFIRE_MC_DIMMTYPE_ADDR(psi_addr); 145 146 if (psi_addr == (uint64_t)-1) 147 return (-1); 148 149 dimmtype = ldphysio(psi_addr); 150 dimmtype &= STARFIRE_MC_DIMMSIZE_MASK; 151 152 for (i = 0; dimmsize_table[i].mc_type != 0; i++) 153 if (dimmsize_table[i].mc_type == dimmtype) 154 break; 155 156 return (dimmsize_table[i].mc_module_size); 157 } 158 159 uint64_t 160 mc_get_alignment_mask(pnode_t nodeid) 161 { 162 uint64_t psi_addr, seg_sz; 163 uint_t mcreg, seg_sz_mask; 164 int i, rlen; 165 struct sf_memunit_regspec reg; 166 167 rlen = prom_getproplen(nodeid, "reg"); 168 if (rlen != sizeof (struct sf_memunit_regspec)) 169 return (-1); 170 171 if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) 172 return (-1); 173 174 psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; 175 psi_addr |= (uint64_t)reg.regspec_addr_lo; 176 psi_addr = STARFIRE_MC_ASR_ADDR(psi_addr); 177 178 if (psi_addr == (uint64_t)-1) 179 return (-1); 180 181 mcreg = ldphysio(psi_addr); 182 seg_sz_mask = (mcreg & STARFIRE_MC_MASK_MASK) >> 8; 183 184 for (i = 0; mc_seg_table[i].seg_size != 0; i++) 185 if (mc_seg_table[i].seg_mask == seg_sz_mask) 186 break; 187 188 if (mc_seg_table[i].seg_size == 0) 189 seg_sz = mc_get_mem_alignment(); 190 else 191 seg_sz = mc_seg_table[i].seg_size; 192 193 #ifdef DEBUG 194 printf("nodeid %x, mc asr addr %llx, val %x, seg_sz_mask %x, " 195 "seg_sz %llx\n", nodeid, psi_addr, mcreg, seg_sz_mask, seg_sz); 196 #endif /* DEBUG */ 197 198 return (seg_sz - 1); 199 } 200 201 int 202 mc_read_asr(pnode_t nodeid, uint_t *mcregp) 203 { 204 uint64_t psi_addr; 205 206 *mcregp = 0; 207 208 psi_addr = mc_get_asr_addr(nodeid); 209 if (psi_addr == (uint64_t)-1) 210 return (-1); 211 212 *mcregp = ldphysio(psi_addr); 213 214 return (0); 215 } 216 217 int 218 mc_write_asr(pnode_t nodeid, uint_t mcreg) 219 { 220 uint_t mcreg_rd; 221 uint64_t psi_addr; 222 223 psi_addr = mc_get_asr_addr(nodeid); 224 if (psi_addr == (uint64_t)-1) 225 return (-1); 226 227 stphysio(psi_addr, mcreg); 228 229 mcreg_rd = ldphysio(psi_addr); 230 ASSERT(mcreg_rd == mcreg); 231 232 return ((mcreg_rd != mcreg) ? -1 : 0); 233 } 234 235 uint64_t 236 mc_asr_to_pa(uint_t mcreg) 237 { 238 uint64_t pa, masr, addrmask, lowbitmask; 239 240 /* 241 * Remove memory present bit. 242 */ 243 masr = (uint64_t)(mcreg & ~STARFIRE_MC_MEM_PRESENT_MASK); 244 /* 245 * Get mask for bits 32-26. 246 */ 247 lowbitmask = masr & (uint64_t)STARFIRE_MC_MASK_MASK; 248 lowbitmask <<= STARFIRE_MC_MASK_SHIFT; 249 addrmask = STARFIRE_MC_ADDR_HIBITS | lowbitmask; 250 251 pa = (masr << STARFIRE_MC_BASE_SHIFT) & addrmask; 252 253 return (pa); 254 } 255 256 uint_t 257 mc_pa_to_asr(uint_t masr, uint64_t pa) 258 { 259 uint64_t addrmask, lowbitmask; 260 uint_t base; 261 262 /* 263 * Get mask for bits 32-26. 264 */ 265 lowbitmask = masr & (uint64_t)STARFIRE_MC_MASK_MASK; 266 lowbitmask <<= STARFIRE_MC_MASK_SHIFT; 267 addrmask = STARFIRE_MC_ADDR_HIBITS | lowbitmask; 268 269 base = (pa & addrmask) >> STARFIRE_MC_BASE_SHIFT; 270 masr &= ~ STARFIRE_MC_MEM_BASEADDR_MASK; 271 masr |= base & STARFIRE_MC_MEM_BASEADDR_MASK; 272 273 ASSERT(mc_asr_to_pa(masr) == pa); 274 275 return (masr); 276 } 277