NDIS точечная и сборная DMA
Осторожность
Для процессоров Arm и Arm64 настоятельно рекомендуется, чтобы средства записи драйверов NDIS использовали WDF DMA или WDM DMA вместо точечной и сборной DMA NDIS.
Дополнительные сведения о WDF DMA смотрите в разделе выполнение операций DMA в драйверах KMDF.
Дополнительные сведения о WDM DMA см. в дочерних разделах, связанных с DMA, в разделе Управление входными и выходными данными для драйверов.
Минипорт-драйверы NDIS могут использовать метод рассеяния/сбора 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 также может выполнять двойную буферизацию данных в физический адрес, поддерживаемый сетевым адаптером (NIC), если, например, физический адрес данных превышает 32-разрядный максимум, а сетевой адаптер не поддерживает 64-разрядную DMA.
Чтобы избежать взаимоблокировки, NDIS получает список SG для пакета и отправляет один пакет за раз. Если NDIS пытается обработать все пакеты перед отправкой в miniport драйвер, система может исчерпать ресурсы. В этом случае NDIS будет ожидать, чтобы регистры карт стали доступными, пока некоторые регистры карт заблокированы для пакетов, которые не были отправлены. Не удается повторно использовать заблокированные пакеты.
Этот подход к поддержке SGDMA имеет следующие ограничения:
Поскольку пакет сопоставляется прежде, чем поступает на минипорт-драйвер, драйвер не может оптимизироваться для небольших пакетов или пакетов, которые слишком фрагментированы. Минипорт-драйвер не может выполнить двойное буферирование пакета в известный физический адрес.
Не гарантируется, что массив физических адресов, передаваемый NDIS драйверу мини-порта, сопоставляется с виртуальным адресом исходных данных. Таким образом, если драйвер изменяет данные на виртуальном адресе в цепочке MDL перед отправкой, изменения, внесенные в данные, не отражаются в данных в физических адресах. В этом случае сетевой адаптер отправляет неизмененные данные.
NDIS ограничивается отправкой одного пакета за раз, чтобы избежать взаимоблокировки из-за проблем с ресурсами. Это не так эффективно, как отправка нескольких пакетов.
Так как NDIS не может определить возможности передачи минипорт-драйверов, он не может предварительно зарезервировать память для буфера списка SG. Поэтому NDIS должен выделить необходимую память во время выполнения. Это не так эффективно, как предварительное выделение памяти.
Функции HAL, которые выделяют список SG, должны вызываться на уровне IRQL = DISPATCH_LEVEL. NDIS не знает текущего уровня IRQL, поэтому должен задать уровень приоритета IRQL как DISPATCH_LEVEL, даже если он уже его имеет. Это неэффективно, если IRQL уже находится на DISPATCH_LEVEL.
Преимущества поддержки NDIS SGDMA
В интерфейсе NDIS 6.0 и более поздних версий NDIMA 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 возвращает размер буфера, который должен быть достаточно большим для хранения списка scatter/gather. Минипорт-драйверы должны использовать этот размер для предварительного размещения хранилища для списков scatter/gather.
Драйвер минипорта также передает NdisMRegisterScatterGatherDma точки входа для функций MiniportXxx, которые NDIS вызывает для обработки списка разброса/сбора. NDIS вызывает функцию минипорт драйвера MiniportProcessSGList после того, как HAL создал разбросанный/собранный список для буфера. NdisMRegisterScatterGatherDma предоставляет дескриптор в параметре pNdisMiniportDmaHandle, который драйвер минипорта должен использовать в последующих вызовах функций NDIS точечной/сборной DMA.
Драйвер минипорта NDIS вызывает функцию NdisMDeregisterScatterGatherDma из функции MiniportHaltEx для выпуска ресурсов DMA.
Выделение и освобождение точечной и сборной списков
Драйвер минипорта NDIS вызывает функцию NdisMAllocateNetBufferSGList внутри функции MiniportSendNetBufferLists. Драйвер минипорта вызывает NdisMAllocateNetBufferSGList для каждой структуры NET_BUFFER, которую он должен сопоставить. После того как ресурсы станут доступными и HAL подготовит список SG, NDIS вызывает функцию MiniportProcessSGList драйвера. NDIS может вызвать MiniportProcessSGList до или после того как вызов метода NdisMAllocateNetBufferSGList будет завершен драйвером минипорта.
Чтобы повысить производительность системы, список scatter/gather создается из данных сети, начиная с MDL, указанного в элементе CurrentMdl связанной структуры NET_BUFFER_DATA. Смещение начала сетевых данных в списке SG от начала списка определяется значением CurrentMdlOffset, указанным в связанной структуре NET_BUFFER_DATA.
При обработке DPC для прерывания завершения отправки и после того, как драйвер минипорта перестал нуждаться в списке SG, драйвер минипорта должен вызвать функцию NdisMFreeNetBufferSGList, чтобы освободить список SG.
Примечание не вызывайте NdisMFreeNetBufferSGList, пока драйвер или оборудование все еще обращаются к памяти, описанной структурой NET_BUFFER, связанной с листом scatter/gather.
Перед доступом к полученным данным драйверы минипорта должны вызывать NdisMFreeNetBufferSGList для очистки кэша памяти.