xref: /reactos/drivers/network/dd/dc21x4/hardware.c (revision 501c2bdd)
1 /*
2  * PROJECT:     ReactOS DC21x4 Driver
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Hardware specific functions
5  * COPYRIGHT:   Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include "dc21x4.h"
11 
12 #include <debug.h>
13 
14 /* FUNCTIONS ******************************************************************/
15 
16 VOID
17 DcDisableHw(
18     _In_ PDC21X4_ADAPTER Adapter)
19 {
20     ULONG OpMode;
21 
22     /* Disable interrupts */
23     DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
24 
25     /* Stop DMA */
26     OpMode = Adapter->OpMode;
27     OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
28     DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
29 
30     /* Put the adapter to snooze mode */
31     DcPowerSave(Adapter, TRUE);
32 
33     /* Perform a software reset */
34     DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
35 }
36 
37 VOID
38 DcStopTxRxProcess(
39     _In_ PDC21X4_ADAPTER Adapter)
40 {
41     ULONG i, OpMode, Status;
42 
43     OpMode = Adapter->OpMode;
44     OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
45     DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
46 
47     for (i = 0; i < 5000; ++i)
48     {
49         Status = DC_READ(Adapter, DcCsr5_Status);
50 
51         if (((Status & DC_STATUS_TX_STATE_MASK) == DC_STATUS_TX_STATE_STOPPED) &&
52             ((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED))
53         {
54             return;
55         }
56 
57         NdisStallExecution(10);
58     }
59 
60     WARN("Failed to stop the TX/RX process 0x%08lx\n", Status);
61 }
62 
63 VOID
64 DcWriteGpio(
65     _In_ PDC21X4_ADAPTER Adapter,
66     _In_ ULONG Value)
67 {
68     ULONG Data, Register;
69 
70     /* Some chips don't have a separate GPIO register */
71     if (Adapter->Features & DC_SIA_GPIO)
72     {
73         Data = Adapter->SiaSetting;
74         Data &= 0x0000FFFF;  /* SIA */
75         Data |= Value << 16; /* GPIO */
76         Adapter->SiaSetting = Data;
77 
78         Register = DcCsr15_SiaGeneral;
79     }
80     else
81     {
82         Data = Value;
83         Register = DcCsr12_Gpio;
84     }
85     DC_WRITE(Adapter, Register, Data);
86 }
87 
88 VOID
89 DcWriteSia(
90     _In_ PDC21X4_ADAPTER Adapter,
91     _In_ ULONG Csr13,
92     _In_ ULONG Csr14,
93     _In_ ULONG Csr15)
94 {
95     ULONG SiaConn, SiaGen;
96 
97     TRACE("CSR13 %08lx, CSR14 %08lx, CSR15 %08lx\n", Csr13, Csr14, Csr15);
98 
99     SiaConn = 0;
100 
101     /* The 21145 comes with 16 new bits in CSR13 */
102     if (Adapter->Features & DC_SIA_ANALOG_CONTROL)
103     {
104         SiaConn = Adapter->AnalogControl;
105     }
106 
107     /* Reset the transceiver */
108     DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | DC_SIA_CONN_RESET);
109     NdisStallExecution(20);
110 
111     /* Some chips don't have a separate GPIO register */
112     if (Adapter->Features & DC_SIA_GPIO)
113     {
114         SiaGen = Adapter->SiaSetting;
115         SiaGen &= 0xFFFF0000; /* GPIO */
116         SiaGen |= Csr15;      /* SIA */
117         Adapter->SiaSetting = SiaGen;
118     }
119     else
120     {
121         SiaGen = Csr15;
122     }
123 
124     DC_WRITE(Adapter, DcCsr14_SiaTxRx, Csr14);
125     DC_WRITE(Adapter, DcCsr15_SiaGeneral, SiaGen);
126 
127     /* Don't reset the transceiver twice */
128     if (Csr13 == DC_SIA_CONN_RESET)
129         return;
130 
131     DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | Csr13);
132 }
133 
134 VOID
135 DcTestPacket(
136     _In_ PDC21X4_ADAPTER Adapter)
137 {
138     PDC_TCB Tcb;
139     PDC_TBD Tbd;
140     ULONG FrameNumber;
141 
142     Adapter->MediaTestStatus = FALSE;
143     Adapter->ModeFlags |= DC_MODE_TEST_PACKET;
144 
145     if (!Adapter->LoopbackFrameSlots)
146     {
147         ERR("Failed to complete test packets, CSR12 %08lx, CSR5 %08lx\n",
148             DC_READ(Adapter, DcCsr12_SiaStatus),
149             DC_READ(Adapter, DcCsr5_Status));
150 
151         /* Try to recover the lost TX buffers */
152         NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem);
153         return;
154     }
155 
156     --Adapter->LoopbackFrameSlots;
157 
158     FrameNumber = (Adapter->LoopbackFrameNumber++) % DC_LOOPBACK_FRAMES;
159 
160     Tbd = Adapter->CurrentTbd;
161     Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd);
162 
163     Tcb = Adapter->CurrentTcb;
164     Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
165 
166     Tcb->Tbd = Tbd;
167     Tcb->Packet = NULL;
168 
169     ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
170 
171     /* Put the loopback frame on the transmit ring */
172     Tbd->Address1 = Adapter->LoopbackFramePhys[FrameNumber];
173     Tbd->Address2 = 0;
174     Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
175     Tbd->Control |= DC_LOOPBACK_FRAME_SIZE |
176                     DC_TBD_CONTROL_FIRST_FRAGMENT |
177                     DC_TBD_CONTROL_LAST_FRAGMENT |
178                     DC_TBD_CONTROL_REQUEST_INTERRUPT;
179     DC_WRITE_BARRIER();
180     Tbd->Status = DC_TBD_STATUS_OWNED;
181 
182     /* Send the loopback packet to verify connectivity of a media */
183     DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
184 }
185 
186 BOOLEAN
187 DcSetupFrameDownload(
188     _In_ PDC21X4_ADAPTER Adapter,
189     _In_ BOOLEAN WaitForCompletion)
190 {
191     PDC_TCB Tcb;
192     PDC_TBD Tbd;
193     ULONG i, Control;
194 
195     Tbd = Adapter->CurrentTbd;
196 
197     /* Ensure correct setup frame processing */
198     if (Tbd != Adapter->HeadTbd)
199     {
200         ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
201 
202         /* Put the null frame on the transmit ring */
203         Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
204         Tbd->Address1 = 0;
205         Tbd->Address2 = 0;
206         DC_WRITE_BARRIER();
207         Tbd->Status = DC_TBD_STATUS_OWNED;
208 
209         Tbd = DC_NEXT_TBD(Adapter, Tbd);
210     }
211 
212     Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd);
213 
214     Tcb = Adapter->CurrentTcb;
215     Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
216 
217     Tcb->Tbd = Tbd;
218     Tcb->Packet = NULL;
219 
220     ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
221 
222     /* Prepare the setup frame */
223     Tbd->Address1 = Adapter->SetupFramePhys;
224     Tbd->Address2 = 0;
225     Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
226     Control = DC_SETUP_FRAME_SIZE | DC_TBD_CONTROL_SETUP_FRAME;
227     if (!WaitForCompletion)
228         Control |= DC_TBD_CONTROL_REQUEST_INTERRUPT;
229     if (Adapter->ProgramHashPerfectFilter)
230         Control |= DC_TBD_CONTROL_HASH_PERFECT_FILTER;
231     Tbd->Control |= Control;
232     DC_WRITE_BARRIER();
233     Tbd->Status = DC_TBD_STATUS_OWNED;
234 
235     DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
236 
237     if (!WaitForCompletion)
238         return TRUE;
239 
240     /* Wait up to 500 ms for the chip to process the setup frame */
241     for (i = 50000; i > 0; --i)
242     {
243         NdisStallExecution(10);
244 
245         KeMemoryBarrierWithoutFence();
246         if (!(Tbd->Status & DC_TBD_STATUS_OWNED))
247             break;
248     }
249     if (i == 0)
250     {
251         ERR("Failed to complete setup frame %08lx\n", Tbd->Status);
252         return FALSE;
253     }
254 
255     return TRUE;
256 }
257 
258 CODE_SEG("PAGE")
259 VOID
260 DcSetupFrameInitialize(
261     _In_ PDC21X4_ADAPTER Adapter)
262 {
263     PULONG SetupFrame, SetupFrameStart;
264     PUSHORT MacAddress;
265     ULONG i;
266 
267     PAGED_CODE();
268 
269     SetupFrame = Adapter->SetupFrame;
270 
271     /* Add the physical address entry */
272     MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
273     *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
274     *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
275     *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
276 
277     /* Pad to 16 addresses */
278     SetupFrameStart = Adapter->SetupFrame;
279     for (i = 1; i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES; ++i)
280     {
281         *SetupFrame++ = SetupFrameStart[0];
282         *SetupFrame++ = SetupFrameStart[1];
283         *SetupFrame++ = SetupFrameStart[2];
284     }
285 }
286 
287 static
288 VOID
289 DcSetupFramePerfectFiltering(
290     _In_ PDC21X4_ADAPTER Adapter)
291 {
292     PULONG SetupFrame, SetupFrameStart;
293     PUSHORT MacAddress;
294     ULONG i;
295 
296     SetupFrame = Adapter->SetupFrame;
297 
298     /* Add the physical address entry */
299     MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
300     *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
301     *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
302     *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
303 
304     /* Store multicast addresses */
305     for (i = 0; i < Adapter->MulticastCount; ++i)
306     {
307         MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress;
308 
309         *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
310         *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
311         *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
312     }
313 
314     ++i;
315 
316     /* Add the broadcast address entry */
317     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
318     {
319         *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
320         *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
321         *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
322 
323         ++i;
324     }
325 
326     /* Pad to 16 addresses */
327     SetupFrameStart = Adapter->SetupFrame;
328     while (i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES)
329     {
330         *SetupFrame++ = SetupFrameStart[0];
331         *SetupFrame++ = SetupFrameStart[1];
332         *SetupFrame++ = SetupFrameStart[2];
333 
334         ++i;
335     }
336 }
337 
338 static
339 VOID
340 DcSetupFrameImperfectFiltering(
341     _In_ PDC21X4_ADAPTER Adapter)
342 {
343     PULONG SetupFrame = Adapter->SetupFrame;
344     PUSHORT MacAddress;
345     ULONG Hash, i;
346 
347     RtlZeroMemory(SetupFrame, DC_SETUP_FRAME_SIZE);
348 
349     /* Fill up the 512-bit multicast hash table */
350     for (i = 0; i < Adapter->MulticastCount; ++i)
351     {
352         MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress;
353 
354         /* Only need lower 9 bits of the hash */
355         Hash = DcEthernetCrc(MacAddress, ETH_LENGTH_OF_ADDRESS);
356         Hash &= 512 - 1;
357         SetupFrame[Hash / 16] |= 1 << (Hash % 16);
358     }
359 
360     /* Insert the broadcast address hash to the bin */
361     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
362     {
363         Hash = DC_SETUP_FRAME_BROADCAST_HASH;
364         SetupFrame[Hash / 16] |= 1 << (Hash % 16);
365     }
366 
367     /* Add the physical address entry */
368     MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
369     SetupFrame[39] = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
370     SetupFrame[40] = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
371     SetupFrame[41] = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
372 }
373 
374 NDIS_STATUS
375 DcUpdateMulticastList(
376     _In_ PDC21X4_ADAPTER Adapter)
377 {
378     BOOLEAN UsePerfectFiltering;
379 
380     /* If more than 14 addresses are requested, switch to hash filtering mode */
381     UsePerfectFiltering = (Adapter->MulticastCount <= DC_SETUP_FRAME_ADDRESSES);
382 
383     Adapter->ProgramHashPerfectFilter = UsePerfectFiltering;
384     Adapter->OidPending = TRUE;
385 
386     if (UsePerfectFiltering)
387         DcSetupFramePerfectFiltering(Adapter);
388     else
389         DcSetupFrameImperfectFiltering(Adapter);
390 
391     NdisAcquireSpinLock(&Adapter->SendLock);
392 
393     DcSetupFrameDownload(Adapter, FALSE);
394 
395     NdisReleaseSpinLock(&Adapter->SendLock);
396 
397     return NDIS_STATUS_PENDING;
398 }
399 
400 NDIS_STATUS
401 DcApplyPacketFilter(
402     _In_ PDC21X4_ADAPTER Adapter,
403     _In_ ULONG PacketFilter)
404 {
405     ULONG OpMode, OldPacketFilter;
406 
407     INFO("Packet filter value 0x%lx\n", PacketFilter);
408 
409     NdisAcquireSpinLock(&Adapter->ModeLock);
410 
411     /* Update the filtering mode */
412     OpMode = Adapter->OpMode;
413     OpMode &= ~(DC_OPMODE_RX_PROMISCUOUS | DC_OPMODE_RX_ALL_MULTICAST);
414     if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
415     {
416         OpMode |= DC_OPMODE_RX_PROMISCUOUS;
417     }
418     else if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
419     {
420         OpMode |= DC_OPMODE_RX_ALL_MULTICAST;
421     }
422     Adapter->OpMode = OpMode;
423     DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
424 
425     NdisReleaseSpinLock(&Adapter->ModeLock);
426 
427     OldPacketFilter = Adapter->PacketFilter;
428     Adapter->PacketFilter = PacketFilter;
429 
430     /* Program the NIC to receive or reject broadcast frames */
431     if ((OldPacketFilter ^ PacketFilter) & NDIS_PACKET_TYPE_BROADCAST)
432     {
433         return DcUpdateMulticastList(Adapter);
434     }
435 
436     return NDIS_STATUS_SUCCESS;
437 }
438 
439 static
440 CODE_SEG("PAGE")
441 VOID
442 DcSoftReset(
443     _In_ PDC21X4_ADAPTER Adapter)
444 {
445     PAGED_CODE();
446 
447     /* Linux driver does this */
448     if (Adapter->Features & DC_HAS_MII)
449     {
450         /* Select the MII/SYM port */
451         DC_WRITE(Adapter, DcCsr6_OpMode, DC_OPMODE_PORT_SELECT);
452     }
453 
454     /* Perform a software reset */
455     DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
456     NdisMSleep(100);
457     DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode);
458 }
459 
460 CODE_SEG("PAGE")
461 NDIS_STATUS
462 DcSetupAdapter(
463     _In_ PDC21X4_ADAPTER Adapter)
464 {
465     PAGED_CODE();
466 
467     DcInitTxRing(Adapter);
468     DcInitRxRing(Adapter);
469 
470     /* Initial values */
471     if (!MEDIA_IS_FIXED(Adapter))
472     {
473         Adapter->LinkSpeedMbps = 10;
474     }
475     Adapter->MediaNumber = Adapter->DefaultMedia;
476     Adapter->ModeFlags &= ~(DC_MODE_PORT_AUTOSENSE | DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED |
477                             DC_MODE_TEST_PACKET | DC_MODE_AUTONEG_MASK);
478 
479     DcSoftReset(Adapter);
480 
481     /* Receive descriptor ring buffer */
482     DC_WRITE(Adapter, DcCsr3_RxRingAddress, Adapter->RbdPhys);
483 
484     /* Transmit descriptor ring buffer */
485     DC_WRITE(Adapter, DcCsr4_TxRingAddress, Adapter->TbdPhys);
486 
487     switch (Adapter->ChipType)
488     {
489         case DC21040:
490         {
491             DcWriteSia(Adapter,
492                        Adapter->Media[Adapter->MediaNumber].Csr13,
493                        Adapter->Media[Adapter->MediaNumber].Csr14,
494                        Adapter->Media[Adapter->MediaNumber].Csr15);
495 
496             /* Explicitly specifed by user */
497             if (Adapter->MediaNumber == MEDIA_10T_FD)
498             {
499                 Adapter->OpMode |= DC_OPMODE_FULL_DUPLEX;
500             }
501             break;
502         }
503 
504         case DC21041:
505         {
506             MediaSiaSelect(Adapter);
507             break;
508         }
509 
510         case DC21140:
511         {
512             if (Adapter->MediaNumber == MEDIA_MII)
513             {
514                 MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP));
515                 MediaMiiSelect(Adapter);
516             }
517             else
518             {
519                 /* All media use the same GPIO directon */
520                 DC_WRITE(Adapter, DcCsr12_Gpio, Adapter->Media[Adapter->MediaNumber].GpioCtrl);
521                 NdisStallExecution(10);
522 
523                 MediaGprSelect(Adapter);
524             }
525             break;
526         }
527 
528         case DC21143:
529         case DC21145:
530         {
531             /* Init the HPNA PHY */
532             if ((Adapter->MediaBitmap & (1 << MEDIA_HMR)) && Adapter->HpnaInitBitmap)
533             {
534                 HpnaPhyInit(Adapter);
535             }
536 
537             if (Adapter->MediaNumber == MEDIA_MII)
538             {
539                 MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP));
540                 MediaMiiSelect(Adapter);
541                 break;
542             }
543 
544             /* If the current media is FX, assume we have a link */
545             if (MEDIA_IS_FX(Adapter->MediaNumber))
546             {
547                 Adapter->LinkUp = TRUE;
548 
549                 NdisMIndicateStatus(Adapter->AdapterHandle,
550                                     NDIS_STATUS_MEDIA_CONNECT,
551                                     NULL,
552                                     0);
553                 NdisMIndicateStatusComplete(Adapter->AdapterHandle);
554             }
555 
556             MediaSiaSelect(Adapter);
557             break;
558         }
559 
560         default:
561             ASSERT(FALSE);
562             UNREACHABLE;
563             break;
564     }
565 
566     /* Start the TX process */
567     Adapter->OpMode |= DC_OPMODE_TX_ENABLE;
568     DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
569 
570     /* Load the address recognition RAM */
571     if (!DcSetupFrameDownload(Adapter, TRUE))
572     {
573         /* This normally should not happen */
574         ASSERT(FALSE);
575 
576         NdisWriteErrorLogEntry(Adapter->AdapterHandle,
577                                NDIS_ERROR_CODE_HARDWARE_FAILURE,
578                                1,
579                                __LINE__);
580 
581         return NDIS_STATUS_HARD_ERRORS;
582     }
583 
584     return NDIS_STATUS_SUCCESS;
585 }
586