• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   UINTN LengthInBytes;
671   EFI_STATUS Status;
672 
673   for ( offset = 0; offset < BufLength; ){
674     pLength = (UINT16*) (pNicDevice->pBulkInBuff + offset);
675     pLengthBar = (UINT16*) (pNicDevice->pBulkInBuff + offset +2);
676 
677     *pLength &= 0x7ff;
678     *pLengthBar &= 0x7ff;
679     *pLengthBar |= 0xf800;
680 
681     if ((*pLength ^ *pLengthBar ) != 0xFFFF) {
682       DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength = %d\n", BufLength));
683       return;
684     }
685 
686     pRxPacket = pNicDevice->pRxFree;
687     LengthInBytes = sizeof ( *pRxPacket ) - sizeof ( pRxPacket->pNext );
688     if ( NULL == pRxPacket ) {
689       Status = gBS->AllocatePool ( EfiRuntimeServicesData,
690                                    sizeof( RX_TX_PACKET ),
691                                    (VOID **) &pRxPacket );
692       if ( !EFI_ERROR ( Status )) {
693         //
694         //  Add this packet to the free packet list
695         //
696         pNicDevice->pRxFree = pRxPacket;
697         pRxPacket->pNext = NULL;
698       }
699       else {
700         //
701         //  Use the discard packet buffer
702         //
703         //pRxPacket = &Packet;
704       }
705     }
706 
707 
708     pData = pNicDevice->pBulkInBuff + offset + 4;
709     pRxPacket->Length = *pLength;
710     pRxPacket->LengthBar = *(UINT16*) (pNicDevice->pBulkInBuff + offset +2);
711     CopyMem (&pRxPacket->Data[0], pData, *pLength);
712     //DEBUG((DEBUG_INFO, "Packet [%d]\n", *pLength));
713 
714     pNicDevice->pRxFree = pRxPacket->pNext;
715     pRxPacket->pNext = NULL;
716 
717     if ( NULL == pNicDevice->pRxTail ) {
718       pNicDevice->pRxHead = pRxPacket;
719     }
720     else {
721       pNicDevice->pRxTail->pNext = pRxPacket;
722     }
723     pNicDevice->pRxTail = pRxPacket;
724     offset += (*pLength + 4);
725 
726   }
727 }
728 
729 
730 
731 /**
732   Receive a frame from the network.
733 
734   This routine polls the USB receive interface for a packet.  If a packet
735   is available, this routine adds the receive packet to the list of
736   pending receive packets.
737 
738   This routine calls ::Ax88772NegotiateLinkComplete to verify
739   that the link is up.  This routine also calls ::SN_Reset to
740   reset the network adapter when necessary.  Finally this
741   routine attempts to receive one or more packets from the
742   network adapter.
743 
744   @param [in] pNicDevice  Pointer to the NIC_DEVICE structure
745   @param [in] bUpdateLink TRUE = Update link status
746 
747 **/
748 VOID
Ax88772Rx(IN NIC_DEVICE * pNicDevice,IN BOOLEAN bUpdateLink)749 Ax88772Rx (
750   IN NIC_DEVICE * pNicDevice,
751   IN BOOLEAN bUpdateLink
752   )
753 {
754   BOOLEAN bFullDuplex;
755   BOOLEAN bLinkUp;
756   BOOLEAN bRxPacket;
757   BOOLEAN bSpeed100;
758   UINTN LengthInBytes;
759   RX_TX_PACKET Packet;
760   RX_TX_PACKET * pRxPacket;
761   EFI_USB_IO_PROTOCOL *pUsbIo;
762   EFI_STATUS Status;
763   EFI_TPL TplPrevious;
764   UINT32 TransferStatus;
765 
766   //
767   //  Synchronize with Ax88772Timer
768   //
769   VERIFY_TPL ( TPL_AX88772 );
770   TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );
771   DEBUG (( DEBUG_TPL | DEBUG_INFO,
772             "%d: TPL\r\n",
773             TPL_AX88772 ));
774 
775   //
776   //  Get the link status
777   //
778   if ( bUpdateLink ) {
779     bLinkUp = pNicDevice->bLinkUp;
780     bSpeed100 = pNicDevice->b100Mbps;
781     bFullDuplex = pNicDevice->bFullDuplex;
782     Status = Ax88772NegotiateLinkComplete ( pNicDevice,
783                                             &pNicDevice->PollCount,
784                                             &pNicDevice->bComplete,
785                                             &pNicDevice->bLinkUp,
786                                             &pNicDevice->b100Mbps,
787                                             &pNicDevice->bFullDuplex );
788 
789     //
790     // Determine if the autonegotiation is complete
791     //
792     if ( pNicDevice->bComplete ) {
793       if ( pNicDevice->bLinkUp ) {
794         if (( bSpeed100 && ( !pNicDevice->b100Mbps ))
795           || (( !bSpeed100 ) && pNicDevice->b100Mbps )
796           || ( bFullDuplex && ( !pNicDevice->bFullDuplex ))
797           || (( !bFullDuplex ) && pNicDevice->bFullDuplex )) {
798           pNicDevice->PollCount = 0;
799           DEBUG (( DEBUG_LINK | DEBUG_INFO,
800                     "Reset to establish proper link setup: %d Mbps, %s duplex\r\n",
801                     pNicDevice->b100Mbps ? 100 : 10,
802                     pNicDevice->bFullDuplex ? L"Full" : L"Half" ));
803           Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );
804         }
805         if (( !bLinkUp ) && pNicDevice->bLinkUp ) {
806           //
807           // Display the autonegotiation status
808           //
809           DEBUG (( DEBUG_LINK | DEBUG_INFO,
810                     "Link: Up, %d Mbps, %s duplex\r\n",
811                     pNicDevice->b100Mbps ? 100 : 10,
812                     pNicDevice->bFullDuplex ? L"Full" : L"Half" ));
813         }
814       }
815     }
816 
817     //
818     //  Update the link status
819     //
820     if ( bLinkUp && ( !pNicDevice->bLinkUp )) {
821       DEBUG (( DEBUG_LINK | DEBUG_INFO, "Link: Down\r\n" ));
822     }
823   }
824 
825   //
826   //  Loop until all the packets are emptied from the receiver
827   //
828   do {
829     bRxPacket = FALSE;
830 
831     //
832     //  Locate a packet for use
833     //
834     pRxPacket = pNicDevice->pRxFree;
835     LengthInBytes = MAX_BULKIN_SIZE;
836     if ( NULL == pRxPacket ) {
837       Status = gBS->AllocatePool ( EfiRuntimeServicesData,
838                                    sizeof ( *pRxPacket ),
839                                    (VOID **) &pRxPacket );
840       if ( !EFI_ERROR ( Status )) {
841         //
842         //  Add this packet to the free packet list
843         //
844         pNicDevice->pRxFree = pRxPacket;
845         pRxPacket->pNext = NULL;
846       }
847       else {
848         //
849         //  Use the discard packet buffer
850         //
851         pRxPacket = &Packet;
852       }
853     }
854 
855     //
856     //  Attempt to receive a packet
857     //
858     SetMem (&pNicDevice->pBulkInBuff[0], MAX_BULKIN_SIZE, 0);
859     pUsbIo = pNicDevice->pUsbIo;
860     Status = pUsbIo->UsbBulkTransfer ( pUsbIo,
861                                        USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,
862                                        &pNicDevice->pBulkInBuff[0],
863                                        &LengthInBytes,
864                                        2,
865                                        &TransferStatus );
866     if ( LengthInBytes > 0 ) {
867       FillPkt2Queue(pNicDevice, LengthInBytes);
868     }
869     pRxPacket = pNicDevice->pRxHead;
870     if (( !EFI_ERROR ( Status ))
871       && ( 0 < pRxPacket->Length )
872       && ( pRxPacket->Length <= sizeof ( pRxPacket->Data ))
873       && ( LengthInBytes > 0)) {
874 
875       //
876       //  Determine if the packet should be received
877       //
878       bRxPacket = TRUE;
879       LengthInBytes = pRxPacket->Length;
880       pNicDevice->bLinkIdle = FALSE;
881       if ( pNicDevice->pRxFree == pRxPacket ) {
882         //
883         //  Display the received packet
884         //
885         if ( 0 != ( pRxPacket->Data[0] & 1 )) {
886           if (( 0xff == pRxPacket->Data[0])
887             && ( 0xff == pRxPacket->Data[1])
888             && ( 0xff == pRxPacket->Data[2])
889             && ( 0xff == pRxPacket->Data[3])
890             && ( 0xff == pRxPacket->Data[4])
891             && ( 0xff == pRxPacket->Data[5])) {
892             DEBUG (( DEBUG_RX_BROADCAST | DEBUG_INFO,
893                       "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
894                       pRxPacket->Data[0],
895                       pRxPacket->Data[1],
896                       pRxPacket->Data[2],
897                       pRxPacket->Data[3],
898                       pRxPacket->Data[4],
899                       pRxPacket->Data[5],
900                       pRxPacket->Data[6],
901                       pRxPacket->Data[7],
902                       pRxPacket->Data[8],
903                       pRxPacket->Data[9],
904                       pRxPacket->Data[10],
905                       pRxPacket->Data[11],
906                       pRxPacket->Data[12],
907                       pRxPacket->Data[13],
908                       LengthInBytes ));
909           }
910           else {
911             DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,
912                       "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
913                       pRxPacket->Data[0],
914                       pRxPacket->Data[1],
915                       pRxPacket->Data[2],
916                       pRxPacket->Data[3],
917                       pRxPacket->Data[4],
918                       pRxPacket->Data[5],
919                       pRxPacket->Data[6],
920                       pRxPacket->Data[7],
921                       pRxPacket->Data[8],
922                       pRxPacket->Data[9],
923                       pRxPacket->Data[10],
924                       pRxPacket->Data[11],
925                       pRxPacket->Data[12],
926                       pRxPacket->Data[13],
927                       LengthInBytes ));
928           }
929         }
930         else {
931           DEBUG (( DEBUG_RX_UNICAST | DEBUG_INFO,
932                     "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
933                     pRxPacket->Data[0],
934                     pRxPacket->Data[1],
935                     pRxPacket->Data[2],
936                     pRxPacket->Data[3],
937                     pRxPacket->Data[4],
938                     pRxPacket->Data[5],
939                     pRxPacket->Data[6],
940                     pRxPacket->Data[7],
941                     pRxPacket->Data[8],
942                     pRxPacket->Data[9],
943                     pRxPacket->Data[10],
944                     pRxPacket->Data[11],
945                     pRxPacket->Data[12],
946                     pRxPacket->Data[13],
947                     LengthInBytes ));
948         }
949 
950       }
951       else {
952         //
953         //  Error, not enough buffers for this packet, discard packet
954         //
955         DEBUG (( DEBUG_WARN | DEBUG_INFO,
956                   "WARNING - No buffer, discarding RX packet: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",
957                   pRxPacket->Data[0],
958                   pRxPacket->Data[1],
959                   pRxPacket->Data[2],
960                   pRxPacket->Data[3],
961                   pRxPacket->Data[4],
962                   pRxPacket->Data[5],
963                   pRxPacket->Data[6],
964                   pRxPacket->Data[7],
965                   pRxPacket->Data[8],
966                   pRxPacket->Data[9],
967                   pRxPacket->Data[10],
968                   pRxPacket->Data[11],
969                   pRxPacket->Data[12],
970                   pRxPacket->Data[13],
971                   LengthInBytes ));
972       }
973     }
974   }while ( bRxPacket );
975 
976   //
977   //  Release the synchronization withhe Ax88772Timer
978   //
979   gBS->RestoreTPL ( TplPrevious );
980   DEBUG (( DEBUG_TPL | DEBUG_INFO,
981             "%d: TPL\r\n",
982             TplPrevious ));
983 }
984 
985 
986 /**
987   Enable or disable the receiver
988 
989   This routine calls ::Ax88772UsbCommand to update the
990   receiver state.  This routine also calls ::Ax88772MacAddressSet
991   to establish the MAC address for the network adapter.
992 
993   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
994   @param [in] RxFilter         Simple network RX filter mask value
995 
996   @retval EFI_SUCCESS          The MAC address was set.
997   @retval other                The MAC address was not set.
998 
999 **/
1000 EFI_STATUS
Ax88772RxControl(IN NIC_DEVICE * pNicDevice,IN UINT32 RxFilter)1001 Ax88772RxControl (
1002   IN NIC_DEVICE * pNicDevice,
1003   IN UINT32 RxFilter
1004   )
1005 {
1006   UINT16 MediumStatus;
1007   INT32 MulticastHash[2];
1008   UINT16 RxControl;
1009   USB_DEVICE_REQUEST SetupMsg;
1010   EFI_STATUS Status;
1011 
1012   DBG_ENTER ( );
1013 
1014   //
1015   //  Disable all multicast
1016   //
1017   MulticastHash[0] = 0;
1018   MulticastHash[1] = 0;
1019 
1020   //
1021   // Enable the receiver if something is to be received
1022   //
1023   Status = EFI_SUCCESS;
1024   RxControl = RXC_SO | RXC_MFB_16384;
1025   if ( 0 != RxFilter ) {
1026     //
1027     //  Enable the receiver
1028     //
1029     SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
1030                          | USB_REQ_TYPE_VENDOR
1031                          | USB_TARGET_DEVICE;
1032     SetupMsg.Request = CMD_MEDIUM_STATUS_READ;
1033     SetupMsg.Value = 0;
1034     SetupMsg.Index = 0;
1035     SetupMsg.Length = sizeof ( MediumStatus );
1036     Status = Ax88772UsbCommand ( pNicDevice,
1037                                  &SetupMsg,
1038                                  &MediumStatus );
1039     if ( !EFI_ERROR ( Status )) {
1040       if ( 0 == ( MediumStatus & MS_RE )) {
1041         MediumStatus |= MS_RE | MS_ONE;
1042         if ( pNicDevice->bFullDuplex ) {
1043           MediumStatus |= MS_TFC | MS_RFC;
1044         }
1045         SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
1046                              | USB_TARGET_DEVICE;
1047         SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;
1048         SetupMsg.Value = MediumStatus;
1049         SetupMsg.Index = 0;
1050         SetupMsg.Length = 0;
1051         Status = Ax88772UsbCommand ( pNicDevice,
1052                                      &SetupMsg,
1053                                      NULL );
1054         if ( EFI_ERROR ( Status )) {
1055           DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1056                     "ERROR - Failed to enable receiver, Status: %r\r\n",
1057                     Status ));
1058         }
1059       }
1060     }
1061     else {
1062       DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1063                 "ERROR - Failed to read receiver status, Status: %r\r\n",
1064                 Status ));
1065     }
1066 
1067     //
1068     //  Enable multicast if requested
1069     //
1070     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {
1071       RxControl |= RXC_AM;
1072       MulticastHash[0] = pNicDevice->MulticastHash[0];
1073       MulticastHash[1] = pNicDevice->MulticastHash[1];
1074     }
1075 
1076     //
1077     //  Enable all multicast if requested
1078     //
1079     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {
1080       RxControl |= RXC_AMALL;
1081       MulticastHash[0] = -1;
1082       MulticastHash[1] = -1;
1083     }
1084 
1085     //
1086     //  Enable broadcast if requested
1087     //
1088     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {
1089       RxControl |= RXC_AB;
1090     }
1091 
1092     //
1093     //  Enable promiscuous mode if requested
1094     //
1095     if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {
1096       RxControl |= RXC_PRO;
1097       MulticastHash[0] = -1;
1098       MulticastHash[1] = -1;
1099     }
1100   }
1101 
1102   //
1103   //  Update the MAC address
1104   //
1105   if ( !EFI_ERROR ( Status )) {
1106     Status = Ax88772MacAddressSet ( pNicDevice, &pNicDevice->SimpleNetworkData.CurrentAddress.Addr[0]);
1107   }
1108 
1109   //
1110   //  Update the receiver control
1111   //
1112   if ( !EFI_ERROR ( Status )) {
1113     SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
1114                          | USB_TARGET_DEVICE;
1115     SetupMsg.Request = CMD_RX_CONTROL_WRITE;
1116     SetupMsg.Value = RxControl;
1117     SetupMsg.Index = 0;
1118     SetupMsg.Length = 0;
1119     Status = Ax88772UsbCommand ( pNicDevice,
1120                                  &SetupMsg,
1121                                  NULL );
1122     if ( !EFI_ERROR ( Status )) {
1123       DEBUG (( DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST | DEBUG_RX_UNICAST | DEBUG_INFO,
1124                 "RxControl: 0x%04x\r\n",
1125                 RxControl ));
1126 
1127       //
1128       //  Update the multicast hash table
1129       //
1130       SetupMsg.RequestType = USB_REQ_TYPE_VENDOR
1131                            | USB_TARGET_DEVICE;
1132       SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;
1133       SetupMsg.Value = 0;
1134       SetupMsg.Index = 0;
1135       SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );
1136       Status = Ax88772UsbCommand ( pNicDevice,
1137                                    &SetupMsg,
1138                                    &pNicDevice->MulticastHash );
1139       if ( !EFI_ERROR ( Status )) {
1140         DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,
1141                   "Multicast Hash: 0x%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
1142                   (UINT8) MulticastHash[0],
1143                   (UINT8)( MulticastHash[0] >> 8 ),
1144                   (UINT8)( MulticastHash[0] >> 16 ),
1145                   (UINT8)( MulticastHash[0] >> 24 ),
1146                   (UINT8) MulticastHash[1],
1147                   (UINT8)( MulticastHash[1] >> 8 ),
1148                   (UINT8)( MulticastHash[1] >> 16 ),
1149                   (UINT8)( MulticastHash[1] >> 24 )));
1150       }
1151       else {
1152         DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1153                   "ERROR - Failed to update multicast hash table, Status: %r\r\n",
1154                   Status ));
1155       }
1156     }
1157     else {
1158       DEBUG (( DEBUG_ERROR | DEBUG_INFO,
1159                 "ERROR - Failed to set receiver control, Status: %r\r\n",
1160                 Status ));
1161     }
1162   }
1163 
1164   //
1165   // Return the operation status
1166   //
1167   DBG_EXIT_STATUS ( Status );
1168   return Status;
1169 }
1170 
1171 
1172 /**
1173   Read an SROM location
1174 
1175   This routine calls ::Ax88772UsbCommand to read data from the
1176   SROM.
1177 
1178   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
1179   @param [in] Address          SROM address
1180   @param [out] pData           Buffer to receive the data
1181 
1182   @retval EFI_SUCCESS          The read was successful
1183   @retval other                The read failed
1184 
1185 **/
1186 EFI_STATUS
Ax88772SromRead(IN NIC_DEVICE * pNicDevice,IN UINT32 Address,OUT UINT16 * pData)1187 Ax88772SromRead (
1188   IN NIC_DEVICE * pNicDevice,
1189   IN UINT32 Address,
1190   OUT UINT16 * pData
1191   )
1192 {
1193   USB_DEVICE_REQUEST SetupMsg;
1194   EFI_STATUS Status;
1195 
1196   DBG_ENTER ( );
1197 
1198   //
1199   //  Read a value from the SROM
1200   //
1201   SetupMsg.RequestType = USB_ENDPOINT_DIR_IN
1202                        | USB_REQ_TYPE_VENDOR
1203                        | USB_TARGET_DEVICE;
1204   SetupMsg.Request = CMD_SROM_READ;
1205   SetupMsg.Value = (UINT16) Address;
1206   SetupMsg.Index = 0;
1207   SetupMsg.Length = sizeof ( *pData );
1208   Status = Ax88772UsbCommand ( pNicDevice,
1209                                &SetupMsg,
1210                                pData );
1211 
1212   //
1213   // Return the operation status
1214   //
1215   DBG_EXIT_STATUS ( Status );
1216   return Status;
1217 }
1218 
1219 
1220 /**
1221   This routine is called at a regular interval to poll for
1222   receive packets.
1223 
1224   This routine polls the link state and gets any receive packets
1225   by calling ::Ax88772Rx.
1226 
1227   @param [in] Event            Timer event
1228   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
1229 
1230 **/
1231 VOID
Ax88772Timer(IN EFI_EVENT Event,IN NIC_DEVICE * pNicDevice)1232 Ax88772Timer (
1233   IN EFI_EVENT Event,
1234   IN NIC_DEVICE * pNicDevice
1235   )
1236 {
1237   //
1238   //  Use explicit DEBUG messages since the output frequency is too
1239   //  high for DEBUG_INFO to keep up and have spare cycles for the
1240   //  shell
1241   //
1242   DEBUG (( DEBUG_TIMER, "Entering Ax88772Timer\r\n" ));
1243 
1244   //
1245   //  Poll the link state and get any receive packets
1246   //
1247   Ax88772Rx ( pNicDevice, FALSE );
1248 
1249   DEBUG (( DEBUG_TIMER, "Exiting Ax88772Timer\r\n" ));
1250 }
1251 
1252 
1253 /**
1254   Send a command to the USB device.
1255 
1256   @param [in] pNicDevice       Pointer to the NIC_DEVICE structure
1257   @param [in] pRequest         Pointer to the request structure
1258   @param [in, out] pBuffer     Data buffer address
1259 
1260   @retval EFI_SUCCESS          The USB transfer was successful
1261   @retval other                The USB transfer failed
1262 
1263 **/
1264 EFI_STATUS
Ax88772UsbCommand(IN NIC_DEVICE * pNicDevice,IN USB_DEVICE_REQUEST * pRequest,IN OUT VOID * pBuffer)1265 Ax88772UsbCommand (
1266   IN NIC_DEVICE * pNicDevice,
1267   IN USB_DEVICE_REQUEST * pRequest,
1268   IN OUT VOID * pBuffer
1269   )
1270 {
1271   UINT32 CmdStatus;
1272   EFI_USB_DATA_DIRECTION Direction;
1273   EFI_USB_IO_PROTOCOL * pUsbIo;
1274   EFI_STATUS Status;
1275 
1276   DBG_ENTER ( );
1277 
1278   //
1279   // Determine the transfer direction
1280   //
1281   Direction = EfiUsbNoData;
1282   if ( 0 != pRequest->Length ) {
1283     Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))
1284               ? EfiUsbDataIn : EfiUsbDataOut;
1285   }
1286 
1287   //
1288   // Issue the command
1289   //
1290   pUsbIo = pNicDevice->pUsbIo;
1291   Status = pUsbIo->UsbControlTransfer ( pUsbIo,
1292                                         pRequest,
1293                                         Direction,
1294                                         USB_BUS_TIMEOUT,
1295                                         pBuffer,
1296                                         pRequest->Length,
1297                                         &CmdStatus );
1298 
1299   //
1300   // Determine the operation status
1301   //
1302   if ( !EFI_ERROR ( Status )) {
1303     Status = CmdStatus;
1304   }
1305   else {
1306     //
1307     // Display any errors
1308     //
1309     DEBUG (( DEBUG_INFO,
1310               "Ax88772UsbCommand - Status: %r\n",
1311               Status ));
1312 
1313     //
1314     // Only use status values associated with the Simple Network protocol
1315     //
1316     if ( EFI_TIMEOUT == Status ) {
1317       Status = EFI_DEVICE_ERROR;
1318     }
1319   }
1320 
1321   //
1322   // Return the operation status
1323   //
1324   DBG_EXIT_STATUS ( Status );
1325   return Status;
1326 }
1327