Bagikan melalui


Mode Polling NDIS

Gambaran Umum Mengenai 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 membebani sistem ketika rangkaian indikasi panjang dibuat, dan menghindari masalah ini membutuhkan banyak kode yang rumit agar bisa tepat. Mode Polling NDIS menawarkan alternatif untuk DPC dan alat eksekusi serupa.

Mode Poll NDIS mengalihkan kompleksitas keputusan penjadwalan dari driver NIC dan NDIS, di mana NDIS menetapkan batas kerja setiap iterasi. Untuk mencapai ini, Mode Polling menyediakan:

  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 antrian perangkat keras untuk penerimaan dan masker interupsi untuk antrian 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 pada ISR karena menjalankan pada IRQL yang sangat tinggi. Driver menonaktifkan gangguan dari ISR dan menunda pemrosesan perangkat keras ke fungsiMiniportInterruptDPC (DPC).

  3. NDIS akhirnya memanggil DPC driver, dan driver tersebut mengosongkan penyelesaian apa pun dari antrean perangkat keras dan menunjukkan penyelesaian tersebut ke sistem operasi.

Dua masalah dapat memengaruhi tumpukan jaringan ketika driver menangguhkan operasi I/O ke DPC.

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

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

Menghindari masalah ini membutuhkan banyak kode rumit di dalam 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 Poll NDIS memperkenalkan objek Poll untuk mengatasi masalah yang terkait dengan DPC. Objek Poll adalah sebuah konstruksi konsep 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 Poll, driver tidak perlu mengaktifkan kembali interupsi setiap iterasi polling karena Mode Poll akan memberi tahu driver Anda ketika selesai polling dan saatnya untuk mengaktifkan kembali interupsi.

  • 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 gelombang paket Rx menggunakan objek Poll alih-alih DPC.

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

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

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

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

    Setelah driver mengambil hingga jumlah maksimum paket Rx, ia harus menginisialisasi NBL, menambahkannya ke antrean NBL yang disediakan oleh penangan polling, dan keluar dari callback. Pengendali 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:

*NdisPoll Kata kunci INF standar Enumerasi memiliki atribut berikut:

Nama Subkunci
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.

Bawaan
Nilai default untuk menu.

SubkeyName ParamDesc Nilai EnumDesc
*NdisPoll Mode Ndis Polling 0 Dinonaktifkan
1 (Bawaan) 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. MemanggilNdisRegisterPoll untuk membuat objek Polling dan menyimpannya dalam konteks miniport.

Contoh berikut menunjukkan bagaimana driver miniport dapat membuat objek Poll untuk alur antrean penerimaan. 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 Jajak Pendapat untuk pelaksanaan

Pada ISR, driver miniport memanggil NdisRequestPoll untuk memasukkan objek Poll ke dalam antrean untuk dieksekusi. 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 jajak pendapat

NDIS memanggil callback driver miniport NdisPoll untuk memeriksa indikasi penerimaan dan penyelesaian pengiriman. NDIS pertama kali memanggil NdisPoll ketika driver memanggil NdisRequestPoll untuk mengantre objek Poll. NDIS akan terus memanggil NdisPoll saat driver melakukan kemajuan pada indikasi penerimaan atau penyelesaian pengiriman.

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

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

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

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

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

Berikut adalah cara yang mungkin dilakukan oleh driver untuk menerapkan NdisPoll pada proses antrean penerimaan.

_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 balikNdisSetPollNotification untuk mengaktifkan atau menonaktifkan gangguan yang terkait dengan objek Polling. NDIS biasanya memanggil callback NdisSetPollNotification ketika mendeteksi bahwa driver miniport tidak membuat kemajuan dalam NdisPoll. NDIS menggunakan NdisSetPollNotification untuk memberi tahu pengandar bahwa NDIS akan berhenti memanggil NdisPoll. Driver harus memanggil NdisRequestPoll ketika pekerjaan baru siap untuk diproses.

Berikut adalah cara driver dapat menerapkan NdisSetPollNotification untuk alur antrean penerimaan.

_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; 
    } 
}