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