in mm/page.c [424:612]
void build_copy_page(void)
{
int off;
u32 *buf = &__copy_page_start;
struct uasm_label *l = labels;
struct uasm_reloc *r = relocs;
int i;
static atomic_t run_once = ATOMIC_INIT(0);
if (atomic_xchg(&run_once, 1)) {
return;
}
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
set_prefetch_parameters();
/*
* This algorithm makes the following assumptions:
* - All prefetch biases are multiples of 8 words.
* - The prefetch biases are less than one page.
* - The store prefetch bias isn't greater than the load
* prefetch bias.
*/
BUG_ON(pref_bias_copy_load % (8 * copy_word_size));
BUG_ON(pref_bias_copy_store % (8 * copy_word_size));
BUG_ON(PAGE_SIZE < pref_bias_copy_load);
BUG_ON(pref_bias_copy_store > pref_bias_copy_load);
off = PAGE_SIZE - pref_bias_copy_load;
if (off > 0xffff || !pref_bias_copy_load)
pg_addiu(&buf, A2, A0, off);
else
uasm_i_ori(&buf, A2, A0, off);
if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x())
uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000));
off = cache_line_size ? min(8, pref_bias_copy_load / cache_line_size) *
cache_line_size : 0;
while (off) {
build_copy_load_pref(&buf, -off);
off -= cache_line_size;
}
off = cache_line_size ? min(8, pref_bias_copy_store / cache_line_size) *
cache_line_size : 0;
while (off) {
build_copy_store_pref(&buf, -off);
off -= cache_line_size;
}
uasm_l_copy_pref_both(&l, buf);
do {
build_copy_load_pref(&buf, off);
build_copy_load(&buf, T0, off);
build_copy_load_pref(&buf, off + copy_word_size);
build_copy_load(&buf, T1, off + copy_word_size);
build_copy_load_pref(&buf, off + 2 * copy_word_size);
build_copy_load(&buf, T2, off + 2 * copy_word_size);
build_copy_load_pref(&buf, off + 3 * copy_word_size);
build_copy_load(&buf, T3, off + 3 * copy_word_size);
build_copy_store_pref(&buf, off);
build_copy_store(&buf, T0, off);
build_copy_store_pref(&buf, off + copy_word_size);
build_copy_store(&buf, T1, off + copy_word_size);
build_copy_store_pref(&buf, off + 2 * copy_word_size);
build_copy_store(&buf, T2, off + 2 * copy_word_size);
build_copy_store_pref(&buf, off + 3 * copy_word_size);
build_copy_store(&buf, T3, off + 3 * copy_word_size);
off += 4 * copy_word_size;
} while (off < half_copy_loop_size);
pg_addiu(&buf, A1, A1, 2 * off);
pg_addiu(&buf, A0, A0, 2 * off);
off = -off;
do {
build_copy_load_pref(&buf, off);
build_copy_load(&buf, T0, off);
build_copy_load_pref(&buf, off + copy_word_size);
build_copy_load(&buf, T1, off + copy_word_size);
build_copy_load_pref(&buf, off + 2 * copy_word_size);
build_copy_load(&buf, T2, off + 2 * copy_word_size);
build_copy_load_pref(&buf, off + 3 * copy_word_size);
build_copy_load(&buf, T3, off + 3 * copy_word_size);
build_copy_store_pref(&buf, off);
build_copy_store(&buf, T0, off);
build_copy_store_pref(&buf, off + copy_word_size);
build_copy_store(&buf, T1, off + copy_word_size);
build_copy_store_pref(&buf, off + 2 * copy_word_size);
build_copy_store(&buf, T2, off + 2 * copy_word_size);
build_copy_store_pref(&buf, off + 3 * copy_word_size);
if (off == -(4 * copy_word_size))
uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both);
build_copy_store(&buf, T3, off + 3 * copy_word_size);
off += 4 * copy_word_size;
} while (off < 0);
if (pref_bias_copy_load - pref_bias_copy_store) {
pg_addiu(&buf, A2, A0,
pref_bias_copy_load - pref_bias_copy_store);
uasm_l_copy_pref_store(&l, buf);
off = 0;
do {
build_copy_load(&buf, T0, off);
build_copy_load(&buf, T1, off + copy_word_size);
build_copy_load(&buf, T2, off + 2 * copy_word_size);
build_copy_load(&buf, T3, off + 3 * copy_word_size);
build_copy_store_pref(&buf, off);
build_copy_store(&buf, T0, off);
build_copy_store_pref(&buf, off + copy_word_size);
build_copy_store(&buf, T1, off + copy_word_size);
build_copy_store_pref(&buf, off + 2 * copy_word_size);
build_copy_store(&buf, T2, off + 2 * copy_word_size);
build_copy_store_pref(&buf, off + 3 * copy_word_size);
build_copy_store(&buf, T3, off + 3 * copy_word_size);
off += 4 * copy_word_size;
} while (off < half_copy_loop_size);
pg_addiu(&buf, A1, A1, 2 * off);
pg_addiu(&buf, A0, A0, 2 * off);
off = -off;
do {
build_copy_load(&buf, T0, off);
build_copy_load(&buf, T1, off + copy_word_size);
build_copy_load(&buf, T2, off + 2 * copy_word_size);
build_copy_load(&buf, T3, off + 3 * copy_word_size);
build_copy_store_pref(&buf, off);
build_copy_store(&buf, T0, off);
build_copy_store_pref(&buf, off + copy_word_size);
build_copy_store(&buf, T1, off + copy_word_size);
build_copy_store_pref(&buf, off + 2 * copy_word_size);
build_copy_store(&buf, T2, off + 2 * copy_word_size);
build_copy_store_pref(&buf, off + 3 * copy_word_size);
if (off == -(4 * copy_word_size))
uasm_il_bne(&buf, &r, A2, A0,
label_copy_pref_store);
build_copy_store(&buf, T3, off + 3 * copy_word_size);
off += 4 * copy_word_size;
} while (off < 0);
}
if (pref_bias_copy_store) {
pg_addiu(&buf, A2, A0, pref_bias_copy_store);
uasm_l_copy_nopref(&l, buf);
off = 0;
do {
build_copy_load(&buf, T0, off);
build_copy_load(&buf, T1, off + copy_word_size);
build_copy_load(&buf, T2, off + 2 * copy_word_size);
build_copy_load(&buf, T3, off + 3 * copy_word_size);
build_copy_store(&buf, T0, off);
build_copy_store(&buf, T1, off + copy_word_size);
build_copy_store(&buf, T2, off + 2 * copy_word_size);
build_copy_store(&buf, T3, off + 3 * copy_word_size);
off += 4 * copy_word_size;
} while (off < half_copy_loop_size);
pg_addiu(&buf, A1, A1, 2 * off);
pg_addiu(&buf, A0, A0, 2 * off);
off = -off;
do {
build_copy_load(&buf, T0, off);
build_copy_load(&buf, T1, off + copy_word_size);
build_copy_load(&buf, T2, off + 2 * copy_word_size);
build_copy_load(&buf, T3, off + 3 * copy_word_size);
build_copy_store(&buf, T0, off);
build_copy_store(&buf, T1, off + copy_word_size);
build_copy_store(&buf, T2, off + 2 * copy_word_size);
if (off == -(4 * copy_word_size))
uasm_il_bne(&buf, &r, A2, A0,
label_copy_nopref);
build_copy_store(&buf, T3, off + 3 * copy_word_size);
off += 4 * copy_word_size;
} while (off < 0);
}
uasm_i_jr(&buf, RA);
uasm_i_nop(&buf);
BUG_ON(buf > &__copy_page_end);
uasm_resolve_relocs(relocs, labels);
pr_debug("Synthesized copy page handler (%u instructions).\n",
(u32)(buf - &__copy_page_start));
pr_debug("\t.set push\n");
pr_debug("\t.set noreorder\n");
for (i = 0; i < (buf - &__copy_page_start); i++)
pr_debug("\t.word 0x%08x\n", (&__copy_page_start)[i]);
pr_debug("\t.set pop\n");
}