Bagikan melalui


Mode Polling NDIS

Gambaran Umum Mode Polling NDIS

Mode Polling NDIS adalah model eksekusi polling terkontrol OS yang mendorong jalur data antarmuka jaringan.

Sebelumnya, NDIS tidak memiliki definisi formal dari konteks eksekusi jalur data. Driver NDIS biasanya mengandalkan Panggilan Prosedur Tangguhan (DPC) untuk menerapkan model eksekusi mereka. Namun menggunakan DPC dapat membanjiri sistem ketika rantai indikasi panjang dibuat dan menghindari masalah ini membutuhkan banyak kode yang rumit untuk mendapatkan yang benar. Mode Polling NDIS menawarkan alternatif untuk DPC dan alat eksekusi serupa.

Mode Polling NDIS memindahkan kompleksitas keputusan penjadwalan dari driver NIC dan ke NDIS, di mana NDIS menetapkan batas kerja per iterasi. Untuk mencapai Mode Polling ini, berikan:

  1. Mekanisme bagi OS untuk memberikan tekanan kembali pada NIC.

  2. Mekanisme bagi OS untuk mengontrol gangguan dengan halus.

Mode Polling NDIS tersedia untuk driver miniport NDIS 6.85 dan yang lebih baru.

Masalah dengan model DPC

Diagram urutan berikut mengilustrasikan contoh umum tentang bagaimana driver miniport NDIS menangani ledakan paket Rx menggunakan DPC. Dalam contoh ini perangkat keras adalah standar dalam hal PCIe NIC. Ini memiliki antrean perangkat keras penerimaan dan masker interupsi untuk antrean tersebut.

Diagram memperlihatkan model DPC NDIS dengan paket Rx dan antrean perangkat keras penerima.

Ketika tidak ada aktivitas jaringan, perangkat keras mengaktifkan interupsi Rx. Ketika paket Rx tiba:

  1. Perangkat keras menghasilkan interupsi dan NDIS memanggil fungsi MiniportInterrupt driver (ISR).

  2. Driver melakukan sangat sedikit pekerjaan di ISR karena mereka berjalan pada IRQL yang sangat tinggi. Driver menonaktifkan gangguan dari ISR dan menunda pemrosesan perangkat keras ke fungsi MiniportInterruptDPC (DPC).

  3. NDIS akhirnya memanggil DPC driver dan driver mengosongkan penyelesaian apa pun dari antrean perangkat keras dan menunjukkannya ke OS.

Dua titik nyeri dapat memengaruhi tumpukan jaringan ketika driver menunda operasi I/O ke DPC:

  1. Driver tidak tahu apakah sistem mampu memproses semua data yang ditunjukkan, sehingga driver tidak memiliki pilihan selain menguras sebanyak mungkin elemen dari antrean perangkat kerasnya dan menunjukkannya ke atas tumpukan.

  2. Karena driver menggunakan DPC untuk menunda pekerjaan dari ISR-nya, semua indikasi dibuat pada DISPATCH_LEVEL. Ini dapat membanjiri sistem ketika rantai indikasi panjang dibuat dan menyebabkan Pemeriksaan Bug 0x133 DPC_WATCHDOG_VIOLATION.

Menghindari titik nyeri ini membutuhkan banyak kode yang sulit di driver Anda. Meskipun Anda dapat memeriksa apakah pengawas DPC mendekati batas dengan fungsi KeQueryDpcWatchdogInformation dan keluar dari DPC, Anda masih perlu membangun infrastruktur di sekitar ini di driver Anda: Anda memerlukan beberapa cara untuk menjeda sebentar, kemudian terus menunjukkan paket, dan pada saat yang sama Anda perlu menyinkronkan semua ini dengan masa pakai datapath.

Pengantar objek Polling

Mode Polling NDIS memperkenalkan objek Polling untuk mengatasi titik nyeri yang terkait dengan DPC. Objek Polling adalah konstruksi konteks eksekusi. Driver miniport dapat menggunakan objek Polling sebagai pengganti DPC saat berhadapan dengan operasi datapath.

