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