ช่วงฟลัช/ทำให้ใช้ไม่ได้ตามที่อยู่เสมือน ARMv8; แคช;

ฉันกำลังใช้ฟังก์ชันการบำรุงรักษาแคชสำหรับ ARMv8 (Cortex-A53) ที่ทำงานในโหมด 32 บิต มีปัญหาเมื่อฉันพยายามล้างขอบเขตหน่วยความจำโดยใช้ที่อยู่เสมือน (VA) DCacheFlushByRange หน้าตาเป็นแบบนี้

// 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 ใช้เพื่อตรวจสอบฟังก์ชัน DMA คัดลอกบัฟเฟอร์หนึ่งไปยังอีกบัฟเฟอร์หนึ่ง บัฟเฟอร์ต้นทางถูกล้างก่อน DMA บัฟเฟอร์ปลายทางจะใช้ไม่ได้หลังจาก DMA เสร็จสิ้น บัฟเฟอร์มีการจัดชิดกัน 64 ไบต์ ทดสอบ

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);

ในดัมพ์ฉันเห็นว่า buf1 ยังคงมีเพียงศูนย์เท่านั้น เมื่อปิดแคช ผลลัพธ์จะถูกต้อง ดังนั้น DMA เองจึงทำงานได้อย่างถูกต้อง

อีกประเด็นคือเมื่อ D-cache ทั้งหมดถูกล้าง/ทำให้ใช้ไม่ได้โดยผลลัพธ์ชุด/วิธีถูกต้อง

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

ในไม่ช้า ล้าง/ทำให้ใช้ไม่ได้ตามชุด/วิธีทำงานอย่างถูกต้อง เช่นเดียวกับการกระพริบ/ทำให้ใช้ไม่ได้โดยใช้ VA ไม่ได้ อะไรอาจเป็นปัญหา?

PS: kBufSize=4096; ขนาดบัฟเฟอร์ทั้งหมดคือ 4096 * sizeof(uint32_t) == 16KB


person user3124812    schedule 07.02.2017    source แหล่งที่มา
comment
คุณควรล้างแคช L1 ทั้งหมดหากช่วง/บัฟเฟอร์มีขนาดใหญ่ จากนั้นหยุดชั่วคราวเพื่อให้แน่ใจว่าแคชเสร็จสมบูรณ์ก่อนที่จะล้างแคช L2 นอกจากนี้ยังมีบัฟเฟอร์การเขียน (หรือสิ่งที่คล้ายกัน) ซึ่งไม่ได้เป็นส่วนหนึ่งของแคช คุณไม่ได้ระบุขนาดหรือว่า 'buf1' เป็นศูนย์ทั้งหมดหรือบางส่วน ชุดมักจะอยู่ติดต่อกัน   -  person artless noise    schedule 07.02.2017
comment
ขนาดบัฟเฟอร์คือ 16KB ฉันลองใช้บัฟเฟอร์ 64B แล้ว ผลลัพธ์ก็เหมือนเดิม ล้างทั้ง L1 & Flush L2 ภูมิภาคโดย VA ไม่ทำงาน บัฟเฟอร์ปลายทางทั้งหมดเป็นศูนย์ในทุกกรณี   -  person user3124812    schedule 08.02.2017
comment
ขออภัย ฉันไม่คุ้นเคยกับ A53 แต่ใน Cortex-A7 มีอินเทอร์เฟซการลงทะเบียนหน่วยความจำที่แมปกับ L2 รีจิสเตอร์ CP15 จะไม่ล้างแคช L2 (แม้ว่าคู่มืออาจดูเหมือนระบุสิ่งนี้ก็ตาม) คุณมีคู่มือ ARM นอกเหนือจาก Cortex-A53 TRM หรือไม่ โดยปกติแล้ว SCU และตัวจับเวลาบนชิป ฯลฯ จะมีไฟล์รีจิสเตอร์แยกกันอย่างน้อยกับชิป ARM รุ่นก่อนหน้า Linux ใช้กลไกที่แตกต่างกันใน cache.S   -  person artless noise    schedule 08.02.2017
comment
@artlessnoise L2 Cache Controller เป็นชิปที่แยกจากกันใน A7 (คล้ายกับอุปกรณ์ต่อพ่วงอื่นๆ ถึงแม้จะรวมเข้าด้วยกันทั้งหมดก็ตาม) A53 ได้รวมแคช L2 ไว้แล้ว   -  person user3124812    schedule 09.02.2017


คำตอบ (1)


ไม่มีปัญหากับฟังก์ชั่นของตัวเองมากกว่าคุณสมบัติการใช้งานแคช Cortex-A53

จาก Cortex-A53 TRM

การดำเนินการ DCIMVAC ในคำสั่ง AArch32 และ DC IVAC ใน AArch64 ทำให้ที่อยู่เป้าหมายไม่ถูกต้อง หากข้อมูลสกปรกภายในคลัสเตอร์ ล้างข้อมูลจะดำเนินการก่อนที่จะไม่ถูกต้อง


ดังนั้นจึงไม่มีสิ่งที่ใช้ไม่ได้จริง มีสะอาดและเป็นโมฆะ

ลำดับปกติ (อย่างน้อยสำหรับฉัน) คือ

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

แต่เนื่องจาก invalidate() ทำการฟลัช ข้อมูลเก่าจากแคช (ขอบเขต dst) จึงถูกเขียนทับข้อมูลในหน่วยความจำหลังจากการถ่ายโอน DMA


วิธีแก้ไข/วิธีแก้ไขคือ

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


* ข้อมูลจากขอบเขตหน่วยความจำ 'dst' สามารถดึงเข้าสู่แคชล่วงหน้าได้ หากสิ่งนั้นเกิดขึ้นก่อนที่ DMA จะใส่ข้อมูลลงในหน่วยความจำ ข้อมูลเก่าจากแคชจะถูกนำมาใช้ การทำให้ใช้งานไม่ได้ครั้งที่สองเป็นเรื่องปกติ เนื่องจากข้อมูลไม่ได้ถูกทำเครื่องหมายว่า 'สกปรก' จึงจะถูกดำเนินการเป็น 'ใช้งานไม่ได้อย่างแท้จริง' ในกรณีนี้ไม่มีการล้าง/ล้าง

person user3124812    schedule 16.02.2017