Objek Polling menawarkan hal berikut:

  • Ini menyediakan cara bagi NDIS untuk menetapkan batas kerja per iterasi.

  • Ini terkait erat dengan mekanisme pemberitahuan. Ini membuat OS dan NIC tetap sinkron mengenai kapan pekerjaan perlu diproses.

  • Ini memiliki konsep iterasi dan interupsi bawaan. Saat menggunakan DPC, driver dipaksa untuk mengaktifkan kembali interupsi setiap kali mereka menyelesaikan DPC. Saat menggunakan objek Polling, driver tidak perlu mengaktifkan kembali interupsi setiap iterasi polling karena Mode Polling akan memberi tahu driver Anda ketika selesai polling dan saatnya untuk mengaktifkan kembali gangguan lagi.

  • Saat membuat keputusan penjadwalan, sistem dapat cerdas tentang apakah akan berjalan pada DISPATCH_LEVEL atau PASSIVE_LEVEL. Ini dapat memungkinkan prioritas lalu lintas yang disempurnakan dari NIC yang berbeda dan menyebabkan distribusi beban kerja yang lebih adil pada komputer.

  • Ini memiliki jaminan serialisasi. Setelah Anda menjalankan kode dari dalam konteks eksekusi objek Polling, Anda dijamin bahwa tidak ada kode lain yang terkait dengan konteks eksekusi yang sama yang akan berjalan. Ini memungkinkan driver NIC untuk memiliki implementasi bebas kunci dari datapath-nya.

Model Mode Polling NDIS

Diagram urutan berikut menggambarkan bagaimana driver PCIe NIC hipotetis yang sama menangani ledakan paket Rx menggunakan objek Polling alih-alih DPC.

Diagram memperlihatkan Mode Polling NDIS dengan paket Rx dan antrean perangkat keras penerima.

Seperti model DPC, ketika paket Rx tiba, perangkat keras menghasilkan gangguan, NDIS memanggil ISR driver, dan driver menonaktifkan gangguan dari ISR. Pada titik ini model Mode Polling berbeda:

  1. Alih-alih mengantre DPC, driver mengantre objek Polling (yang sebelumnya dibuat) dari ISR untuk memberi tahu NDIS bahwa pekerjaan baru siap diproses.

  2. Pada titik tertentu di masa mendatang NDIS memanggil penanganan iterasi polling driver untuk memproses pekerjaan. Tidak seperti DPC, driver tidak diizinkan untuk menunjukkan NBL Rx sebanyak yang ada elemen yang siap dalam antrean perangkat kerasnya. Driver harus memeriksa parameter data polling handler untuk mendapatkan jumlah maksimum NBL yang dapat ditunjukkannya.

    Setelah driver mengambil hingga jumlah maksimum paket Rx, driver harus menginisialisasi NBL, tambahkan ke antrean NBL yang disediakan oleh penangan polling, dan keluar dari panggilan balik. Driver tidak boleh mengaktifkan interupsi sebelum keluar.

  3. NDIS terus melakukan polling pada pengemudi hingga menilai bahwa pengemudi tidak lagi membuat kemajuan ke depan. Pada titik ini NDIS akan berhenti melakukan polling dan meminta driver untuk mengaktifkan kembali interupsi.

Kata kunci INF standar untuk Mode Polling NDIS

Kata kunci berikut harus digunakan untuk mengaktifkan atau menonaktifkan dukungan untuk Mode Polling NDIS:

*Kata kunci INF standar Enumerasi NdisPoll memiliki atribut berikut:

SubkeyName
Nama kata kunci yang harus Anda tentukan dalam file INF dan yang muncul di registri.

ParamDesc
Teks tampilan yang terkait dengan SubkeyName.

Nilai
Nilai bilangan bulat enumerasi yang terkait dengan setiap opsi dalam daftar. Nilai ini disimpan dalam NDI\params\ SubkeyName\Value.

EnumDesc
Teks tampilan yang terkait dengan setiap nilai yang muncul di menu.

