NDIS Точечная и сборная DMA
Внимание!
Для процессоров Arm и Arm64 мы настоятельно рекомендуем, чтобы записи драйверов NDIS использовали WDF DMA или WDM DMA вместо NDIS Scatter/Gather DMA.
Дополнительные сведения о WDF DMA см. в разделе Обработка операций DMA в драйверах KMDF.
Дополнительные сведения о WDM DMA см. в дочерних разделах, связанных с DMA статьи Управление входными и выходными данными для драйверов.
Для передачи данных между сетевой картой и системной памятью драйверы мини-портов NDIS могут использовать метод Точечная и сборная DMA (SGDMA). Для успешной передачи DMA требуется, чтобы физический адрес данных был в диапазоне адресов, который поддерживает сетевая карта. HAL предоставляет драйверу механизм для получения списка физических адресов для цепочки MDL и при необходимости выполняет двойную буферизацию данных в физический диапазон адресов.
В версиях NDIS до NDIS 6.0 поддержка SGDMA в драйверах мини-портов и NDIS в некоторых отношениях ограничена и, в частности, не работает хорошо в сценарии отправки с несколькими пакетами. Поддержка NDIS 6.0 SGDMA позволяет преодолеть эти ограничения, предоставляя простой интерфейс для драйверов мини-портов.
История NDIS SGDMA
В версиях NDIS до NDIS 6.0 NDIS получает список точечной сбора (SG) для каждого пакета перед отправкой пакета драйверу мини-порта. NDIS также обрабатывает случай, когда исходная попытка получить список SG завершается сбоем из-за чрезмерной фрагментации. В этом случае NDIS выполняет двойную буферизацию пакета в непрерывный буфер и пытается повторить попытку. HAL также может использовать двойную буферизацию данных в физический адрес, поддерживаемый сетевой картой, если, например, физический адрес данных превышает 32-разрядный максимум, а сетевой адаптер не поддерживает 64-разрядную DMA.
Чтобы избежать взаимоблокировки, NDIS получает список SG для пакета и отправляет по одному пакету за раз. Если NDIS попытается сопоставить все пакеты перед их отправкой драйверу мини-порта, система может исчерпнуть ресурсы. В этом случае NDIS будет ожидать, пока регистры карт станут доступными, в то время как некоторые регистры карт будут заблокированы для пакетов, которые не были отправлены. Заблокированные пакеты нельзя использовать повторно.
Этот подход к поддержке SGDMA имеет следующие ограничения:
Так как пакет сопоставляется до того, как он попадает в драйвер мини-порта, драйвер не может оптимизировать для небольших пакетов или пакетов, которые слишком фрагментированы. Драйвер мини-порта не может удвоить буфер пакета на известный физический адрес.
Нет никакой гарантии, что физический массив адресов, переданный NDIS драйверу мини-порта, сопоставляется с виртуальным адресом исходных данных. Таким образом, если драйвер изменяет данные по виртуальному адресу в цепочке MDL перед их отправкой, изменения, внесенные в данные, не отражаются в данных в физических адресах. В этом случае сетевой адаптер отправляет неизмененные данные.
NDIS ограничивается отправкой одного пакета за раз, чтобы избежать взаимоблокировки из-за проблем с ресурсами. Это не так эффективно, как отправка нескольких пакетов.
Поскольку NDIS не может определить возможности передачи драйверов мини-портов, он не может предварительно выделить хранилище для буфера списка SG. Поэтому NDIS должна выделить необходимое хранилище во время выполнения. Это не так эффективно, как предварительное выделение хранилища.
Функции HAL, которые выделяют список SG, должны вызываться по адресу IRQL = DISPATCH_LEVEL. NDIS не содержит текущих сведений IRQL, поэтому необходимо задать для irQL значение DISPATCH_LEVEL даже если он уже находится на DISPATCH_LEVEL. Это не эффективно, если IRQL уже находится на DISPATCH_LEVEL.
Преимущества поддержки NDIS SGDMA
В интерфейсе NDIS 6.0 и более поздних версий SGDMA NDIS не сопоставляет буфер данных перед отправкой в драйвер мини-порта. Вместо этого NDIS предоставляет драйверу интерфейс для сопоставления сетевых данных.
Такой подход дает следующие преимущества:
Так как NDIS предоставляет интерфейс HAL для сопоставления сетевых данных, NDIS защищает драйверы минипорта от сложности и деталей процесса сопоставления.
Драйверы мини-портов имеют доступ к данным перед их сопоставлением. Поэтому любые изменения, внесенные в исходные данные, отражаются в данных, представленных списком SG, даже если NDIS или HAL дважды буферизируют данные.
Драйверы минипорта могут оптимизировать передачу небольших или сильно фрагментированных пакетов, копируя их в предварительно размещенный буфер с известным физическим адресом. Такой подход позволяет избежать необязательного сопоставления и, следовательно, повысить производительность системы.
NDIS может безопасно отправлять несколько буферов в драйвер мини-порта. Это приводит к уменьшению числа вызовов драйверов мини-портов и, следовательно, повышает производительность системы.
Драйверы мини-портов могут предварительно выделить память для списка SG в составе блоков дескриптора передачи. Поэтому драйверы NDIS или мини-порта не обязаны выделять память для списков SG во время выполнения.
Так как драйверы мини-портов могут работать в среде IRQL = DISPATCH_LEVEL, драйверы минипорта могут избежать ненужных вызовов для вызова IRQL для DISPATCH_LEVEL. Например, так как отправка выполняется в контексте прерывания DPC, драйверы мини-портов могут освободить список SG без вызова IRQL.
Регистрация и отмена регистрации каналов DMA
Драйвер мини-порта NDIS вызывает функцию NdisMRegisterScatterGatherDma из функции MiniportInitializeEx для регистрации канала DMA с помощью NDIS.
Драйвер мини-порта передает описание DMA в NdisMRegisterScatterGatherDma в параметре DmaDescription . NdisMRegisterScatterGatherDma возвращает размер буфера, который должен быть достаточно большим, чтобы вместить точечный/собирательный список. Драйверы мини-портов должны использовать этот размер для предварительного выделения хранилища для точечных и сборных списков.
Драйвер мини-порта также передает NdisMRegisterScatterGatherDma точки входа для функций MiniportXxx, которые NDIS вызывает для обработки списка точечной и сборной. NDIS вызывает функцию MiniportProcessSGList драйвера минипорта после того, как HAL настроит список точечной и сборной для буфера. NdisMRegisterScatterGatherDma предоставляет дескриптор в параметре pNdisMiniportDmaHandle , который драйвер мини-порта должен использовать в последующих вызовах функций DMA NDIS scatter/gather.
Драйвер мини-порта NDIS вызывает функцию NdisMDeregisterScatterGatherDma из своей функции MiniportHaltEx , чтобы освободить точечные и собирательные ресурсы DMA.
Выделение и освобождение точечных и собирающихся списков
Драйвер мини-порта NDIS вызывает функцию NdisMAllocateNetBufferSGList в функции MiniportSendNetBufferLists . Драйвер мини-порта вызывает NdisMAllocateNetBufferSGList один раз для каждой NET_BUFFER структуры, которую он должен сопоставить. Когда ресурсы станут доступными и HAL подготовит список SG, NDIS вызывает функцию MiniportProcessSGList драйвера. NDIS может вызывать MiniportProcessSGList до или после вызова NdisMAllocateNetBufferSGList .
Для повышения производительности системы список точечной и сборной создается на основе сетевых данных, начиная с начала MDL, указанного в элементе CurrentMdl связанной структуры NET_BUFFER_DATA . Начало сетевых данных в списке SG смещается от начала списка SG на значение, указанное в элементе CurrentMdlOffset связанной структуры NET_BUFFER_DATA .
При обработке DPC для прерывания отправки и завершения и после того, как драйверу мини-порта больше не нужен список SG, драйвер мини-порта должен вызвать функцию NdisMFreeNetBufferSGList , чтобы освободить список SG.
Примечание Не вызывайте NdisMFreeNetBufferSGList , пока драйвер или оборудование по-прежнему обращается к памяти, описанной структурой NET_BUFFER, связанной со списком точечной и сборной.
Перед доступом к полученным данным драйверы мини-портов должны вызвать NdisMFreeNetBufferSGList для очистки кэша памяти.