| 1 | /* |
| 2 | * ========== Copyright Header Begin ========================================== |
| 3 | * |
| 4 | * Hypervisor Software File: l2subr.s |
| 5 | * |
| 6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 7 | * |
| 8 | * - Do no alter or remove copyright notices |
| 9 | * |
| 10 | * - Redistribution and use of this software in source and binary forms, with |
| 11 | * or without modification, are permitted provided that the following |
| 12 | * conditions are met: |
| 13 | * |
| 14 | * - Redistribution of source code must retain the above copyright notice, |
| 15 | * this list of conditions and the following disclaimer. |
| 16 | * |
| 17 | * - Redistribution in binary form must reproduce the above copyright notice, |
| 18 | * this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * |
| 21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors |
| 22 | * may be used to endorse or promote products derived from this software |
| 23 | * without specific prior written permission. |
| 24 | * |
| 25 | * This software is provided "AS IS," without a warranty of any kind. |
| 26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, |
| 27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
| 28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN |
| 29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR |
| 30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR |
| 31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN |
| 32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR |
| 33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE |
| 34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, |
| 35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF |
| 36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
| 37 | * |
| 38 | * You acknowledge that this software is not designed, licensed or |
| 39 | * intended for use in the design, construction, operation or maintenance of |
| 40 | * any nuclear facility. |
| 41 | * |
| 42 | * ========== Copyright Header End ============================================ |
| 43 | */ |
| 44 | /* |
| 45 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
| 46 | * Use is subject to license terms. |
| 47 | */ |
| 48 | |
| 49 | .ident "@(#)l2subr.s 1.11 07/05/03 SMI" |
| 50 | |
| 51 | #include <sys/asm_linkage.h> |
| 52 | #include <sys/htypes.h> |
| 53 | #include "offsets.h" |
| 54 | #include "cpu_errs.h" |
| 55 | #include "util.h" |
| 56 | |
| 57 | |
| 58 | /* |
| 59 | * L2_FLUSH_BASEADDR - get a 4MB-aligned DRAM address for l2$ flushing |
| 60 | * The assumption is that %htba contains a valid dram address valid |
| 61 | * for the current machine configuration. Round it down to a 4MB |
| 62 | * boundary to use as a base address for l2$ flushing. |
| 63 | */ |
| 64 | #define L2_FLUSH_BASEADDR(addr, scr) \ |
| 65 | rdhpr %htba, addr ;\ |
| 66 | set (4 MB) - 1, scr ;\ |
| 67 | andn addr, scr, addr |
| 68 | |
| 69 | |
| 70 | /* |
| 71 | * get_l2_vdbits_for_pa()() |
| 72 | * Read VD (Valid Dirty) bits of l2$ set for a given PA |
| 73 | * Arguments: |
| 74 | * %g1 -> input - physical address (preserved) |
| 75 | * %g2 -> output - VD bit array for 12 ways |
| 76 | * --------------------------------------- |
| 77 | * |VPARITY| DPARITY||V11|..|V0|D11|..|D0| |
| 78 | * --------------------------------------- |
| 79 | * Bits-> 25 24 23 12 11 0 |
| 80 | * |
| 81 | * %g3 -> scratch |
| 82 | * %g4 - preserved |
| 83 | * %g5, %g6 - preserved |
| 84 | * %g7 -> input - return address |
| 85 | */ |
| 86 | ENTRY_NP(get_l2_vdbits_for_pa) |
| 87 | set 0xa6004000, %g2 |
| 88 | sllx %g2, 8, %g2 ! %g2 = L2_SELECT_A6 | L2_VDSEL |
| 89 | and %g1, 0xC0, %g3 ! %g3 = paddr & L2_BANK_MASK |
| 90 | or %g2, %g3, %g2 ! %g2 |= %g3 |
| 91 | set 0x3FF00, %g3 ! %g3 = L2_SET_MASK |
| 92 | and %g1, %g3, %g3 ! %g3 &= paddr |
| 93 | or %g2, %g3, %g2 ! %g2 |= %g3 |
| 94 | jmp %g7 + 4 ! return |
| 95 | ldx [%g2], %g2 ! %g2 -> output |
| 96 | SET_SIZE(get_l2_vdbits_for_pa) |
| 97 | |
| 98 | |
| 99 | /* |
| 100 | * get_l2_vdbits_for_set() |
| 101 | * Read VD (Valid Dirty) bits of l2$ set specified by index and bank |
| 102 | * Arguments: |
| 103 | * %g1 -> input - set index (preserved) |
| 104 | * %g2 -> input - L2 bank number (preserved) |
| 105 | * %g3 -> output - VD bit array for 12 ways |
| 106 | * --------------------------------------- |
| 107 | * |VPARITY| DPARITY |V11 .. V0|D11 .. D0| |
| 108 | * --------------------------------------- |
| 109 | * Bits-> 25 24 23 12 11 0 |
| 110 | * |
| 111 | * %g4 -> scratch |
| 112 | * %g5, %g6 - preserved |
| 113 | * %g7 -> input - return address |
| 114 | */ |
| 115 | ENTRY_NP(get_l2_vdbits_for_set) |
| 116 | set 0xa6004000, %g3 |
| 117 | sllx %g3, 8, %g3 ! %g3 = L2_SELECT_A6 | L2_VDSEL |
| 118 | sllx %g1, L2_SET_SHIFT, %g4 ! %g4 = set << L2_SET_SHIFT |
| 119 | or %g3, %g4, %g3 ! %g3 |= %g4 |
| 120 | sllx %g2, L2_BANK_SHIFT, %g4 ! %g4 = bank << L2_BANK_SHIFT |
| 121 | or %g3, %g4, %g3 ! %g3 |= %g4 |
| 122 | jmp %g7 + 4 ! return |
| 123 | ldx [%g3], %g3 ! %g3 -> output |
| 124 | SET_SIZE(get_l2_vdbits_for_set) |
| 125 | |
| 126 | /* |
| 127 | * get_l2_uabits_for_pa()() |
| 128 | * Read UA (Used Allocated) bits of l2$ set for a given PA |
| 129 | * Arguments: |
| 130 | * %g1 -> input - physical address (preserved) |
| 131 | * %g2 -> output - UA bit array for 12 ways |
| 132 | * ------------------------------- |
| 133 | * | DPARITY |V11 .. V0|D11 .. D0| |
| 134 | * ------------------------------- |
| 135 | * Bits-> 24 23 12 11 0 |
| 136 | * |
| 137 | * %g3 -> scratch |
| 138 | * %g4 - preserved |
| 139 | * %g5, %g6 - preserved |
| 140 | * %g7 -> input - return address |
| 141 | */ |
| 142 | ENTRY_NP(get_l2_uabits_for_pa) |
| 143 | set 0xa6000000, %g2 |
| 144 | sllx %g2, 8, %g2 ! %g2 = L2_SELECT_A6 |
| 145 | and %g1, 0xC0, %g3 ! %g3 = paddr & L2_BANK_MASK |
| 146 | or %g2, %g3, %g2 ! %g2 |= %g3 |
| 147 | set 0x3FF00, %g3 ! %g3 = L2_SET_MASK |
| 148 | and %g1, %g3, %g3 ! %g3 &= paddr |
| 149 | or %g2, %g3, %g2 ! %g2 |= %g3 |
| 150 | jmp %g7 + 4 ! return |
| 151 | ldx [%g2], %g2 ! %g2 -> output |
| 152 | SET_SIZE(get_l2_uabits_for_pa) |
| 153 | |
| 154 | /* |
| 155 | * get_l2_tag_for_line(int way, int set, int bank) |
| 156 | * Read L2$ tag for a given way, set, and bank. |
| 157 | * Arguments: |
| 158 | * %g1 -> input - cache way |
| 159 | * %g2 -> input - set index |
| 160 | * %g3 -> input - bank number |
| 161 | * %g4 -> output - L2$ tag |
| 162 | * -------------------------- |
| 163 | * | TAG => PA<39:18> | ECC | |
| 164 | * -------------------------- |
| 165 | * 27...............6 5...0 |
| 166 | * %g5, %g6 - preserved |
| 167 | * %g7 -> return address |
| 168 | */ |
| 169 | ENTRY_NP(get_l2_tag_for_line) |
| 170 | set 0xa4000000, %g4 ! %g4 = L2_SELECT_A4 >> 8 |
| 171 | or %g4, %g2, %g4 ! %g4 += set index |
| 172 | sllx %g4, L2_SET_SHIFT, %g4 ! %g4 << L2_SET_SHIFT (8) |
| 173 | sllx %g1, L2_WAY_SHIFT, %g1 ! %g1 = %g1 << L2_WAY_SHIFT |
| 174 | or %g4, %g1, %g4 ! %g4 |= %g1 |
| 175 | srlx %g1, L2_WAY_SHIFT, %g1 ! %g1 = %g1 >> L2_WAY_SHIFT |
| 176 | sllx %g3, L2_BANK_SHIFT, %g3 ! %g3 = %g3 << L2_BANK_SHIFT |
| 177 | or %g4, %g3, %g4 ! %g4 |= %g3 |
| 178 | srlx %g3, L2_BANK_SHIFT, %g3 ! %g3 = %g3 >> L2_BANK_SHIFT |
| 179 | jmp %g7 + 4 ! return |
| 180 | ldx [%g4], %g4 ! %g4 -> output |
| 181 | SET_SIZE(get_l2_tag_for_line) |
| 182 | |
| 183 | /* |
| 184 | * get_l2_tag_by_way(uint64_t pa, int way) |
| 185 | * Read L2$ tag for a given way and physical address |
| 186 | * Arguments: |
| 187 | * %g1 -> input - physical address |
| 188 | * %g2 -> input - way |
| 189 | * %g3 -> output - L2$ tag |
| 190 | * -------------------------- |
| 191 | * | TAG => PA<39:18> | ECC | |
| 192 | * -------------------------- |
| 193 | * 27...............6 5...0 |
| 194 | * %g4 -> scratch |
| 195 | * %g5, %g6 - preserved |
| 196 | * %g7 -> return address |
| 197 | */ |
| 198 | ENTRY_NP(get_l2_tag_by_way) |
| 199 | set 0x3FFC0, %g4 ! %g4 = L2 SET|BANK MASK <17:6> |
| 200 | and %g4, %g1, %g4 ! %g4 &= %g1 (pa) |
| 201 | sllx %g2, L2_WAY_SHIFT, %g3 ! %g3 = %g2 << L2_WAY_SHIFT |
| 202 | or %g4, %g3, %g4 ! %g4 |= %g3 |
| 203 | set 0xA4, %g3 |
| 204 | sllx %g3, 32, %g3 ! %g3 = L2_SELECT_A4 |
| 205 | or %g3, %g4, %g3 ! %g3 |= %g4 |
| 206 | jmp %g7 + 4 ! return |
| 207 | ldx [%g3], %g3 ! %g3 -> output |
| 208 | SET_SIZE(get_l2_tag_by_way) |
| 209 | |
| 210 | /* |
| 211 | * set_l2_bank_dmmode(int bank) |
| 212 | * Set the L2 bank in direct-mapped displacement mode |
| 213 | * Arguments: |
| 214 | * %g1 - input -> L2 bank number (preserved) |
| 215 | * %g2 - scratch |
| 216 | * %g3 - scratch |
| 217 | * %g4, %g5, %g6 - preserved |
| 218 | * %g7 - input -> return address |
| 219 | */ |
| 220 | ENTRY_NP(set_l2_bank_dmmode) |
| 221 | setx L2_CONTROL_REG, %g3, %g2 |
| 222 | sllx %g1, L2_BANK_SHIFT, %g3 |
| 223 | or %g2, %g3, %g2 ! or in L2 bank |
| 224 | ldx [%g2], %g3 ! read L2_CONTROL[bank] |
| 225 | or %g3, L2_DMMODE, %g3 ! %g3 |= L2_DMMODE |
| 226 | jmp %g7 + 4 ! return |
| 227 | stx %g3, [%g2] ! L2_CONTROL[bank] = %g3 |
| 228 | SET_SIZE(set_l2_bank_dmmode) |
| 229 | |
| 230 | |
| 231 | /* |
| 232 | * reset_l2_bank_dmmode(int bank) |
| 233 | * Reset the L2 bank to normal mode |
| 234 | * Arguments: |
| 235 | * %g1 - input -> L2 bank number (preserved) |
| 236 | * %g2 - scratch |
| 237 | * %g3 - scratch |
| 238 | * %g4, %g5, %g6 - preserved |
| 239 | * %g7 - input -> return address |
| 240 | */ |
| 241 | ENTRY_NP(reset_l2_bank_dmmode) |
| 242 | setx L2_CONTROL_REG, %g3, %g2 |
| 243 | sllx %g1, L2_BANK_SHIFT, %g3 |
| 244 | or %g2, %g3, %g2 ! or in L2 bank |
| 245 | ldx [%g2], %g3 ! read L2_CONTROL[bank] |
| 246 | bclr L2_DMMODE, %g3 ! %g3 &= ~L2_DMMODE |
| 247 | jmp %g7 + 4 ! return |
| 248 | stx %g3, [%g2] ! L2_CONTROL[bank] = %g3 |
| 249 | SET_SIZE(reset_l2_bank_dmmode) |
| 250 | |
| 251 | |
| 252 | /* |
| 253 | * set_all_banks_dmmode - set all l2 banks to direct-mapped mode |
| 254 | * |
| 255 | * NON-LEAF |
| 256 | * %g7 - return address |
| 257 | * clobbers %g6 along with the lowered-numbered registers |
| 258 | * clobbered by set_l2_bank_dmmode |
| 259 | */ |
| 260 | ENTRY_NP(set_all_banks_dmmode) |
| 261 | mov %g7, %g6 ! save return |
| 262 | |
| 263 | mov 0, %g1 ! bank 0 |
| 264 | HVCALL(set_l2_bank_dmmode) |
| 265 | |
| 266 | mov 1, %g1 ! bank 1 |
| 267 | HVCALL(set_l2_bank_dmmode) |
| 268 | |
| 269 | mov 2, %g1 ! bank 2 |
| 270 | HVCALL(set_l2_bank_dmmode) |
| 271 | |
| 272 | mov 3, %g1 ! bank 3 |
| 273 | HVCALL(set_l2_bank_dmmode) |
| 274 | |
| 275 | mov %g6, %g7 ! restore return |
| 276 | HVRET |
| 277 | SET_SIZE(set_all_banks_dmmode) |
| 278 | |
| 279 | /* |
| 280 | * reset_all_banks_dmmode - set all l2 banks to normal mode |
| 281 | * |
| 282 | * NON-LEAF |
| 283 | * %g7 - return address |
| 284 | * clobbers %g6 along with the lowered-numbered registers |
| 285 | * clobbered by reset_set_l2_bank_dmmode |
| 286 | */ |
| 287 | ENTRY_NP(reset_all_banks_dmmode) |
| 288 | mov %g7, %g6 ! save return |
| 289 | |
| 290 | mov 0, %g1 |
| 291 | HVCALL(reset_l2_bank_dmmode) |
| 292 | |
| 293 | mov 1, %g1 ! bank 1 |
| 294 | HVCALL(reset_l2_bank_dmmode) |
| 295 | |
| 296 | mov 2, %g1 ! bank 2 |
| 297 | HVCALL(reset_l2_bank_dmmode) |
| 298 | |
| 299 | mov 3, %g1 ! bank 3 |
| 300 | HVCALL(reset_l2_bank_dmmode) |
| 301 | |
| 302 | mov %g6, %g7 ! restore return |
| 303 | HVRET |
| 304 | SET_SIZE(reset_all_banks_dmmode) |
| 305 | |
| 306 | /* |
| 307 | * l2_flush_cache(void) |
| 308 | * Flush the entire l2 cache |
| 309 | * clobbers %g1-%g6 |
| 310 | * %g7 - return address |
| 311 | */ |
| 312 | ENTRY_NP(l2_flush_cache) |
| 313 | mov %g7, %g5 ! set_all_banks_dmmode clobbers %g6 |
| 314 | |
| 315 | HVCALL(set_all_banks_dmmode) |
| 316 | |
| 317 | /* |
| 318 | * read in from 0 to 3MB * 2. Experiments have shown that reading |
| 319 | * in 3 times the size of L2$ from 3 different 4MB-aligned addresses |
| 320 | * flushes the cache reliably. |
| 321 | */ |
| 322 | L2_FLUSH_BASEADDR(%g2, %g4) |
| 323 | set 0x900000, %g1 ! end |
| 324 | add %g2, %g1, %g1 |
| 325 | |
| 326 | 1: |
| 327 | ldx [%g2], %g0 |
| 328 | inc L2_LINE_SIZE, %g2 ! next cache line |
| 329 | cmp %g2, %g1 |
| 330 | blu,pt %xcc, 1b ! not done, go to 1 |
| 331 | nop |
| 332 | |
| 333 | HVCALL(reset_all_banks_dmmode) |
| 334 | |
| 335 | mov %g5, %g7 |
| 336 | HVRET |
| 337 | SET_SIZE(l2_flush_cache) |
| 338 | |
| 339 | |
| 340 | /* |
| 341 | * l2_flush_line(uint64_t pa) [Non-leaf function] |
| 342 | * Flush the L2$ line corresponding to the physical address, pa |
| 343 | * Arguments: |
| 344 | * %g1 - input - physical address |
| 345 | * %g2-%g6 - scratch |
| 346 | * %g7 - input - return address |
| 347 | */ |
| 348 | ENTRY_NP(l2_flush_line) |
| 349 | mov %g1, %g6 ! save phys addr |
| 350 | mov %g7, %g5 ! save return address |
| 351 | and %g1, 0xC0, %g1 ! %g1 &= L2_BANK_MASK |
| 352 | srlx %g1, L2_BANK_SHIFT, %g1 ! %g1 = L2 bank |
| 353 | ba set_l2_bank_dmmode ! set L2[bank] = DMMODE |
| 354 | rd %pc, %g7 |
| 355 | |
| 356 | ! do displacement flush |
| 357 | set 0x3FFC0, %g1 ! %g1 = L2 SET|BANK MASK <17:6> |
| 358 | and %g1, %g6, %g1 ! %g1 = pa & L2_SET|BANK MASK |
| 359 | |
| 360 | L2_FLUSH_BASEADDR(%g3, %g4) |
| 361 | |
| 362 | add %g3, %g1, %g3 ! %g3 = flush addr for set, bank |
| 363 | set 0x40000, %g2 ! way increment |
| 364 | set 0x2C0000, %g4 |
| 365 | mov 0, %g1 ! current way |
| 366 | ! loop 12-way |
| 367 | 1: |
| 368 | ldx [%g3 + %g1], %g0 ! displacement flush read |
| 369 | add %g1, %g2, %g1 ! way += 0x40000 (next way) |
| 370 | cmp %g1, %g4 ! done? |
| 371 | bleu %xcc, 1b |
| 372 | nop |
| 373 | |
| 374 | ! reset dmmode bit |
| 375 | and %g6, 0xC0, %g1 ! %g1 &= L2_BANK_MASK |
| 376 | srlx %g1, L2_BANK_SHIFT, %g1 ! %g1 = L2 bank |
| 377 | ba reset_l2_bank_dmmode |
| 378 | rd %pc, %g7 |
| 379 | |
| 380 | ! return |
| 381 | mov %g6, %g1 ! restore input args |
| 382 | mov %g5, %g7 ! restore input args |
| 383 | HVRET |
| 384 | SET_SIZE(l2_flush_line) |
| 385 | |
| 386 | /* |
| 387 | * dump_l2_set_tag_data_ecc(uint64_t pa, void *dump_area) [Non-leaf] |
| 388 | * Dump the L2$ tag and data and ECC for the set corresponding to the |
| 389 | * given physical address, pa. |
| 390 | * |
| 391 | * The dump format is: |
| 392 | * 0x0 [VPARITY | DPARITY | VALID bits | DIRTY bits] |
| 393 | * 0x8 [APARITY | USED bits | ALLOC bits] |
| 394 | * 0x10 [way 0 tag + ECC] |
| 395 | * 0x18 [way 0 32-bit word 0 + ECC] |
| 396 | * 0x20 [way 0 32-bit word 1 + ECC] |
| 397 | * 0x28 [way 0 32-bit word 2 + ECC] |
| 398 | * ... |
| 399 | * 0x90 [way 0 32-bit word 15 + ECC] |
| 400 | * 0x98 [way 1 tag + ECC] |
| 401 | * 0xa0 way 1 data |
| 402 | * ... |
| 403 | * |
| 404 | * This function does not change L2$ enabled/disabled status. |
| 405 | * |
| 406 | * Arguments: |
| 407 | * %g1 - input - physical address |
| 408 | * %g2 - input - pointer to dump area |
| 409 | * %g3-%g6 - scratch |
| 410 | * %g7 - input - return address |
| 411 | */ |
| 412 | ENTRY_NP(dump_l2_set_tag_data_ecc) |
| 413 | mov %g2, %g5 |
| 414 | mov %g7, %g6 |
| 415 | ba get_l2_vdbits_for_pa |
| 416 | rd %pc, %g7 |
| 417 | |
| 418 | stx %g2, [%g5] ! store VD bits and parity |
| 419 | add %g5, 8, %g5 |
| 420 | |
| 421 | ba get_l2_uabits_for_pa |
| 422 | rd %pc, %g7 |
| 423 | |
| 424 | stx %g2, [%g5] ! save UA bits and parity |
| 425 | add %g5, 8, %g5 |
| 426 | |
| 427 | mov %g0, %g2 ! set way = 0 |
| 428 | ba get_l2_tag_by_way |
| 429 | rd %pc, %g7 |
| 430 | |
| 431 | stx %g3, [%g5] ! save tag_ECC[0] |
| 432 | add %g5, 8, %g5 |
| 433 | |
| 434 | mov %g6, %g7 ! restore original return |
| 435 | |
| 436 | mov %g0, %g2 ! way number |
| 437 | 1: |
| 438 | set 0x3FFC0, %g4 ! %g4 = L2 SET|BANK MASK <17:6> |
| 439 | and %g4, %g1, %g4 ! %g4 &= %g1 (pa) |
| 440 | or %g4, %g2, %g4 ! %g4 |= (way_num << L2_WAY_SHIFT) |
| 441 | ! way 0, word 0 |
| 442 | set 0xA1, %g3 |
| 443 | sllx %g3, 32, %g3 ! %g3 = L2_SELECT_A1 | EVEN |
| 444 | or %g4, %g3, %g4 ! %g4 |= L2_SELECT_A1 |
| 445 | ldx [%g4], %g6 ! read even 32-bit |
| 446 | stx %g6, [%g5] ! store even 32-bit data |
| 447 | add %g5, 8, %g5 ! increment pointer |
| 448 | set (1 << 22), %g3 ! ODDEVEN = 1 |
| 449 | or %g4, %g3, %g4 ! select ODD |
| 450 | ldx [%g4], %g6 ! read odd 32-bit |
| 451 | stx %g6, [%g5] ! store odd 32-bit data |
| 452 | add %g5, 8, %g5 ! increment pointer |
| 453 | ! way 0, word 1 |
| 454 | add %g4, 8, %g4 ! next word |
| 455 | andn %g4, %g3, %g4 ! EVEN |
| 456 | ldx [%g4], %g6 ! read even 32-bit |
| 457 | stx %g6, [%g5] ! store even 32-bit data |
| 458 | add %g5, 8, %g5 ! increment pointer |
| 459 | set (1 << 22), %g3 ! ODDEVEN = 1 |
| 460 | or %g4, %g3, %g4 ! select ODD |
| 461 | ldx [%g4], %g6 ! read odd 32-bit |
| 462 | stx %g6, [%g5] ! store odd 32-bit data |
| 463 | add %g5, 8, %g5 ! increment pointer |
| 464 | ! way 0, word 2 |
| 465 | add %g4, 8, %g4 ! next word |
| 466 | andn %g4, %g3, %g4 ! EVEN |
| 467 | ldx [%g4], %g6 ! read even 32-bit |
| 468 | stx %g6, [%g5] ! store even 32-bit data |
| 469 | add %g5, 8, %g5 ! increment pointer |
| 470 | or %g4, %g3, %g4 ! select ODD |
| 471 | ldx [%g4], %g6 ! read odd 32-bit |
| 472 | stx %g6, [%g5] ! store odd 32-bit data |
| 473 | add %g5, 8, %g5 ! increment pointer |
| 474 | ! way 0, word 3 |
| 475 | add %g4, 8, %g4 ! next word |
| 476 | andn %g4, %g3, %g4 ! EVEN |
| 477 | ldx [%g4], %g6 ! read even 32-bit |
| 478 | stx %g6, [%g5] ! store even 32-bit data |
| 479 | add %g5, 8, %g5 ! increment pointer |
| 480 | or %g4, %g3, %g4 ! select ODD |
| 481 | ldx [%g4], %g6 ! read odd 32-bit |
| 482 | stx %g6, [%g5] ! store odd 32-bit data |
| 483 | add %g5, 8, %g5 ! increment pointer |
| 484 | ! way 0, word 4 |
| 485 | add %g4, 8, %g4 ! next word |
| 486 | andn %g4, %g3, %g4 ! EVEN |
| 487 | ldx [%g4], %g6 ! read even 32-bit |
| 488 | stx %g6, [%g5] ! store even 32-bit data |
| 489 | add %g5, 8, %g5 ! increment pointer |
| 490 | or %g4, %g3, %g4 ! select ODD |
| 491 | ldx [%g4], %g6 ! read odd 32-bit |
| 492 | stx %g6, [%g5] ! store odd 32-bit data |
| 493 | add %g5, 8, %g5 ! increment pointer |
| 494 | ! way 0, word 5 |
| 495 | add %g4, 8, %g4 ! next word |
| 496 | andn %g4, %g3, %g4 ! EVEN |
| 497 | ldx [%g4], %g6 ! read even 32-bit |
| 498 | stx %g6, [%g5] ! store even 32-bit data |
| 499 | add %g5, 8, %g5 ! increment pointer |
| 500 | or %g4, %g3, %g4 ! select ODD |
| 501 | ldx [%g4], %g6 ! read odd 32-bit |
| 502 | stx %g6, [%g5] ! store odd 32-bit data |
| 503 | add %g5, 8, %g5 ! increment pointer |
| 504 | ! way 0, word 6 |
| 505 | add %g4, 8, %g4 ! next word |
| 506 | andn %g4, %g3, %g4 ! EVEN |
| 507 | ldx [%g4], %g6 ! read even 32-bit |
| 508 | stx %g6, [%g5] ! store even 32-bit data |
| 509 | add %g5, 8, %g5 ! increment pointer |
| 510 | or %g4, %g3, %g4 ! select ODD |
| 511 | ldx [%g4], %g6 ! read odd 32-bit |
| 512 | stx %g6, [%g5] ! store odd 32-bit data |
| 513 | add %g5, 8, %g5 ! increment pointer |
| 514 | ! way 0, word 7 |
| 515 | add %g4, 8, %g4 ! next word |
| 516 | andn %g4, %g3, %g4 ! EVEN |
| 517 | ldx [%g4], %g6 ! read even 32-bit |
| 518 | stx %g6, [%g5] ! store even 32-bit data |
| 519 | add %g5, 8, %g5 ! increment pointer |
| 520 | or %g4, %g3, %g4 ! select ODD |
| 521 | ldx [%g4], %g6 ! read odd 32-bit |
| 522 | stx %g6, [%g5] ! store odd 32-bit data |
| 523 | add %g5, 8, %g5 ! increment pointer |
| 524 | ! next way |
| 525 | srlx %g2, L2_WAY_SHIFT, %g2 ! current way |
| 526 | add %g2, 1, %g2 ! next way |
| 527 | cmp %g2, L2_NUM_WAYS |
| 528 | bz 2f ! read tag and loop back if not done |
| 529 | nop |
| 530 | |
| 531 | ! read tag |
| 532 | mov %g7, %g6 ! save original return |
| 533 | ba get_l2_tag_by_way |
| 534 | rd %pc, %g7 |
| 535 | mov %g6, %g7 ! restore original return |
| 536 | stx %g3, [%g5] ! save tag_ECC[next] |
| 537 | add %g5, 8, %g5 ! increment |
| 538 | ba 1b |
| 539 | sllx %g2, L2_WAY_SHIFT, %g2 ! shift to way field |
| 540 | |
| 541 | 2: |
| 542 | ! set %g2 back to original value based on %g5 |
| 543 | sub %g5, 0x618, %g2 ! restore %g2 |
| 544 | HVRET |
| 545 | SET_SIZE(dump_l2_set_tag_data_ecc) |
| 546 | |
| 547 | /* |
| 548 | * check_l2_state(uint64_t pa) |
| 549 | * Checks L2$ line state for the given physical address |
| 550 | * and returns 0 for clean, 1 for dirty, 2 for invalid, 3 = not found |
| 551 | * Arguments: |
| 552 | * %g1 - input - physical address |
| 553 | * %g4 - output - clean, dirty or invalid state |
| 554 | * %g7 - input - return address |
| 555 | */ |
| 556 | ENTRY_NP(check_l2_state) |
| 557 | mov %g7, %g6 |
| 558 | |
| 559 | ! get PA<39:18> from pa |
| 560 | setx L2_PA_TAG_MASK, %g2, %g5 |
| 561 | and %g1, %g5, %g5 ! %g5 has PA<39:18> |
| 562 | srlx %g5, L2_PA_TAG_SHIFT, %g5 |
| 563 | |
| 564 | ! read L2 tag |
| 565 | set 0, %g2 |
| 566 | 2: |
| 567 | ba get_l2_tag_by_way ! returns tag in %g3 |
| 568 | rd %pc, %g7 |
| 569 | setx L2_TAG_MASK, %g7, %g4 |
| 570 | and %g3, %g4, %g3 |
| 571 | srlx %g3, L2_TAG_SHIFT, %g3 ! %g3 has L2 TAG<27:6> |
| 572 | cmp %g3, %g5 ! %g5 has the PA tag |
| 573 | bz 1f |
| 574 | add %g2, 1, %g2 |
| 575 | cmp %g2, 12 ! 12th way? |
| 576 | bnz 2b ! no, do next way |
| 577 | mov %g6, %g7 |
| 578 | ! done, return not found |
| 579 | jmp %g7 + 4 |
| 580 | set L2_LINE_NOT_FOUND, %g4 ! return not found |
| 581 | |
| 582 | ! tag match found |
| 583 | 1: |
| 584 | mov %g2, %g5 ! %g5 = %g2 |
| 585 | sub %g5, 1, %g5 ! %g5 has the way number |
| 586 | ba get_l2_vdbits_for_pa ! returns vdbits in %g2 |
| 587 | rd %pc, %g7 |
| 588 | add %g5, 12, %g5 |
| 589 | set 1, %g3 |
| 590 | sllx %g3, %g5, %g3 ! set valid[way] |
| 591 | btst %g3, %g2 ! is valid? |
| 592 | bz 0f |
| 593 | mov %g6, %g7 |
| 594 | |
| 595 | ! check dirty or clean |
| 596 | srlx %g3, 12, %g3 ! set dirty[way] |
| 597 | btst %g3, %g2 ! is dirty? |
| 598 | bnz 2f ! yes, return dirty |
| 599 | mov %g6, %g7 |
| 600 | ! return clean |
| 601 | jmp %g7 + 4 |
| 602 | set L2_LINE_CLEAN, %g4 ! return clean |
| 603 | |
| 604 | ! return dirty |
| 605 | 2: |
| 606 | jmp %g7 + 4 |
| 607 | set L2_LINE_DIRTY, %g4 ! return dirty |
| 608 | |
| 609 | ! return invalid |
| 610 | 0: |
| 611 | jmp %g7 + 4 |
| 612 | set L2_LINE_INVALID, %g4 ! return invalid |
| 613 | SET_SIZE(check_l2_state) |