Default
Nilai default untuk menu.

SubkeyName ParamDesc Nilai EnumDesc
*NdisPoll Mode Polling Ndis 0 Nonaktif
1 (Default) Diaktifkan

Untuk informasi selengkapnya tentang menggunakan kata kunci enumerasi, lihat Kata Kunci Enumerasi.

Membuat objek Polling

Untuk membuat objek Polling, driver miniport melakukan hal berikut dalam fungsi panggilan balik MiniportInitializeEx:

  1. Mengalokasikan konteks miniport privat.
  2. Mengalokasikan struktur NDIS_POLL_CHARACTERISTICS untuk menentukan titik masuk untuk fungsi panggilan balik NdisPoll dan NdisSetPollNotification.
  3. Memanggil NdisRegisterPoll untuk membuat objek Polling dan menyimpannya dalam konteks miniport.

Contoh berikut menunjukkan bagaimana driver miniport dapat membuat objek Polling untuk alur antrean penerima. Penanganan kesalahan dihilangkan untuk kesederhanaan.

NDIS_SET_POLL_NOTIFICATION NdisSetPollNotification; 
NDIS_POLL NdisPoll; 

NDIS_STATUS 
MiniportInitialize( 
    _In_ NDIS_HANDLE NdisAdapterHandle, 
    _In_ NDIS_HANDLE MiniportDriverContext, 
    _In_ NDIS_MINIPORT_INIT_PARAMETERS * MiniportInitParameters 
) 
{ 
    // Allocate a private miniport context 
    MINIPORT_CONTEXT * miniportContext = ...;
 
    NDIS_POLL_CHARACTERISTICS pollCharacteristics; 
    pollCharacteristics.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; 
    pollCharacteristics.Header.Revision = NDIS_POLL_CHARACTERISTICS_REVISION_1; 
    pollCharacteristics.Header.Size = NDIS_SIZEOF_NDIS_POLL_CHARACTERISTICS_REVISION_1; 
    pollCharacteristics.SetPollNotificationHandler = NdisSetPollNotification; 
    pollCharacteristics.PollHandler = NdisPoll; 

    // Create a Poll object and store it in the miniport context 
    NdisRegisterPoll( 
        NdisAdapterHandle, 
        miniportContext, 
        &pollCharacteristics, 
        &miniportContext->RxPoll); 
 
    return NDIS_STATUS_SUCCESS; 
} 

Mengantre objek Polling untuk eksekusi

Dari ISR, driver miniport memanggil NdisRequestPoll untuk mengantrekan objek Polling untuk eksekusi. Contoh berikut menunjukkan penanganan penerimaan tetapi mengabaikan berbagi baris interupsi untuk kesederhanaan.

BOOLEAN 
MiniportIsr( 
  KINTERRUPT * Interrupt, 
  void * Context 
) 
{ 
    auto miniportContext = static_cast<MINIPORT_CONTEXT *>(Context); 
    auto hardwareContext = miniportContext->HardwareContext; 

    // Check if this interrupt is due to a received packet 
    if (hardwareContext->ISR & RX_OK) 
    { 
        // Disable the receive interrupt and queue the Poll 
        hardwareContext->IMR &= ~RX_OK; 
        NdisRequestPoll(miniportContext->RxPoll, nullptr); 
    }

    return TRUE; 
} 

Menerapkan penanganan iterasi Polling

NDIS memanggil panggilan balik NdisPoll driver miniport ke polling untuk menerima indikasi dan mengirim penyelesaian. NDIS pertama kali memanggil NdisPoll ketika driver memanggil NdisRequestPoll untuk mengantre objek Polling. NDIS akan terus memanggil NdisPoll saat driver membuat kemajuan maju pada menerima indikasi atau mengirimkan penyelesaian.

