Skip to content

Commit 7ac4ab4

Browse files
authored
Merge pull request #3 from filipnavara/interrupts
RSS & extended interrupts
2 parents 4c486b1 + c69b985 commit 7ac4ab4

File tree

14 files changed

+385
-146
lines changed

14 files changed

+385
-146
lines changed

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ The driver contains code from the Intel FreeBSD igb driver version 2.5.30.
1010

1111
Thanks to *CoolStar* for writing open source [RealTek driver](https://github.com/coolstar/if_re-win), and to *alotipac* for the [Raspberry Pi GENET Ethernet driver](https://github.com/raspberrypi/windows-drivers/). Both of them were invaluable resources that helped me bootstrap the prototype.
1212

13+
## Technical details
14+
15+
The driver supports one 1 TX queue and up to 4 RX queues. This was chosen to balance the supported send offloading methods, receive side scaling, and the number of interrupt vectors supported by the card. For transmission the NIC supports offloading of sending large IPv4, IPv6, TCP, and UDP packets. Since the NIC doesn't support receive side coalescing, we rely mostly on receive side scaling to distribute the load of RX queues.
16+
17+
### Interrupt mapping
18+
19+
In MSI/Legacy mode the RX queues are mapped into the first 4 bits of the Extended Interrupt Cause register. The TX queue uses the legacy bits.
20+
21+
In MSI-X mode we map the RX queues to the first 4 interrupts. The 5th interrupt is used for link status changes and the TX queue.
22+
1323
## TODO
1424

15-
- [ ] Efficient MSI/MSI-X interrupt handling
16-
- [x] Offloading
17-
- [x] Checksums
18-
- [x] Large send offload
1925
- [ ] Energy Efficient Ethernet
20-
- [ ] RSS
26+
- [ ] Wake on LAN
27+
- [ ] Manual Duplex/Speed setting
28+
- [ ] VLAN filtering
2129
- [ ] Enable support for more NIC models

adapter.cpp

Lines changed: 128 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ IgbInitializeAdapterContext(
2828
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
2929
WdfSpinLockCreate(&attributes, &adapter->Lock));
3030

31-
WDF_OBJECT_ATTRIBUTES timerAttributes;
32-
WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
33-
timerAttributes.ParentObject = device;
34-
3531
Exit:
3632
DBGPRINT("IntelInitializeAdapterContext - %x\n", status);
3733

@@ -141,23 +137,28 @@ IgbAdapterSetDatapathCapabilities(
141137
NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA(
142138
&txCapabilities,
143139
&txDmaCapabilities,
144-
1);
140+
IGB_MAX_TX_QUEUES);
145141

146-
txCapabilities.FragmentRingNumberOfElementsHint = /*RE_TX_BUF_NUM*/1024;
147-
txCapabilities.MaximumNumberOfFragments = /*RE_NTXSEGS*/1;
142+
txCapabilities.FragmentRingNumberOfElementsHint = IGB_TX_BUF_NUM;
143+
txCapabilities.MaximumNumberOfFragments = IGB_MAX_PHYS_BUF_COUNT;
148144

149145
NET_ADAPTER_DMA_CAPABILITIES rxDmaCapabilities;
150146
NET_ADAPTER_DMA_CAPABILITIES_INIT(&rxDmaCapabilities, adapter->DmaEnabler);
151147

148+
SIZE_T maxRxQueues = IGB_MAX_RX_QUEUES;
149+
150+
if (adapter->MsiInterrupts > 1)
151+
maxRxQueues = min(maxRxQueues, adapter->MsiInterrupts - 1);
152+
152153
NET_ADAPTER_RX_CAPABILITIES rxCapabilities;
153154
NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA(
154155
&rxCapabilities,
155156
&rxDmaCapabilities,
156157
IGB_BUF_SIZE,
157-
1);
158+
maxRxQueues);
158159

159-
rxCapabilities.FragmentBufferAlignment = /*RE_RX_BUFFER_ALIGN*/128;
160-
rxCapabilities.FragmentRingNumberOfElementsHint = /*RE_RX_BUF_NUM*/1024;
160+
rxCapabilities.FragmentBufferAlignment = IGB_RX_BUFFER_ALIGN;
161+
rxCapabilities.FragmentRingNumberOfElementsHint = IGB_RX_BUF_NUM;
161162

162163
NetAdapterSetDataPathCapabilities(adapter->NetAdapter, &txCapabilities, &rxCapabilities);
163164
}
@@ -221,6 +222,100 @@ EvtAdapterOffloadSetRxChecksum(
221222
adapter->RxUdpHwChkSum = NetOffloadIsRxChecksumUdpEnabled(offload);
222223
}
223224

