1 /** @file
2   Implement the interface to the AX88772 Ethernet controller.
3 
4   This module implements the interface to the ASIX AX88772
5   USB to Ethernet MAC with integrated 10/100 PHY.  Note that this implementation
6   only supports the integrated PHY since no other test cases were available.
7 
8   Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
9   This program and the accompanying materials
10   are licensed and made available under the terms and conditions of the BSD License
11   which accompanies this distribution.  The full text of the license may be found at
12   http://opensource.org/licenses/bsd-license.php
13 
14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 
17 **/
18 
19 #include "Ax88772.h"
20 
21 
22 /**
23   Compute the CRC
24 
25   @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
26 
27   @returns The CRC-32 value associated with this MAC address
28 
29 **/
30 UINT32
Ax88772Crc(IN UINT8 * pMacAddress)31 Ax88772Crc (
32   IN UINT8 * pMacAddress
33   )
34 {
35   UINT32 BitNumber;
36   INT32 Carry;
37   INT32 Crc;
38   UINT32 Data;
39   UINT8 * pEnd;
40 
41   DBG_ENTER ( );
42 
43   //
44   //  Walk the MAC address
45   //
46   Crc = -1;
47   pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];
48   while ( pEnd > pMacAddress ) {
49     Data = *pMacAddress++;
50 
51 
52     //
53     //  CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
54     //
55     //          1 0000 0100 1100 0001 0001 1101 1011 0111
56     //
57     for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) {
58       Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 );
59       Crc <<= 1;
60       if ( 0 != Carry ) {
61         Crc ^= 0x04c11db7;
62       }
63       Data >>= 1;
64     }
65   }
66 
67   //
68   //  Return the CRC value
69   //
70   DBG_EXIT_HEX ( Crc );
71   return (UINT32) Crc;
72 }
73 
74 
75 /**
76   Get the MAC address
77 
78   This routine calls ::Ax88772UsbCommand to request the MAC
79   address from the network adapter.
80 
81   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
82   @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.
83 
84   @retval EFI_SUCCESS          The MAC address is available.
85   @retval other                The MAC address is not valid.
86 
87 **/
88 EFI_STATUS
Ax88772MacAddressGet(IN NIC_DEVICE * pNicDevice,OUT UINT8 * pMacAddress)89 Ax88772MacAddressGet (
90   IN NIC_DEVICE * pNicDevice,
91   OUT UINT8 * pMacAddress
92   )
93 {
94   USB_DEVICE_REQUEST SetupMsg;
95   EFI_STATUS Status;
96 
97   DBG_ENTER ( );
98 
99   //
100   //  Set the register address.
101   //
102   SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
103                        | USB_REQ_TYPE_VENDOR
104                        | USB_TARGET_DEVICE;
105   SetupMsg.Request = CMD_MAC_ADDRESS_READ;
106   SetupMsg.Value = 0;
107   SetupMsg.Index = 0;
108   SetupMsg.Length = PXE_HWADDR_LEN_ETHER;
109 
110   //
111   //  Read the PHY register
112   //
113   Status = Ax88772UsbCommand ( pNicDevice,
114                                &SetupMsg,
115                                pMacAddress );
116 
117   //
118   // Return the operation status
119   //
120   DBG_EXIT_STATUS ( Status );
121   return Status;
122 }
123 
124 
125 /**
126   Set the MAC address
127 
128   This routine calls ::Ax88772UsbCommand to set the MAC address
129   in the network adapter.
130 
131   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
132   @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.
133 
134   @retval EFI_SUCCESS          The MAC address was set.
135   @retval other                The MAC address was not set.
136 
137 **/
138 EFI_STATUS
Ax88772MacAddressSet(IN NIC_DEVICE * pNicDevice,IN UINT8 * pMacAddress)139 Ax88772MacAddressSet (
140   IN NIC_DEVICE * pNicDevice,
141   IN UINT8 * pMacAddress
142   )
143 {
144   USB_DEVICE_REQUEST SetupMsg;
145   EFI_STATUS Status;
146 
147   DBG_ENTER ( );
148 
149   //
150   //  Set the register address.
151   //
152   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
153                        | USB_TARGET_DEVICE;
154   SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;
155   SetupMsg.Value = 0;
156   SetupMsg.Index = 0;
157   SetupMsg.Length = PXE_HWADDR_LEN_ETHER;
158 
159   //
160   //  Read the PHY register
161   //
162   Status = Ax88772UsbCommand ( pNicDevice,
163                                &SetupMsg,
164                                pMacAddress );
165 
166   //
167   // Return the operation status
168   //
169   DBG_EXIT_STATUS ( Status );
170   return Status;
171 }
172 
173 
174 /**
175   Clear the multicast hash table
176 
177   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
178 
179 **/
180 VOID
Ax88772MulticastClear(IN NIC_DEVICE * pNicDevice)181 Ax88772MulticastClear (
182   IN NIC_DEVICE * pNicDevice
183   )
184 {
185   DBG_ENTER ( );
186 
187   //
188   // Clear the multicast hash table
189   //
190   pNicDevice->MulticastHash[0] = 0;
191   pNicDevice->MulticastHash[1] = 0;
192 
193   DBG_EXIT ( );
194 }
195 
196 
197 /**
198   Enable a multicast address in the multicast hash table
199 
200   This routine calls ::Ax88772Crc to compute the hash bit for
201   this MAC address.
202 
203   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
204   @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.
205 
206 **/
207 VOID
Ax88772MulticastSet(IN NIC_DEVICE * pNicDevice,IN UINT8 * pMacAddress)208 Ax88772MulticastSet (
209   IN NIC_DEVICE * pNicDevice,
210   IN UINT8 * pMacAddress
211   )
212 {
213   UINT32 BitNumber;
214   UINT32 Crc;
215   UINT32 Mask;
216 
217   DBG_ENTER ( );
218 
219   //
220   //  Compute the CRC on the destination address
221   //
222   Crc = Ax88772Crc ( pMacAddress );
223 
224   //
225   //  Set the bit corresponding to the destination address
226   //
227   BitNumber = Crc >> 26;
228   if ( 32 > BitNumber ) {
229     Mask = 1 << BitNumber;
230     pNicDevice->MulticastHash[0] |= Mask;
231   }
232   else {
233     Mask = 1 << ( BitNumber - 32 );
234     pNicDevice->MulticastHash[1] |= Mask;
235   }
236 
237   //
238   //  Display the multicast address
239   //
240   DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,
241             "Enable multicast: 0x%02x-%02x-%02x-%02x-%02x-%02x, CRC: 0x%08x, Bit number: 0x%02x\r\n",
242             pMacAddress[0],
243             pMacAddress[1],
244             pMacAddress[2],
245             pMacAddress[3],
246             pMacAddress[4],
247             pMacAddress[5],
248             Crc,
249             BitNumber ));
250 
251   DBG_EXIT ( );
252 }
253 
254 
255 /**
256   Start the link negotiation
257 
258   This routine calls ::Ax88772PhyWrite to start the PHY's link
259   negotiation.
260 
261   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
262 
263   @retval EFI_SUCCESS          The link negotiation was started.
264   @retval other                Failed to start the link negotiation.
265 
266 **/
267 EFI_STATUS
Ax88772NegotiateLinkStart(IN NIC_DEVICE * pNicDevice)268 Ax88772NegotiateLinkStart (
269   IN NIC_DEVICE * pNicDevice
270   )
271 {
272   UINT16 Control;
273   EFI_STATUS Status;
274 
275   DBG_ENTER ( );
276 
277   //
278   // Set the supported capabilities.
279   //
280   Status = Ax88772PhyWrite ( pNicDevice,
281                              PHY_ANAR,
282                              AN_CSMA_CD
283                              | AN_TX_FDX | AN_TX_HDX
284                              | AN_10_FDX | AN_10_HDX );
285   if ( !EFI_ERROR ( Status )) {
286     //
287     // Set the link speed and duplex
288     //
289     Control = BMCR_AUTONEGOTIATION_ENABLE
290             | BMCR_RESTART_AUTONEGOTIATION;
291     if ( pNicDevice->b100Mbps ) {
292       Control |= BMCR_100MBPS;
293     }
294     if ( pNicDevice->bFullDuplex ) {
295       Control |= BMCR_FULL_DUPLEX;
296     }
297     Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );
298   }
299 
300   //
301   // Return the operation status
302   //
303   DBG_EXIT_STATUS ( Status );
304   return Status;
305 }
306 
307 
308 /**
309   Complete the negotiation of the PHY link
310 
311   This routine calls ::Ax88772PhyRead to determine if the
312   link negotiation is complete.
313 
314   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
315   @param [in, out] pPollCount  Address of number of times this routine was polled
316   @param [out] pbComplete      Address of boolean to receive complate status.
317   @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.
318   @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.
319   @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.
320 
321   @retval EFI_SUCCESS          The MAC address is available.
322   @retval other                The MAC address is not valid.
323 
324 **/
325 EFI_STATUS
Ax88772NegotiateLinkComplete(IN NIC_DEVICE * pNicDevice,IN OUT UINTN * pPollCount,OUT BOOLEAN * pbComplete,OUT BOOLEAN * pbLinkUp,OUT BOOLEAN * pbHiSpeed,OUT BOOLEAN * pbFullDuplex)326 Ax88772NegotiateLinkComplete (
327   IN NIC_DEVICE * pNicDevice,
328   IN OUT UINTN * pPollCount,
329   OUT BOOLEAN * pbComplete,
330   OUT BOOLEAN * pbLinkUp,
331   OUT BOOLEAN * pbHiSpeed,
332   OUT BOOLEAN * pbFullDuplex
333   )
334 {
335   UINT16 Mask;
336   UINT16 PhyData;
337   EFI_STATUS  Status;
338 
339   DBG_ENTER ( );
340 
341   //
342   //  Determine if the link is up.
343   //
344   *pbComplete = FALSE;
345 
346   //
347   //  Get the link status
348   //
349   Status = Ax88772PhyRead ( pNicDevice,
350                             PHY_BMSR,
351                             &PhyData );
352   if ( !EFI_ERROR ( Status )) {
353     //
354     //  Determine if the autonegotiation is complete.
355     //
356     *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));
357     *pbComplete = *pbLinkUp;
358     if ( 0 != *pbComplete ) {
359       //
360       //  Get the partners capabilities.
361       //
362       Status = Ax88772PhyRead ( pNicDevice,
363                                 PHY_ANLPAR,
364                                 &PhyData );
365       if ( !EFI_ERROR ( Status )) {
366         //
367         //  Autonegotiation is complete
368         //  Determine the link speed.
369         //
370         *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));
371 
372         //
373         //  Determine the link duplex.
374         //
375         Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;
376         *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));
377       }
378     }
379   }
380 
381   //
382   // Return the operation status
383   //
384   DBG_EXIT_STATUS ( Status );
385   return Status;
386 }
387 
388 
389 /**
390   Read a register from the PHY
391 
392   This routine calls ::Ax88772UsbCommand to read a PHY register.
393 
394   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
395   @param [in] RegisterAddress  Number of the register to read.
396   @param [in, out] pPhyData    Address of a buffer to receive the PHY register value
397 
398   @retval EFI_SUCCESS          The PHY data is available.
399   @retval other                The PHY data is not valid.
400 
401 **/
402 EFI_STATUS
Ax88772PhyRead(IN NIC_DEVICE * pNicDevice,IN UINT8 RegisterAddress,IN OUT UINT16 * pPhyData)403 Ax88772PhyRead (
404   IN NIC_DEVICE * pNicDevice,
405   IN UINT8 RegisterAddress,
406   IN OUT UINT16 * pPhyData
407   )
408 {
409   USB_DEVICE_REQUEST SetupMsg;
410   EFI_STATUS Status;
411 
412   DBG_ENTER ( );
413 
414   //
415   //  Request access to the PHY
416   //
417   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
418                        | USB_TARGET_DEVICE;
419   SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;
420   SetupMsg.Value = 0;
421   SetupMsg.Index = 0;
422   SetupMsg.Length = 0;
423   Status = Ax88772UsbCommand ( pNicDevice,
424                                &SetupMsg,
425                                NULL );
426   if ( !EFI_ERROR ( Status )) {
427     //
428     //  Read the PHY register address.
429     //
430     SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
431                          | USB_REQ_TYPE_VENDOR
432                          | USB_TARGET_DEVICE;
433     SetupMsg.Request = CMD_PHY_REG_READ;
434     SetupMsg.Value = pNicDevice->PhyId;
435     SetupMsg.Index = RegisterAddress;
436     SetupMsg.Length = sizeof ( *pPhyData );
437     Status = Ax88772UsbCommand ( pNicDevice,
438                                  &SetupMsg,
439                                  pPhyData );
440     if ( !EFI_ERROR ( Status )) {
441       DEBUG (( DEBUG_PHY | DEBUG_INFO,
442                 "PHY %d: 0x%02x --> 0x%04x\r\n",
443                 pNicDevice->PhyId,
444                 RegisterAddress,
445                 *pPhyData ));
446 
447       //
448       //  Release the PHY to the hardware
449       //
450       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
451                            | USB_TARGET_DEVICE;
452       SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
453       SetupMsg.Value = 0;
454       SetupMsg.Index = 0;
455       SetupMsg.Length = 0;
456       Status = Ax88772UsbCommand ( pNicDevice,
457                                    &SetupMsg,
458                                    NULL );
459     }
460   }
461 
462   //
463   //  Return the operation status.
464   //
465   DBG_EXIT_STATUS ( Status );
466   return Status;
467 }
468 
469 
470 /**
471   Write to a PHY register
472 
473   This routine calls ::Ax88772UsbCommand to write a PHY register.
474 
475   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
476   @param [in] RegisterAddress  Number of the register to read.
477   @param [in] PhyData          Address of a buffer to receive the PHY register value
478 
479   @retval EFI_SUCCESS          The PHY data was written.
480   @retval other                Failed to wwrite the PHY register.
481 
482 **/
483 EFI_STATUS
Ax88772PhyWrite(IN NIC_DEVICE * pNicDevice,IN UINT8 RegisterAddress,IN UINT16 PhyData)484 Ax88772PhyWrite (
485   IN NIC_DEVICE * pNicDevice,
486   IN UINT8 RegisterAddress,
487   IN UINT16 PhyData
488   )
489 {
490   USB_DEVICE_REQUEST SetupMsg;
491   EFI_STATUS Status;
492 
493   DBG_ENTER ( );
494 
495   //
496   //  Request access to the PHY
497   //
498   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
499                        | USB_TARGET_DEVICE;
500   SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;
501   SetupMsg.Value = 0;
502   SetupMsg.Index = 0;
503   SetupMsg.Length = 0;
504   Status = Ax88772UsbCommand ( pNicDevice,
505                                &SetupMsg,
506                                NULL );
507   if ( !EFI_ERROR ( Status )) {
508     //
509     //  Write the PHY register
510     //
511     SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
512                          | USB_TARGET_DEVICE;
513     SetupMsg.Request = CMD_PHY_REG_WRITE;
514     SetupMsg.Value = pNicDevice->PhyId;
515     SetupMsg.Index = RegisterAddress;
516     SetupMsg.Length = sizeof ( PhyData );
517     Status = Ax88772UsbCommand ( pNicDevice,
518                                  &SetupMsg,
519                                  &PhyData );
520     if ( !EFI_ERROR ( Status )) {
521       DEBUG (( DEBUG_PHY | DEBUG_INFO,
522                 "PHY %d: 0x%02x <-- 0x%04x\r\n",
523                 pNicDevice->PhyId,
524                 RegisterAddress,
525                 PhyData ));
526 
527       //
528       //  Release the PHY to the hardware
529       //
530       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
531                            | USB_TARGET_DEVICE;
532       SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;
533       SetupMsg.Value = 0;
534       SetupMsg.Index = 0;
535       SetupMsg.Length = 0;
536       Status = Ax88772UsbCommand ( pNicDevice,
537                                    &SetupMsg,
538                                    NULL );
539     }
540   }
541 
542   //
543   //  Return the operation status.
544   //
545   DBG_EXIT_STATUS ( Status );
546   return Status;
547 }
548 
549 
550 /**
551   Reset the AX88772
552 
553   This routine uses ::Ax88772UsbCommand to reset the network
554   adapter.  This routine also uses ::Ax88772PhyWrite to reset
555   the PHY.
556 
557   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
558 
559   @retval EFI_SUCCESS          The MAC address is available.
560   @retval other                The MAC address is not valid.
561 
562 **/
563 EFI_STATUS
Ax88772Reset(IN NIC_DEVICE * pNicDevice)564 Ax88772Reset (
565   IN NIC_DEVICE * pNicDevice
566   )
567 {
568   USB_DEVICE_REQUEST SetupMsg;
569   EFI_STATUS Status;
570 
571   DBG_ENTER ( );
572 
573   //
574   //  Turn off the MAC
575   //
576   SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
577                        | USB_TARGET_DEVICE;
578   SetupMsg.Request = CMD_RX_CONTROL_WRITE;
579   SetupMsg.Value = 0;
580   SetupMsg.Index = 0;
581   SetupMsg.Length = 0;
582   Status = Ax88772UsbCommand ( pNicDevice,
583                                &SetupMsg,
584                                NULL );
585   if ( !EFI_ERROR ( Status )) {
586     DEBUG (( DEBUG_PHY | DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST
587               | DEBUG_RX_UNICAST | DEBUG_TX | DEBUG_INFO,
588               "MAC reset\r\n" ));
589 
590     //
591     //  The link is now idle
592     //
593     pNicDevice->bLinkIdle = TRUE;
594 
595     //
596     //  Delay for a bit
597     //
598     gBS->Stall ( RESET_MSEC );
599 
600     //
601     //  Select the internal PHY
602     //
603     SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
604                          | USB_TARGET_DEVICE;
605     SetupMsg.Request = CMD_PHY_SELECT;
606     SetupMsg.Value = SPHY_PSEL;
607     SetupMsg.Index = 0;
608     SetupMsg.Length = 0;
609     Status = Ax88772UsbCommand ( pNicDevice,
610                                  &SetupMsg,
611                                  NULL );
612     if ( !EFI_ERROR ( Status )) {
613       //
614       //  Delay for a bit
615       //
616       gBS->Stall ( PHY_RESET_MSEC );
617 
618       //
619       //  Clear the internal PHY reset
620       //
621       SetupMsg.Request = CMD_RESET;
622       SetupMsg.Value = SRR_IPRL | SRR_PRL;
623       Status = Ax88772UsbCommand ( pNicDevice,
624                                    &SetupMsg,
625                                    NULL );
626       if ( !EFI_ERROR ( Status )) {
627         //
628         //  Reset the PHY
629         //
630         Status = Ax88772PhyWrite ( pNicDevice,
631                                    PHY_BMCR,
632                                    BMCR_RESET );
633         if ( !EFI_ERROR ( Status )) {
634           //
635           //  Set the gaps
636           //
637           SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
638                                | USB_TARGET_DEVICE;
639           SetupMsg.Request = CMD_GAPS_WRITE;
640           SetupMsg.Value = 0x0c15;
641           SetupMsg.Index = 0x0e;
642           SetupMsg.Length = 0;
643           Status = Ax88772UsbCommand ( pNicDevice,
644                                        &SetupMsg,
645                                        NULL );
646         }
647       }
648     }
649   }
650 
651   //
652   //  Return the operation status.
653   //
654   DBG_EXIT_STATUS ( Status );
655   return Status;
656 }
657 
658 
659 VOID
FillPkt2Queue(IN NIC_DEVICE * pNicDevice,IN UINTN BufLength)660 FillPkt2Queue (
661   IN NIC_DEVICE * pNicDevice,
662   IN UINTN BufLength)
663 {
664 
665   UINT16 * pLength;
666   UINT16 * pLengthBar;
667   UINT8* pData;
668   UINT32 offset;
669   RX_TX_PACKET * pRxPacket;
670   EFI_STATUS Status;
671 
672   for ( offset = 0; offset < BufLength; ){
673     pLength = (UINT16*) (pNicDevice->pBulkInBuff + offset);
674     pLengthBar = (UINT16*) (pNicDevice->pBulkInBuff + offset +2);
675 
676     *pLength &= 0x7ff;
677     *pLengthBar &= 0x7ff;
678     *pLengthBar |= 0xf800;
679 
680     if ((*pLength ^ *pLengthBar ) != 0xFFFF) {
681       DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength = %d\n", BufLength));
682       return;
683     }
684 
685     pRxPacket = pNicDevice->pRxFree;
686     if ( NULL == pRxPacket ) {
687       Status = gBS->AllocatePool ( EfiRuntimeServicesData,
688                                    sizeof( RX_TX_PACKET ),
689                                    (VOID **) &pRxPacket );
690       if ( !EFI_ERROR ( Status )) {
691         //
692         //  Add this packet to the free packet list
693         //
694         pNicDevice->pRxFree = pRxPacket;
695         pRxPacket->pNext = NULL;
696       }
697       else {
698         //
699         //  Use the discard packet buffer
700         //
701         //pRxPacket = &Packet;
702       }
703     }
704 
705 
706     pData = pNicDevice->pBulkInBuff + offset + 4;
707     pRxPacket->Length = *pLength;
708     pRxPacket->LengthBar = *(UINT16*) (pNicDevice->pBulkInBuff + offset +2);
709     CopyMem (&pRxPacket->Data[0], pData, *pLength);
710     //DEBUG((DEBUG_INFO, "Packet [%d]\n", *pLength));
711 
712     pNicDevice->pRxFree = pRxPacket->pNext;
713     pRxPacket->pNext = NULL;
714 
715     if ( NULL == pNicDevice->pRxTail ) {
716       pNicDevice->pRxHead = pRxPacket;
717     }
718     else {
719       pNicDevice->pRxTail->pNext = pRxPacket;
720     }
721     pNicDevice->pRxTail = pRxPacket;
722     offset += (*pLength + 4);
723 
724   }
725 }
726 
727 
728 
729 /**
730   Receive a frame from the network.
731 
732   This routine polls the USB receive interface for a packet.  If a packet
733   is available, this routine adds the receive packet to the list of
734   pending receive packets.
735 
736   This routine calls ::Ax88772NegotiateLinkComplete to verify
737   that the link is up.  This routine also calls ::SN_Reset to
738   reset the network adapter when necessary.  Finally this
739   routine attempts to receive one or more packets from the
740   network adapter.
741 
742   @param [in] pNicDevice  Pointer to the NIC_DEVICE structure
743   @param [in] bUpdateLink TRUE = Update link status
744 
745 **/
746 VOID
Ax88772Rx(IN NIC_DEVICE * pNicDevice,IN BOOLEAN bUpdateLink)747 Ax88772Rx (
748   IN NIC_DEVICE * pNicDevice,
749   IN BOOLEAN bUpdateLink
750   )
751 {
752   BOOLEAN bFullDuplex;
753   BOOLEAN bLinkUp;
754   BOOLEAN bRxPacket;
755   BOOLEAN bSpeed100;
756   UINTN LengthInBytes;
757   RX_TX_PACKET Packet;
758   RX_TX_PACKET * pRxPacket;
759   EFI_USB_IO_PROTOCOL *pUsbIo;
760   EFI_STATUS Status;
761   EFI_TPL TplPrevious;
762   UINT32 TransferStatus;
763 
764   //
765   //  Synchronize with Ax88772Timer
766   //
767   VERIFY_TPL ( TPL_AX88772 );
768   TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );
769   DEBUG (( DEBUG_TPL | DEBUG_INFO,
770             "%d: TPL\r\n",
771             TPL_AX88772 ));
772 
773   //
774   //  Get the link status
775   //
776   if ( bUpdateLink ) {
777     bLinkUp = pNicDevice->bLinkUp;
778     bSpeed100 = pNicDevice->b100Mbps;
779     bFullDuplex = pNicDevice->bFullDuplex;
780     Status = Ax88772NegotiateLinkComplete ( pNicDevice,
781                                             &pNicDevice->PollCount,
782                                             &pNicDevice->bComplete,
783                                             &pNicDevice->bLinkUp,
784                                             &pNicDevice->b100Mbps,
785                                             &pNicDevice->bFullDuplex );
786 
787     //
788     // Determine if the autonegotiation is complete
789     //
790     if ( pNicDevice->bComplete ) {
791       if ( pNicDevice->bLinkUp ) {
792         if (( bSpeed100 && ( !pNicDevice->b100Mbps ))
793           || (( !bSpeed100 ) && pNicDevice->b100Mbps )
794           || ( bFullDuplex && ( !pNicDevice->bFullDuplex ))
795           || (( !bFullDuplex ) && pNicDevice->bFullDuplex )) {
796           pNicDevice->PollCount = 0;
797           DEBUG (( DEBUG_LINK | DEBUG_INFO,
798                     "Reset to establish proper link setup: %d Mbps, %s duplex\r\n",
799                     pNicDevice->b100Mbps ? 100 : 10,
800                     pNicDevice->bFullDuplex ? L"Full" : L"Half" ));
801           Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );
802         }
803         if (( !bLinkUp ) && pNicDevice->bLinkUp ) {
804           //
805           // Display the autonegotiation status
806           //
807           DEBUG (( DEBUG_LINK | DEBUG_INFO,
808                     "Link: Up, %d Mbps, %s duplex\r\n",
809                     pNicDevice->b100Mbps ? 100 : 10,
810                     pNicDevice->bFullDuplex ? L"Full" : L"Half" ));
811         }
812       }
813     }
814 
815     //
816     //  Update the link status
817     //
818     if ( bLinkUp && ( !pNicDevice->bLinkUp )) {
819       DEBUG (( DEBUG_LINK | DEBUG_INFO, "Link: Down\r\n" ));
820     }
821   }
822 
823   //
824   //  Loop until all the packets are emptied from the receiver
825   //
826   do {
827     bRxPacket = FALSE;
828 
829     //
830     //  Locate a packet for use
831     //
832     pRxPacket = pNicDevice->pRxFree;
833     LengthInBytes = MAX_BULKIN_SIZE;
834     if ( NULL == pRxPacket ) {
835       Status = gBS->AllocatePool ( EfiRuntimeServicesData,
836                                    sizeof ( *pRxPacket ),
837                                    (VOID **) &pRxPacket );
838       if ( !EFI_ERROR ( Status )) {
839         //
840         //  Add this packet to the free packet list
841         //
842         pNicDevice->pRxFree = pRxPacket;
843         pRxPacket->pNext = NULL;
844       }
845       else {
846         //
847         //  Use the discard packet buffer
848         //
849         pRxPacket = &Packet;
850       }
851     }
852 
853     //
854     //  Attempt to receive a packet
855     //
856     SetMem (&pNicDevice->pBulkInBuff[0], MAX_BULKIN_SIZE, 0);
857     pUsbIo = pNicDevice->pUsbIo;
858     Status = pUsbIo->UsbBulkTransfer ( pUsbIo,
859                                        USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,
860                                        &pNicDevice->pBulkInBuff[0],
861                                        &LengthInBytes,
862                                        2,
863                                        &TransferStatus );
864     if ( LengthInBytes > 0 ) {
865       FillPkt2Queue(pNicDevice, LengthInBytes);
866     }
867     pRxPacket = pNicDevice->pRxHead;
868     if (( !EFI_ERROR ( Status ))
869       && ( 0 < pRxPacket->Length )
870       && ( pRxPacket->Length <= sizeof ( pRxPacket->Data ))
871       && ( LengthInBytes > 0)) {
872 
873       //
874       //  Determine if the packet should be received
875       //
876       bRxPacket = TRUE;
877       LengthInBytes = pRxPacket->Length;
878       pNicDevice->bLinkIdle = FALSE;
879       if ( pNicDevice->pRxFree == pRxPacket ) {
880         //
881         //  Display the received packet
882         //
883         if ( 0 != ( pRxPacket->Data[0] & 1 )) {
884           if (( 0xff == pRxPacket->Data[0])
885             && ( 0xff == pRxPacket->Data[1])
886             && ( 0xff == pRxPacket->Data[2])
887             && ( 0xff == pRxPacket->Data[3])
888             && ( 0xff == pRxPacket->Data[4])
889             && ( 0xff == pRxPacket->Data[5])) {
890             DEBUG (( DEBUG_RX_BROADCAST | DEBUG_INFO,
891                       "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
892                       pRxPacket->Data[0],
893                       pRxPacket->Data[1],
894                       pRxPacket->Data[2],
895                       pRxPacket->Data[3],
896                       pRxPacket->Data[4],
897                       pRxPacket->Data[5],
898                       pRxPacket->Data[6],
899                       pRxPacket->Data[7],
900                       pRxPacket->Data[8],
901                       pRxPacket->Data[9],
902                       pRxPacket->Data[10],
903                       pRxPacket->Data[11],
904                       pRxPacket->Data[12],
905                       pRxPacket->Data[13],
906                       LengthInBytes ));
907           }
908           else {
909             DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,
910                       "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
911                       pRxPacket->Data[0],
912                       pRxPacket->Data[1],
913                       pRxPacket->Data[2],
914                       pRxPacket->Data[3],
915                       pRxPacket->Data[4],
916                       pRxPacket->Data[5],
917                       pRxPacket->Data[6],
918                       pRxPacket->Data[7],
919                       pRxPacket->Data[8],
920                       pRxPacket->Data[9],
921                       pRxPacket->Data[10],
922                       pRxPacket->Data[11],
923                       pRxPacket->Data[12],
924                       pRxPacket->Data[13],
925                       LengthInBytes ));
926           }
927         }
928         else {
929           DEBUG (( DEBUG_RX_UNICAST | DEBUG_INFO,
930                     "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
931                     pRxPacket->Data[0],
932                     pRxPacket->Data[1],
933                     pRxPacket->Data[2],
934                     pRxPacket->Data[3],
935                     pRxPacket->Data[4],
936                     pRxPacket->Data[5],
937                     pRxPacket->Data[6],
938                     pRxPacket->Data[7],
939                     pRxPacket->Data[8],
940                     pRxPacket->Data[9],
941                     pRxPacket->Data[10],
942                     pRxPacket->Data[11],
943                     pRxPacket->Data[12],
944                     pRxPacket->Data[13],
945                     LengthInBytes ));
946         }
947 
948       }
949       else {
950         //
951         //  Error, not enough buffers for this packet, discard packet
952         //
953         DEBUG (( DEBUG_WARN | DEBUG_INFO,
954                   "WARNING - No buffer, discarding RX packet: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
955                   pRxPacket->Data[0],
956                   pRxPacket->Data[1],
957                   pRxPacket->Data[2],
958                   pRxPacket->Data[3],
959                   pRxPacket->Data[4],
960                   pRxPacket->Data[5],
961                   pRxPacket->Data[6],
962                   pRxPacket->Data[7],
963                   pRxPacket->Data[8],
964                   pRxPacket->Data[9],
965                   pRxPacket->Data[10],
966                   pRxPacket->Data[11],
967                   pRxPacket->Data[12],
968                   pRxPacket->Data[13],
969                   LengthInBytes ));
970       }
971     }
972   }while ( bRxPacket );
973 
974   //
975   //  Release the synchronization withhe Ax88772Timer
976   //
977   gBS->RestoreTPL ( TplPrevious );
978   DEBUG (( DEBUG_TPL | DEBUG_INFO,
979             "%d: TPL\r\n",
980             TplPrevious ));
981 }
982 
983 
984 /**
985   Enable or disable the receiver
986 
987   This routine calls ::Ax88772UsbCommand to update the
988   receiver state.  This routine also calls ::Ax88772MacAddressSet
989   to establish the MAC address for the network adapter.
990 
991   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
992   @param [in] RxFilter         Simple network RX filter mask value
993 
994   @retval EFI_SUCCESS          The MAC address was set.
995   @retval other                The MAC address was not set.
996 
997 **/
998 EFI_STATUS
Ax88772RxControl(IN NIC_DEVICE * pNicDevice,IN UINT32 RxFilter)999 Ax88772RxControl (
1000   IN NIC_DEVICE * pNicDevice,
1001   IN UINT32 RxFilter
1002   )
1003 {
1004   UINT16 MediumStatus;
1005   INT32 MulticastHash[2];
1006   UINT16 RxControl;
1007   USB_DEVICE_REQUEST SetupMsg;
1008   EFI_STATUS Status;
1009 
1010   DBG_ENTER ( );
1011 
1012   //
1013   //  Disable all multicast
1014   //
1015   MulticastHash[0] = 0;
1016   MulticastHash[1] = 0;
1017 
1018   //
1019   // Enable the receiver if something is to be received
1020   //
1021   Status = EFI_SUCCESS;
1022   RxControl = RXC_SO | RXC_MFB_16384;
1023   if ( 0 != RxFilter ) {
1024     //
1025     //  Enable the receiver
1026     //
1027     SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
1028                          | USB_REQ_TYPE_VENDOR
1029                          | USB_TARGET_DEVICE;
1030     SetupMsg.Request = CMD_MEDIUM_STATUS_READ;
1031     SetupMsg.Value = 0;
1032     SetupMsg.Index = 0;
1033     SetupMsg.Length = sizeof ( MediumStatus );
1034     Status = Ax88772UsbCommand ( pNicDevice,
1035                                  &SetupMsg,
1036                                  &MediumStatus );
1037     if ( !EFI_ERROR ( Status )) {
1038       if ( 0 == ( MediumStatus & MS_RE )) {
1039         MediumStatus |= MS_RE | MS_ONE;
1040         if ( pNicDevice->bFullDuplex ) {
1041           MediumStatus |= MS_TFC | MS_RFC;
1042         }
1043         SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
1044                              | USB_TARGET_DEVICE;
1045         SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;
1046         SetupMsg.Value = MediumStatus;
1047         SetupMsg.Index = 0;
1048         SetupMsg.Length = 0;
1049         Status = Ax88772UsbCommand ( pNicDevice,
1050                                      &SetupMsg,
1051                                      NULL );
1052         if ( EFI_ERROR ( Status )) {
1053           DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1054                     "ERROR - Failed to enable receiver, Status: %r\r\n",
1055                     Status ));
1056         }
1057       }
1058     }
1059     else {
1060       DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1061                 "ERROR - Failed to read receiver status, Status: %r\r\n",
1062                 Status ));
1063     }
1064 
1065     //
1066     //  Enable multicast if requested
1067     //
1068     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {
1069       RxControl |= RXC_AM;
1070       MulticastHash[0] = pNicDevice->MulticastHash[0];
1071       MulticastHash[1] = pNicDevice->MulticastHash[1];
1072     }
1073 
1074     //
1075     //  Enable all multicast if requested
1076     //
1077     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {
1078       RxControl |= RXC_AMALL;
1079       MulticastHash[0] = -1;
1080       MulticastHash[1] = -1;
1081     }
1082 
1083     //
1084     //  Enable broadcast if requested
1085     //
1086     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {
1087       RxControl |= RXC_AB;
1088     }
1089 
1090     //
1091     //  Enable promiscuous mode if requested
1092     //
1093     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {
1094       RxControl |= RXC_PRO;
1095       MulticastHash[0] = -1;
1096       MulticastHash[1] = -1;
1097     }
1098   }
1099 
1100   //
1101   //  Update the MAC address
1102   //
1103   if ( !EFI_ERROR ( Status )) {
1104     Status = Ax88772MacAddressSet ( pNicDevice, &pNicDevice->SimpleNetworkData.CurrentAddress.Addr[0]);
1105   }
1106 
1107   //
1108   //  Update the receiver control
1109   //
1110   if ( !EFI_ERROR ( Status )) {
1111     SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
1112                          | USB_TARGET_DEVICE;
1113     SetupMsg.Request = CMD_RX_CONTROL_WRITE;
1114     SetupMsg.Value = RxControl;
1115     SetupMsg.Index = 0;
1116     SetupMsg.Length = 0;
1117     Status = Ax88772UsbCommand ( pNicDevice,
1118                                  &SetupMsg,
1119                                  NULL );
1120     if ( !EFI_ERROR ( Status )) {
1121       DEBUG (( DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST | DEBUG_RX_UNICAST | DEBUG_INFO,
1122                 "RxControl: 0x%04x\r\n",
1123                 RxControl ));
1124 
1125       //
1126       //  Update the multicast hash table
1127       //
1128       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
1129                            | USB_TARGET_DEVICE;
1130       SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;
1131       SetupMsg.Value = 0;
1132       SetupMsg.Index = 0;
1133       SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );
1134       Status = Ax88772UsbCommand ( pNicDevice,
1135                                    &SetupMsg,
1136                                    &pNicDevice->MulticastHash );
1137       if ( !EFI_ERROR ( Status )) {
1138         DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,
1139                   "Multicast Hash: 0x%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
1140                   (UINT8) MulticastHash[0],
1141                   (UINT8)( MulticastHash[0] >> 8 ),
1142                   (UINT8)( MulticastHash[0] >> 16 ),
1143                   (UINT8)( MulticastHash[0] >> 24 ),
1144                   (UINT8) MulticastHash[1],
1145                   (UINT8)( MulticastHash[1] >> 8 ),
1146                   (UINT8)( MulticastHash[1] >> 16 ),
1147                   (UINT8)( MulticastHash[1] >> 24 )));
1148       }
1149       else {
1150         DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1151                   "ERROR - Failed to update multicast hash table, Status: %r\r\n",
1152                   Status ));
1153       }
1154     }
1155     else {
1156       DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1157                 "ERROR - Failed to set receiver control, Status: %r\r\n",
1158                 Status ));
1159     }
1160   }
1161 
1162   //
1163   // Return the operation status
1164   //
1165   DBG_EXIT_STATUS ( Status );
1166   return Status;
1167 }
1168 
1169 
1170 /**
1171   Read an SROM location
1172 
1173   This routine calls ::Ax88772UsbCommand to read data from the
1174   SROM.
1175 
1176   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
1177   @param [in] Address          SROM address
1178   @param [out] pData           Buffer to receive the data
1179 
1180   @retval EFI_SUCCESS          The read was successful
1181   @retval other                The read failed
1182 
1183 **/
1184 EFI_STATUS
Ax88772SromRead(IN NIC_DEVICE * pNicDevice,IN UINT32 Address,OUT UINT16 * pData)1185 Ax88772SromRead (
1186   IN NIC_DEVICE * pNicDevice,
1187   IN UINT32 Address,
1188   OUT UINT16 * pData
1189   )
1190 {
1191   USB_DEVICE_REQUEST SetupMsg;
1192   EFI_STATUS Status;
1193 
1194   DBG_ENTER ( );
1195 
1196   //
1197   //  Read a value from the SROM
1198   //
1199   SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
1200                        | USB_REQ_TYPE_VENDOR
1201                        | USB_TARGET_DEVICE;
1202   SetupMsg.Request = CMD_SROM_READ;
1203   SetupMsg.Value = (UINT16) Address;
1204   SetupMsg.Index = 0;
1205   SetupMsg.Length = sizeof ( *pData );
1206   Status = Ax88772UsbCommand ( pNicDevice,
1207                                &SetupMsg,
1208                                pData );
1209 
1210   //
1211   // Return the operation status
1212   //
1213   DBG_EXIT_STATUS ( Status );
1214   return Status;
1215 }
1216 
1217 
1218 /**
1219   This routine is called at a regular interval to poll for
1220   receive packets.
1221 
1222   This routine polls the link state and gets any receive packets
1223   by calling ::Ax88772Rx.
1224 
1225   @param [in] Event            Timer event
1226   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
1227 
1228 **/
1229 VOID
Ax88772Timer(IN EFI_EVENT Event,IN NIC_DEVICE * pNicDevice)1230 Ax88772Timer (
1231   IN EFI_EVENT Event,
1232   IN NIC_DEVICE * pNicDevice
1233   )
1234 {
1235   //
1236   //  Use explicit DEBUG messages since the output frequency is too
1237   //  high for DEBUG_INFO to keep up and have spare cycles for the
1238   //  shell
1239   //
1240   DEBUG (( DEBUG_TIMER, "Entering Ax88772Timer\r\n" ));
1241 
1242   //
1243   //  Poll the link state and get any receive packets
1244   //
1245   Ax88772Rx ( pNicDevice, FALSE );
1246 
1247   DEBUG (( DEBUG_TIMER, "Exiting Ax88772Timer\r\n" ));
1248 }
1249 
1250 
1251 /**
1252   Send a command to the USB device.
1253 
1254   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
1255   @param [in] pRequest         Pointer to the request structure
1256   @param [in, out] pBuffer     Data buffer address
1257 
1258   @retval EFI_SUCCESS          The USB transfer was successful
1259   @retval other                The USB transfer failed
1260 
1261 **/
1262 EFI_STATUS
Ax88772UsbCommand(IN NIC_DEVICE * pNicDevice,IN USB_DEVICE_REQUEST * pRequest,IN OUT VOID * pBuffer)1263 Ax88772UsbCommand (
1264   IN NIC_DEVICE * pNicDevice,
1265   IN USB_DEVICE_REQUEST * pRequest,
1266   IN OUT VOID * pBuffer
1267   )
1268 {
1269   UINT32 CmdStatus;
1270   EFI_USB_DATA_DIRECTION Direction;
1271   EFI_USB_IO_PROTOCOL * pUsbIo;
1272   EFI_STATUS Status;
1273 
1274   DBG_ENTER ( );
1275 
1276   //
1277   // Determine the transfer direction
1278   //
1279   Direction = EfiUsbNoData;
1280   if ( 0 != pRequest->Length ) {
1281     Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))
1282               ? EfiUsbDataIn : EfiUsbDataOut;
1283   }
1284 
1285   //
1286   // Issue the command
1287   //
1288   pUsbIo = pNicDevice->pUsbIo;
1289   Status = pUsbIo->UsbControlTransfer ( pUsbIo,
1290                                         pRequest,
1291                                         Direction,
1292                                         USB_BUS_TIMEOUT,
1293                                         pBuffer,
1294                                         pRequest->Length,
1295                                         &CmdStatus );
1296 
1297   //
1298   // Determine the operation status
1299   //
1300   if ( !EFI_ERROR ( Status )) {
1301     Status = CmdStatus;
1302   }
1303   else {
1304     //
1305     // Display any errors
1306     //
1307     DEBUG (( DEBUG_INFO,
1308               "Ax88772UsbCommand - Status: %r\n",
1309               Status ));
1310 
1311     //
1312     // Only use status values associated with the Simple Network protocol
1313     //
1314     if ( EFI_TIMEOUT == Status ) {
1315       Status = EFI_DEVICE_ERROR;
1316     }
1317   }
1318 
1319   //
1320   // Return the operation status
1321   //
1322   DBG_EXIT_STATUS ( Status );
1323   return Status;
1324 }
1325