Untuk menerima indikasi, driver harus melakukan hal berikut di NdisPoll:

  1. Periksa parameter penerima struktur NDIS_POLL_DATA untuk mendapatkan jumlah maksimum NBL yang dapat ditunjukkannya.
  2. Ambil hingga jumlah maksimum paket Rx.
  3. Menginisialisasi NBL.
  4. Tambahkan ke antrean NBL yang disediakan oleh struktur NDIS_POLL_RECEIVE_DATA (terletak di struktur NDIS_POLL_DATA parameter NdisPoll PollData).
  5. Keluar dari panggilan balik.

Untuk penyelesaian pengiriman, driver harus melakukan hal berikut di NdisPoll:

  1. Periksa parameter transmisi struktur NDIS_POLL_DATA untuk mendapatkan jumlah maksimum NBL yang dapat diselesaikannya.
  2. Ambil hingga jumlah maksimum paket Tx.
  3. Lengkapi NBL.
  4. Tambahkan ke antrean NBL yang disediakan oleh struktur NDIS_POLL_TRANSMIT_DATA (terletak di struktur NDIS_POLL_DATA parameter NdisPoll PollData).
  5. Keluar dari panggilan balik.

Driver tidak boleh mengaktifkan interupsi objek Polling sebelum keluar dari fungsi NdisPoll . NDIS akan terus melakukan polling driver sampai menilai bahwa tidak ada kemajuan maju yang dibuat. Pada titik ini NDIS akan berhenti melakukan polling dan meminta driver untuk mengaktifkan kembali interupsi.

Berikut adalah cara driver dapat mengimplementasikan NdisPoll untuk alur antrean penerima.

_Use_decl_annotations_ 
void 
NdisPoll( 
    void * Context, 
    NDIS_POLL_DATA * PollData 
) 
{ 
    auto miniportContext = static_cast<MINIPORT_CONTEXT *>(Context); 
    auto hardwareContext = miniportContext->HardwareContext; 

    // Drain received frames 
    auto & receive = PollData->Receive; 
    receive.NumberOfRemainingNbls = NDIS_ANY_NUMBER_OF_NBLS; 
    receive.Flags = NDIS_RECEIVE_FLAGS_SHARED_MEMORY_VALID; 

    while (receive.NumberOfIndicatedNbls < receive.MaxNblsToIndicate) 
    { 
        auto rxDescriptor = HardwareQueueGetNextDescriptorToCheck(hardwareContext->RxQueue); 

        // If this descriptor is still owned by hardware stop draining packets 
        if ((rxDescriptor->Status & HW_OWN) != 0) 
            break; 

        auto nbl = MakeNblFromRxDescriptor(miniportContext->NblPool, rxDescriptor); 

        AppendNbl(&receive.IndicatedNblChain, nbl); 
        receive.NumberOfIndicatedNbls++; 

        // Move to next descriptor 
        HardwareQueueAdvanceNextDescriptorToCheck(hardwareContext->RxQueue); 
    } 
} 

Mengelola interupsi

Driver Miniport menerapkan panggilan balik NdisSetPollNotification untuk mengaktifkan atau menonaktifkan interupsi yang terkait dengan objek Polling. NDIS biasanya memanggil panggilan balik NdisSetPollNotification ketika mendeteksi bahwa driver miniport tidak membuat kemajuan di NdisPoll. NDIS menggunakan NdisSetPollNotification untuk memberi tahu driver bahwa ia akan berhenti memanggil NdisPoll. Driver harus memanggil NdisRequestPoll ketika pekerjaan baru siap untuk diproses.

Berikut adalah cara driver dapat mengimplementasikan NdisSetPollNotification untuk alur antrean penerima.

_Use_decl_annotations_ 
void 
NdisSetPollNotification( 
    void * Context, 
    NDIS_POLL_NOTIFICATION * Notification 
) 
{ 
    auto miniportContext = static_cast<MINIPORT_CONTEXT *>(Context); 
    auto hardwareContext = miniportContext->HardwareContext; 

    if (Notification->Enabled) 
    { 
        hardwareContext->IMR |= RX_OK; 
    } 
    else 
    { 
        hardwareContext->IMR &= ~RX_OK; 
    } 
}