Flush/Batalkan rentang berdasarkan alamat virtual; ARMv8; Cache;

Saya menerapkan fungsi pemeliharaan cache untuk ARMv8 (Cortex-A53) yang berjalan dalam mode 32 bit. Ada masalah saat saya mencoba membersihkan wilayah memori dengan menggunakan alamat virtual (VA). DCacheFlushByRange terlihat seperti ini

// some init.
// kDCacheL1 = 0; kDCacheL2 = 2;
while (alignedVirtAddr < endAddr)
{
    // Flushing L1
    asm volatile("mcr   p15, 2, %0,  c0,  c0,  0" : : "r"(kDCacheL1) :);        // select cache
    isb();
    asm volatile("mcr   p15, 0, %0,  c7, c14,  1" : : "r"(alignedVirtAddr) :);  // clean & invalidate
    dsb();

    // Flushing L2
    asm volatile("mcr   p15, 2, %0,  c0,  c0,  0" : : "r"(kDCacheL2) :);        // select cache
    isb();
    asm volatile("mcr   p15, 0, %0,  c7, c14,  1" : : "r"(alignedVirtAddr) :);  // clean & invalidate
    dsb();

    alignedVirtAddr += lineSize;
}

DMA digunakan untuk memvalidasi fungsi. DMA menyalin satu buffer ke buffer lainnya. Buffer sumber dihapus sebelum DMA, buffer tujuan tidak valid setelah DMA selesai. Buffer diselaraskan dengan 64 byte. Tes

for (uint32_t i = 0; i < kBufSize; i++)
    buf1[i] = 0;
for (uint32_t i = 0; i < kBufSize; i++)
    buf0[i] = kRefValue;

DCacheFlushByRange(buf0, sizeof(buf0));

// run DMA
while (1) // wait DMA completion;

DCacheInvalidateByRange(buf1, sizeof(buf1));
compare(buf0, buf1);

Di dump saya dapat melihat bahwa buf1 masih hanya berisi nol. Ketika cache dimatikan, hasilnya benar sehingga DMA sendiri berfungsi dengan benar.

Poin lainnya adalah ketika seluruh D-cache di-flush/dibatalkan karena hasil set/caranya benar.

// loops th/ way & set for L1 & L2
asm volatile("mcr   p15, 0, %0,  c7, c14,  2" : : "r"(setway) :)

Segera siram/batalkan dengan set/cara bekerja dengan benar. Begitu pula dengan mem-flash/membatalkan menggunakan VA tidak. Apa yang mungkin menjadi masalah?

PS: kBufSize=4096;, total ukuran buffer 4096 * sizeof(uint32_t) == 16KB


person user3124812    schedule 07.02.2017    source sumber
comment
Anda mungkin harus membersihkan seluruh cache L1 jika rentang/buffernya besar dan kemudian berhenti sebentar untuk memastikannya selesai sebelum membersihkan cache L2. Juga, ada buffer tulis (atau sejenisnya) yang bukan merupakan bagian dari cache. Anda tidak memberikan ukuran atau apakah 'buf1' sepenuhnya nol atau sebagian. Kumpulan biasanya merupakan alamat yang berurutan.   -  person artless noise    schedule 07.02.2017
comment
Ukuran buffernya adalah 16KB. Saya juga mencoba buffer 64B, hasilnya sama. Flush seluruh wilayah L1 & Flush L2 oleh VA tidak berfungsi. Seluruh buffer tujuan adalah nol dalam semua kasus.   -  person user3124812    schedule 08.02.2017
comment
Maaf, saya tidak familiar dengan A53, namun pada Cortex-A7, ada antarmuka register yang dipetakan memori ke L2. Register CP15 tidak akan membersihkan cache L2 (meskipun manual sepertinya menunjukkan hal ini). Apakah Anda memiliki manual ARM selain Cortex-A53 TRM? Biasanya SCU dan pengatur waktu on-chip, dll memiliki file register terpisah setidaknya dengan chip ARM sebelumnya. Linux menggunakan mekanisme berbeda di cache.S.   -  person artless noise    schedule 08.02.2017
comment
@artlessnoise L2 Cache Controller adalah chip terpisah di A7 (mirip dengan periferal lain, bahkan semuanya dikemas bersama). A53 memiliki cache L2 terintegrasi.   -  person user3124812    schedule 09.02.2017


Jawaban (1)


Tidak ada masalah dengan fungsi itu sendiri daripada fitur implementasi cache Cortex-A53.

Dari Korteks-A53 TRM

Operasi DCIMVAC di AArch32 dan instruksi DC IVAC di AArch64 melakukan pembatalan alamat target. Jika data dalam cluster kotor maka pembersihan dilakukan sebelum validasi.


Jadi sebenarnya tidak ada yang tidak valid, yang ada adalah bersih dan tidak valid

Urutan normal (setidaknya bagi saya) adalah

flush(src);
dma(); // copy src -> dst
invalidate(dst);

Namun karena invalidate() melakukan flush, data lama dari cache (wilayah pertama) ditulis di atas data dalam memori setelah transfer DMA.


Solusi/solusi adalah

flush(src);
invalidate(dst);
dma(); // copy src -> dst
invalidate(dst); // again, that's right*.


* Data dari wilayah memori 'dst' dapat diambil ke dalam cache terlebih dahulu. Jika itu terjadi sebelum DMA memasukkan data ke dalam memori, data lama dari cache akan digunakan. Pembatalan kedua boleh saja, karena data tidak ditandai sebagai 'kotor', maka akan dilakukan sebagai 'tidak valid murni'. Tidak ada pembersihan/penyiram dalam kasus ini.

person user3124812    schedule 16.02.2017