Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
I driver client NetAdapterCx inviano dati di rete quando il framework richiama la funzione di callback EvtPacketQueueAdvance per una coda di trasmissione. Durante questo callback, i driver client postano i buffer dall'anello di frammento della coda all'hardware, quindi rilasciano i pacchetti e i frammenti completati al sistema operativo.
Panoramica delle operazioni di trasmissione (Tx) post e drenaggio
L'animazione seguente illustra come un driver client per una semplice scheda di interfaccia di rete PCI (NIC) esegua operazioni di post e di svuotamento per una coda di trasmissione (Tx).
In questa animazione, i pacchetti di proprietà del driver client sono evidenziati in blu chiaro e blu scuro e i frammenti di proprietà del driver client sono evidenziati in giallo e arancione. I colori più chiari rappresentano la sottosezione di scarico degli elementi in possesso del driver, mentre i colori più scuri rappresentano la sottosezione post degli elementi in possesso del driver.
Invio di dati in ordine
Ecco una tipica sequenza di postazione e drenaggio per un driver il cui dispositivo trasmette i dati in ordine, come, ad esempio, un semplice NIC PCI.
- Chiamare NetTxQueueGetRingCollection per recuperare la raccolta ad anello della coda di trasmissione. È possibile archiviare questo valore nello spazio di contesto della coda per ridurre le chiamate fuori dal driver. Utilizzare la raccolta di anelli per recuperare l'anello dei pacchetti della coda di trasmissione.
- Pubblicare i dati nell'hardware:
- Allocare una variabile UINT32 per l'indice del pacchetto e impostarla sul NextIndex dell'anello di pacchetti, che rappresenta l'inizio della sottosezione post dell'anello.
- Eseguire le operazioni seguenti in un ciclo:
- Ottenere un pacchetto chiamando NetRingGetPacketAtIndex con l'indice dei pacchetti.
- Controllare se il pacchetto deve essere ignorato. Se deve essere ignorato, proseguire al passaggio 6 di questo ciclo. In caso contrario, continuare.
- Ottieni i frammenti di questo pacchetto. Recuperare l'anello di frammento della coda di trasmissione dalla raccolta circolare, recuperare l'inizio dei frammenti del pacchetto dal membro FragmentIndex del pacchetto, quindi recuperare la fine dei frammenti del pacchetto chiamando NetRingIncrementIndex con FragmentCount del pacchetto.
- Eseguire le operazioni seguenti in un ciclo:
- Chiamare NetRingGetFragmentAtIndex per ottenere un frammento.
- Converti il descrittore NET_FRAGMENT nel descrittore di frammento hardware associato.
- Avanzare l'indice del frammento chiamando NetRingIncrementIndex.
- Aggiornare l'indice Prossimo dell'anello del frammento in modo che corrisponda all'indice corrente dell'iteratore del frammento, il che indica che l'invio all'hardware è stato completato.
- Avanzare l'indice dei pacchetti chiamando NetRingIncrementIndex.
- Aggiornare l'elemento NextIndex dell'anello di pacchetti all'indice dei pacchetti per finalizzare la registrazione dei pacchetti nell'hardware.
- Svuotare i pacchetti di trasmissione completati verso il sistema operativo.
- Impostare l'indice del pacchetto sull'indice di inizio BeginIndex del ring, che corrisponde all'inizio della sezione di scarico del ring.
- Eseguire le operazioni seguenti in un ciclo:
- Ottenere un pacchetto chiamando NetRingGetPacketAtIndex con l'indice dei pacchetti.
- Controllare se il pacchetto ha terminato la trasmissione. In caso contrario, interrompere il ciclo.
- Avanzare l'indice dei pacchetti chiamando NetRingIncrementIndex.
- Aggiornare l'elemento BeginIndex dell'anello di pacchetti all'indice dei pacchetti per finalizzare la registrazione dei pacchetti nell'hardware.
Questi passaggi potrebbero essere simili al seguente nel codice. Si noti che i dettagli specifici dell'hardware, come ad esempio come inviare i descrittori sull'hardware o svuotare una transazione post riuscita, sono stati omessi per maggiore chiarezza.
void
MyEvtTxQueueAdvance(
NETPACKETQUEUE TxQueue
)
{
//
// Retrieve the transmit queue's ring collection and packet ring.
// This example stores the Tx queue's ring collection in its queue context space.
//
PMY_TX_QUEUE_CONTEXT txQueueContext = MyGetTxQueueContext(TxQueue);
NET_RING_COLLECTION const * ringCollection = txQueueContext->RingCollection;
NET_RING * packetRing = ringCollection->Rings[NET_RING_TYPE_PACKET];
UINT32 currentPacketIndex = 0;
//
// Post data to hardware
//
currentPacketIndex = packetRing->NextIndex;
while(currentPacketIndex != packetRing->EndIndex)
{
NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
if(!packet->Ignore)
{
NET_RING * fragmentRing = ringCollection->Rings[NET_RING_TYPE_FRAGMENT];
UINT32 currentFragmentIndex = packet->FragmentIndex;
UINT32 fragmentEndIndex = NetRingIncrementIndex(fragmentRing, currentFragmentIndex + packet->FragmentCount - 1);
for(txQueueContext->PacketTransmitControlBlocks[packetIndex]->numTxDescriptors = 0;
currentFragmentIndex != fragmentEndIndex;
txQueueContext->PacketTransmitControlBlocks[packetIndex]->numTxDescriptors++)
{
NET_FRAGMENT * fragment = NetRingGetFragmentAtIndex(fragmentRing, currentFragmentIndex);
// Post fragment descriptor to hardware
...
//
currentFragmentIndex = NetRingIncrementIndex(fragmentRing, currentFragmentIndex);
}
//
// Update the fragment ring's Next index to indicate that posting is complete and prepare for draining
//
fragmentRing->NextIndex = currentFragmentIndex;
}
currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
}
packetRing->NextIndex = currentPacketIndex;
//
// Drain packets if completed
//
currentPacketIndex = packetRing->BeginIndex;
while(currentPacketIndex != packetRing->NextIndex)
{
NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
// Test packet for transmit completion by checking hardware ownership flags in the packet's last fragment
// Break if transmit is not complete
...
//
currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
}
packetRing->BeginIndex = currentPacketIndex;
}
Invio di dati non in ordine
Per i driver i cui dispositivi potrebbero completare le trasmissioni non in ordine, la differenza principale rispetto ai dispositivi in ordine consiste in chi alloca i buffer di trasmissione e in che modo il driver gestisce il test per il completamento della trasmissione. Per le trasmissioni in ordine con una scheda di rete PCI che supporta DMA, il sistema operativo in genere alloca, collega e possiede i buffer dei frammenti. Quindi, nell'ordine, il driver client può testare il flag di proprietà hardware corrispondente di ogni frammento durante EvtPacketQueueAdvance.
A differenza di questo modello, si consideri una tipica scheda di interfaccia di rete basata su USB. In questa situazione, lo stack USB possiede i buffer di memoria per la trasmissione e tali buffer potrebbero trovarsi altrove nella memoria di sistema. Lo stack USB segnala le completamenti al driver client in modo non sequenziale, quindi il driver client deve registrare separatamente lo stato di completamento di un pacchetto durante la routine di callback per il completamento. A tale scopo, il driver client può usare il campo Scratch del pacchetto oppure può usare un altro metodo, ad esempio l'archiviazione delle informazioni nello spazio di contesto della coda. Quindi, nella chiamata a EvtPacketQueueAdvance, il driver client controlla queste informazioni per il test di completamento dei pacchetti.