Подтвердить что ты не робот

Управление когерентностью кэширования DMA

Мой вопрос заключается в следующем: как я могу определить, когда безопасно отключать отслеживание кэша, когда я правильно использую [pci_]dma_sync_single_for_{cpu,device} в своем драйвере устройства?

Я работаю над драйвером устройства для устройства, которое напрямую записывается в ОЗУ через PCI Express (DMA), и я обеспокоен управлением связностью кеша. Есть бит управления, который я могу установить при запуске DMA, чтобы включить или отключить отслеживание кэша во время DMA, явно для производительности. Я бы хотел, чтобы отключить кэширование, если это вообще возможно.

В подпрограмме прерывания я вызываю pci_dma_sync_single_for_cpu() и ..._for_device(), если это необходимо, при переключении буферов DMA, но в 32-разрядной версии Linux 2.6.18 (RHEL 5) получается, что эти команды являются макросами, которые не имеют ничего общего..., который объясняет, почему мое устройство возвращает мусор, когда отслеживание кэша отключено на этом ядре!

Я прошел по истории источников ядра, и кажется, что до 2.6.25 только 64-разрядные x86 имели перехваты для синхронизации DMA. Из 2.6.26, как представляется, существует общий унифицированный механизм косвенности для синхронизации DMA (в настоящее время в include/asm-generic/dma-mapping-common.h) через поля sync_single_for_{cpu,device} из dma_map_ops, но до сих пор мне не удалось найти никаких определений этих операций.

4b9b3361

Ответ 1

Я действительно удивлен, что никто не ответил на это, поэтому мы переходим к конкретному ответу, отличному от Linux (я имею более полное знание самого ядра Linux, чтобы быть более конкретным)...

Cache snooping просто сообщает контроллеру DMA отправлять запросы о недействительности кэша ко всем ЦП для DMAed памяти. Это, очевидно, добавляет нагрузку на когерентную шину кэша, и она особенно сильно масштабируется с дополнительными процессорами, так как не все процессоры будут иметь одно соединение хопа с контроллером DMA, выдающим snoop. Поэтому простой ответ на "когда безопасно отключить отслеживание кеша" - это когда память, которая находится в DMAed, либо не существует в любом кэше ЦП, либо ее строки кэша помечены как недействительные. Другими словами, любая попытка чтения из области DMAed всегда приведет к чтению из основной памяти.

Итак, как вы гарантируете, что чтения из области DMAed всегда будут в основной памяти?

Еще за день до того, как у нас появились привлекательные функции, такие как отслеживание кэша DMA, мы использовали для записи DMA-памяти, загрузив ее через ряд разбитых этапов следующим образом:

Этап 1: добавьте "грязную" область памяти DMA в список "Dirty memory", который должен быть очищен ".

Этап 2: В следующий раз, когда устройство прерывает свежие данные DMA, выведите асинхронный кеш центрального процессора в сегменты DMA в списке "грязный и подлежащий очистке" для всех процессоров, которые могут обращаться к этим блокам (часто каждый CPU запускает собственные списки, состоящие из блоков локальной памяти). Переместите указанные сегменты в "чистый" список.

Этап 3: следующее прерывание DMA (которое, конечно же, вы не увидите, до того, как завершится предыдущее кэширование недействительности), возьмите новую область из "чистого" списка и сообщите устройству, что его следующий DMA должен войти в что. Переработайте любые грязные блоки.

Этап 4: Повторите.

Чем больше работа, тем больше преимуществ. Во-первых, вы можете привязать обработку DMA к одному CPU (обычно к первому CPU0) или к одному SMP node, что означает, что только один CPU/node должен беспокоиться о недействительности кэша. Во-вторых, вы даете подсистеме памяти гораздо больше возможностей скрывать задержки памяти для вас, распределяя операции со временем и расширяя нагрузку на шину когерентности кэша. Ключом к производительности, как правило, является попытка сделать любой DMA на процессоре как можно ближе к соответствующему контроллеру DMA, насколько это возможно, и в память как можно ближе к этому CPU.

Если вы всегда передаете новое DMAed в память в пространство пользователя и/или другие процессоры, просто вводите свежеприобретенную память в передней части асинхронного кэша, недействительным конвейером. Некоторые операционные системы (не уверенные в Linux) имеют оптимизированную подпрограмму для предопределенной нулевой памяти, поэтому ОС в основном занумевает память в фоновом режиме и поддерживает быстрый кеш-кеш - она ​​будет платить вам за сохранение новых запросов на память ниже этой кешированной суммы, поскольку обнуление памяти очень медленный. Я не знаю о какой-либо платформе, созданной за последние десять лет, которая использует аппаратную перезагрузку памяти, поэтому вы должны предположить, что вся свежая память может содержать допустимые строки кеша, которые требуют недействительности.

Я ценю, что это отвечает только на половину вашего вопроса, но это лучше, чем ничего. Удачи!

Найл

Ответ 2

Возможно, немного просрочено, но:

Если вы отключите отслеживание кеша, аппаратное обеспечение больше не будет заботиться о когерентности кеша. Следовательно, ядро ​​должно сделать это самостоятельно. За последние несколько дней я потратил некоторое время на просмотр вариантов X86 [pci_] dma_sync_single_for_ {cpu, device}. Я не обнаружил никаких признаков того, что они прилагают все усилия для поддержания согласованности. Это похоже на тот факт, что отслеживание кэша по умолчанию включено в спецификации PCI (e).

Следовательно, если вы отключите отслеживание кэша, вам придется поддерживать согласованность самостоятельно, в своем драйвере. Возможно, вызвав clflush_cache_range() (X86) или аналогичный?

работ: