Поделиться через


Очистка кэшированных данных во время операций DMA

На некоторых платформах процессор и системный контроллер DMA (или адаптеры DMA master шины) демонстрируют аномалии когерентности кэша. Приведенные ниже рекомендации позволяют драйверам, используюющим интерфейс операций DMA версии 1 или 2 (см . DMA_OPERATIONS), поддерживать согласованное состояние кэша во всех поддерживаемых архитектурах процессора, включая архитектуры, которые не содержат оборудования для автоматического принудительного обеспечения когерентности кэша.

Примечание Рекомендации в этом разделе применяются только к драйверам, которые используют версии 1 и 2 интерфейса операций DMA. Драйверы, использующие этот интерфейс версии 3, должны следовать другим рекомендациям. Дополнительные сведения см. в разделе Версия 3 интерфейса операций DMA.

Для поддержания целостности данных во время операций DMA драйверы низкого уровня должны следовать этим рекомендациям.

  1. Вызовите Метод KeFlushIoBuffers перед началом операции передачи, чтобы обеспечить согласованность между данными, которые могут быть кэшированы в процессоре, и данными в памяти.

    Если драйвер вызывает AllocateCommonBuffer с параметром CacheEnabled, для параметра CacheEnabled задано значение TRUE, драйвер должен вызвать KeFlushIoBuffers перед началом операции передачи в буфер и из буфера.

  2. Вызовите FlushAdapterBuffers в конце каждой операции передачи устройства, чтобы убедиться, что все оставшиеся байты в буферах системного контроллера DMA записаны в память или на подчиненное устройство.

    Или вызовите FlushAdapterBuffers в конце каждой операции передачи для заданного IRP, чтобы убедиться, что все данные были считаны в системную память или записаны на устройство DMA master шины.

На следующем рисунке показано, почему важно очистить кэш процессора перед операцией чтения или записи с помощью DMA, если процессор узла и контроллер DMA не поддерживают параллелизм кэша автоматически.

схема, иллюстрирующая операции чтения и записи с помощью dma.

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

KeFlushIoBuffers ничего не делает, если процессор и контроллер DMA можно использовать для поддержания когерентности кэша, поэтому вызовы этой процедуры поддержки практически не имеют накладных расходов на такой платформе.

Как также показано на предыдущем рисунке, контроллеры DMA, представленные объектами адаптера, могут иметь внутренние буферы. Такой контроллер DMA может передавать кэшированные данные блоками фиксированного размера, обычно по восемь или более байтов за раз. Кроме того, эти контроллеры DMA могут ждать, пока их внутренние буферы не будут заполнены перед каждой операцией передачи.

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

Драйвер устройства DMA master шины также должен вызывать FlushAdapterBuffers в конце каждой операции передачи для IRP, чтобы убедиться, что все данные были переданы в системную память или на устройство.

FlushAdapterBuffers возвращает логическое значение, указывающее, успешно ли выполнена запрошенная операция очистки. Драйвер может использовать это значение, чтобы определить, как задать блок состояния ввода-вывода при завершении IRP для операции чтения или записи DMA.