225+
226+
static
227+
NTSTATUS
228+
EvtAdapterReceiveScalingEnable(
229+
_In_ NETADAPTER netAdapter,
230+
_In_ NET_ADAPTER_RECEIVE_SCALING_HASH_TYPE hashType,
231+
_In_ NET_ADAPTER_RECEIVE_SCALING_PROTOCOL_TYPE protocolType)
232+
{
233+
IGB_ADAPTER* adapter = IgbGetAdapterContext(netAdapter);
234+
235+
DBGPRINT("EvtAdapterReceiveScalingEnable\n");
236+
237+
u32 mrqc = E1000_MRQC_ENABLE_RSS_4Q;
238+
239+
if (protocolType & NetAdapterReceiveScalingProtocolTypeIPv4)
240+
{
241+
mrqc |= E1000_MRQC_RSS_FIELD_IPV4;
242+
if (protocolType & NetAdapterReceiveScalingProtocolTypeTcp)
243+
mrqc |= E1000_MRQC_RSS_FIELD_IPV4_TCP;
244+
}
245+
246+
if (protocolType & NetAdapterReceiveScalingProtocolTypeIPv6)
247+
{
248+
mrqc |= E1000_MRQC_RSS_FIELD_IPV6;
249+
if (protocolType & NetAdapterReceiveScalingProtocolTypeTcp)
250+
mrqc |= E1000_MRQC_RSS_FIELD_IPV6_TCP;
251+
}
252+
253+
// TODO: E1000_MRQC_RSS_FIELD_IPV4_UDP, E1000_MRQC_RSS_FIELD_IPV6_UDP,
254+
// E1000_MRQC_RSS_FIELD_IPV6_UDP_EX, E1000_MRQC_RSS_FIELD_IPV6_TCP_EX
255+
256+
E1000_WRITE_REG(&adapter->Hw, E1000_MRQC, mrqc);
257+
258+
return STATUS_SUCCESS;
259+
}
260+
261+
static
262+
VOID
263+
EvtAdapterReceiveScalingDisable(
264+
_In_ NETADAPTER netAdapter)
265+
{
266+
IGB_ADAPTER* adapter = IgbGetAdapterContext(netAdapter);
267+
268+
DBGPRINT("EvtAdapterReceiveScalingDisable\n");
269+
270+
E1000_WRITE_REG(&adapter->Hw, E1000_MRQC, 0);
271+
}
272+
273+
static
274+
NTSTATUS
275+
EvtAdapterReceiveScalingSetHashSecretKey(
276+
_In_ NETADAPTER netAdapter,
277+
_In_ NET_ADAPTER_RECEIVE_SCALING_HASH_SECRET_KEY const* hashSecretKey)
278+
{
279+
IGB_ADAPTER* adapter = IgbGetAdapterContext(netAdapter);
280+
281+
DBGPRINT("EvtAdapterReceiveScalingSetHashSecretKey\n");
282+
283+
for (int i = 0; i < 10 && i < hashSecretKey->Length; i++)
284+
{
285+
E1000_WRITE_REG_ARRAY(&adapter->Hw, E1000_RSSRK(0), i, hashSecretKey->Key[i]);
286+
}
287+
288+
return STATUS_SUCCESS;
289+
}
290+
291+
static
292+
NTSTATUS
293+
EvtAdapterReceiveScalingSetIndirectionEntries(
294+
_In_ NETADAPTER netAdapter,
295+
_In_ NET_ADAPTER_RECEIVE_SCALING_INDIRECTION_ENTRIES* indirectionEntries)
296+
{
297+
IGB_ADAPTER* adapter = IgbGetAdapterContext(netAdapter);
298+
299+
DBGPRINT("EvtAdapterReceiveScalingSetIndirectionEntries\n");
300+
301+
for (size_t i = 0; i < indirectionEntries->Length; i++)
302+
{
303+
const ULONG queueId = IgbGetRxQueueContext(indirectionEntries->Entries[i].PacketQueue)->QueueId;
304+
const UINT32 index = indirectionEntries->Entries[i].Index;
305+
if (index < 128)
306+
{
307+
u32 reta = E1000_READ_REG(&adapter->Hw, E1000_RETA(index >> 2));
308+
u32 shift = (index & 2) << 3;
309+
reta ^= reta & (0xff << shift);
310+
reta |= queueId << shift;
311+
E1000_WRITE_REG(&adapter->Hw, E1000_RETA(index >> 2), reta);
312+
}
313+
}
314+
315+
return STATUS_SUCCESS;
316+
317+
}
318+
224319
static
225320
void
226321
IgbAdapterSetOffloadCapabilities(
@@ -271,6 +366,28 @@ IgbAdapterSetOffloadCapabilities(
271366
NetAdapterOffloadSetIeee8021qTagCapabilities(adapter->NetAdapter, &ieee8021qTagOffloadCapabilities);
272367
}
273368

369+
static
370+
void
371+
IgbAdapterSetRssCapabilities(
372+
_In_ IGB_ADAPTER const* adapter)
373+
{
374+
NET_ADAPTER_RECEIVE_SCALING_CAPABILITIES receiveScalingCapabilities;
375+
NET_ADAPTER_RECEIVE_SCALING_CAPABILITIES_INIT(
376+
&receiveScalingCapabilities,
377+
IGB_MAX_RX_QUEUES,
378+
NetAdapterReceiveScalingUnhashedTargetTypeHashIndex,
379+
NetAdapterReceiveScalingHashTypeToeplitz,
380+
NetAdapterReceiveScalingProtocolTypeIPv4 |
381+
NetAdapterReceiveScalingProtocolTypeIPv6 |
382+
NetAdapterReceiveScalingProtocolTypeTcp,
383+
EvtAdapterReceiveScalingEnable,
384+
EvtAdapterReceiveScalingDisable,
385+
EvtAdapterReceiveScalingSetHashSecretKey,
386+
EvtAdapterReceiveScalingSetIndirectionEntries);
387+
receiveScalingCapabilities.SynchronizeSetIndirectionEntries = true;
388+
NetAdapterSetReceiveScalingCapabilities(adapter->NetAdapter, &receiveScalingCapabilities);
389+
}
390+
274391
_Use_decl_annotations_
275392
NTSTATUS
276393
IgbAdapterStart(
@@ -284,6 +401,7 @@ IgbAdapterStart(
284401
IgbAdapterSetReceiveFilterCapabilities(adapter);
285402
IgbAdapterSetDatapathCapabilities(adapter);
286403
IgbAdapterSetOffloadCapabilities(adapter);
404+
IgbAdapterSetRssCapabilities(adapter);
287405

288406
IgbUpdateReceiveFilters(adapter);
289407

adapter.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@ extern "C"
55
#include "e1000_api.h"
66
}
77

8-
#define IGB_MAX_TX_QUEUES 4
8+
#define IGB_MAX_TX_QUEUES 1
99
#define IGB_MAX_RX_QUEUES 4
10+
#define IGB_MAX_INTERRUPTS 5
1011
#define IGB_MAX_MCAST_LIST 32
1112

13+
#define IGB_TX_BUF_NUM 1024
14+
#define IGB_RX_BUF_NUM 1024
15+
#define IGB_RX_BUFFER_ALIGN 128
16+
#define IGB_MAX_PHYS_BUF_COUNT 1
17+
1218
#define IGB_BUF_SIZE 2048
1319

1420
typedef struct _IGB_ADAPTER
@@ -27,7 +33,9 @@ typedef struct _IGB_ADAPTER
2733
SIZE_T MMIOSize;
2834
BUS_INTERFACE_STANDARD PciConfig;
2935

30-
IGB_INTERRUPT* Interrupt;
36+
PIGB_INTERRUPT MiscInterrupt;
37+
PIGB_INTERRUPT Interrupts[IGB_MAX_INTERRUPTS];
38+
UINT MsiInterrupts;
3139

3240
NET_PACKET_FILTER_FLAGS PacketFilterFlags;
3341
UINT MCAddressLength;

device.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include "trace.h"
66
#include "device.h"
77
#include "adapter.h"
8-
//#include "configuration.h"
8+
#include "interrupt.h"
99
#include "link.h"
1010

1111
NTSTATUS
@@ -20,6 +20,7 @@ IgbGetResources(
2020

2121
ULONG errorCode = 0;
2222
ULONG memRegCnt = 0;
23+
ULONG intCnt = 0;
2324

2425
// According to https://msdn.microsoft.com/windows/hardware/drivers/wdf/raw-and-translated-resources
2526
// "Both versions represent the same set of hardware resources, in the same order."
@@ -44,9 +45,21 @@ IgbGetResources(
4445

4546
memRegCnt++;
4647
}
48+
else if (rawDescriptor->Type == CmResourceTypeInterrupt)
49+
{
50+
if (intCnt < IGB_MAX_INTERRUPTS)
51+
{
52+
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
53+
IgbInterruptCreate(adapter->WdfDevice, adapter, rawDescriptor, translatedDescriptor, &adapter->Interrupts[intCnt]));
54+
55+
if (translatedDescriptor->Flags & CM_RESOURCE_INTERRUPT_MESSAGE)
56+
adapter->MsiInterrupts++;
57+
}
58+
intCnt++;
59+
}
4760
}
4861

49-
if (!adapter->MMIOAddress)
62+
if (!adapter->MMIOAddress || intCnt == 0)
5063
{
5164
status = STATUS_RESOURCE_TYPE_NOT_FOUND;
5265
errorCode = NDIS_ERROR_CODE_RESOURCE_CONFLICT;
@@ -71,7 +84,6 @@ NTSTATUS
7184
IgbRegisterScatterGatherDma(
7285
_In_ IGB_ADAPTER* adapter)
7386
{
74-
//TraceEntryRtAdapter(adapter);
7587
DBGPRINT("IntelRegisterScatterGatherDma\n");
7688

7789
WDF_DMA_ENABLER_CONFIG dmaEnablerConfig;

driver.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ EvtDriverDeviceAdd(
111111

112112
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
113113
IgbInitializeAdapterContext(adapter, wdfDevice, netAdapter));
114-
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
115-
IgbInterruptCreate(wdfDevice, adapter, &adapter->Interrupt));
116114

117115
Exit:
118116
if (adapterInit != nullptr)

forward.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3-
typedef struct _IGB_ADAPTER IGB_ADAPTER;
4-
typedef struct _IGB_DEVICE IGB_DEVICE;
5-
typedef struct _IGB_INTERRUPT IGB_INTERRUPT;
3+
typedef struct _IGB_ADAPTER IGB_ADAPTER, *PIGB_ADAPTER;
4+
typedef struct _IGB_DEVICE IGB_DEVICE, *PIGB_DEVICE;
5+
typedef struct _IGB_INTERRUPT IGB_INTERRUPT, *PIGB_INTERRUPT;
6+
typedef struct _IGB_QUEUE_INTERRUPT IGB_QUEUE_INTERRUPT, *PIGB_QUEUE_INTERRUPT;

igb.inx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ AddReg = NetworkAddress.kw
4848
AddReg = OffloadChecksum.kw
4949
AddReg = PriorityVlanTag.kw
5050
AddReg = LSO.kw
51+
AddReg = ReceiveSideScaling.kw
52+
53+
[IGB.ndi.NT.HW]
54+
AddReg = MSIInterrupt.kw
5155

5256
[ndi.reg]
5357
; TODO: Update these if your device is not Ethernet.
@@ -193,6 +197,17 @@ HKR,Ndi\Params\*LsoV2Ipv6, Default, 0, "1"
193197
HKR,Ndi\Params\*LsoV2Ipv6\enum, "0", 0, %Disabled%
194198
HKR,Ndi\Params\*LsoV2Ipv6\enum, "1", 0, %Enabled%
195199

200+
[ReceiveSideScaling.kw]
201+
HKR,Ndi\Params\*RSS, ParamDesc, 0, "%ReceiveSideScaling%"
202+
HKR,Ndi\Params\*RSS, default, 0, "1"
203+
HKR,Ndi\Params\*RSS, type, 0, "enum"
204+
HKR,Ndi\Params\*RSS, optional, 0, "0"
205+
HKR,Ndi\Params\*RSS\enum, "0", 0, %Disabled%"
206+
HKR,Ndi\Params\*RSS\enum, "1", 0, %Enabled%"
207+
208+
[MSIInterrupt.kw]
209+
HKR,Interrupt Management\MessageSignaledInterruptProperties, MSISupported, 0x00010001, 1
210+
196211
[Strings]
197212
AutoDetect = "Auto Negotiation"
198213
SpeedDuplex = "Speed & Duplex"
@@ -220,6 +235,7 @@ PriorityVLANDisabled = "Priority & VLAN Disabled"
220235
PriorityVLANEnabled = "Priority & VLAN Enabled"
221236
PriorityEnabled = "Packet Priority Enabled"
222237
VLANEnabled = "VLAN Enabled"
238+
ReceiveSideScaling = "Receive Side Scaling"
223239

224240
LSOv2Ipv4 = "Large Send Offload v2 (IPv4)"
225241
LSOv2Ipv6 = "Large Send Offload v2 (IPv6)"

0 commit comments

Comments
 (0)