2 Implement the interface to the AX88772 Ethernet controller.
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.
8 Copyright (c) 2011, Intel Corporation
9 All rights reserved. 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
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.
25 @param [in] pMacAddress Address of a six byte buffer to containing the MAC address.
27 @returns The CRC-32 value associated with this MAC address
32 IN UINT8
* pMacAddress
42 // Walk the MAC address
45 pEnd
= &pMacAddress
[ PXE_HWADDR_LEN_ETHER
];
46 while ( pEnd
> pMacAddress
) {
47 Data
= *pMacAddress
++;
49 // CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
51 // 1 0000 0100 1100 0001 0001 1101 1011 0111
53 for ( BitNumber
= 0; 8 > BitNumber
; BitNumber
++ ) {
54 Carry
= (( Crc
>> 31 ) & 1 ) ^ ( Data
& 1 );
63 // Return the CRC value
72 This routine calls ::Ax88772UsbCommand to request the MAC
73 address from the network adapter.
75 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
76 @param [out] pMacAddress Address of a six byte buffer to receive the MAC address.
78 @retval EFI_SUCCESS The MAC address is available.
79 @retval other The MAC address is not valid.
83 Ax88772MacAddressGet (
84 IN NIC_DEVICE
* pNicDevice
,
85 OUT UINT8
* pMacAddress
88 USB_DEVICE_REQUEST SetupMsg
;
92 // Set the register address.
94 SetupMsg
.RequestType
= USB_ENDPOINT_DIR_IN
97 SetupMsg
.Request
= CMD_MAC_ADDRESS_READ
;
100 SetupMsg
.Length
= PXE_HWADDR_LEN_ETHER
;
103 // Read the PHY register
105 Status
= Ax88772UsbCommand ( pNicDevice
,
115 This routine calls ::Ax88772UsbCommand to set the MAC address
116 in the network adapter.
118 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
119 @param [in] pMacAddress Address of a six byte buffer to containing the new MAC address.
121 @retval EFI_SUCCESS The MAC address was set.
122 @retval other The MAC address was not set.
126 Ax88772MacAddressSet (
127 IN NIC_DEVICE
* pNicDevice
,
128 IN UINT8
* pMacAddress
131 USB_DEVICE_REQUEST SetupMsg
;
135 // Set the register address.
137 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
139 SetupMsg
.Request
= CMD_MAC_ADDRESS_WRITE
;
142 SetupMsg
.Length
= PXE_HWADDR_LEN_ETHER
;
145 // Read the PHY register
147 Status
= Ax88772UsbCommand ( pNicDevice
,
154 Clear the multicast hash table
156 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
160 Ax88772MulticastClear (
161 IN NIC_DEVICE
* pNicDevice
166 // Clear the multicast hash table
168 for ( i
= 0 ; i
< 8 ; i
++ )
169 pNicDevice
->MulticastHash
[0] = 0;
173 Enable a multicast address in the multicast hash table
175 This routine calls ::Ax88772Crc to compute the hash bit for
178 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
179 @param [in] pMacAddress Address of a six byte buffer to containing the MAC address.
183 Ax88772MulticastSet (
184 IN NIC_DEVICE
* pNicDevice
,
185 IN UINT8
* pMacAddress
191 // Compute the CRC on the destination address
193 Crc
= Ax88772Crc ( pMacAddress
) >> 26;
196 // Set the bit corresponding to the destination address
198 pNicDevice
->MulticastHash
[ Crc
>> 3 ] |= ( 1<< (Crc
& 7));
202 Start the link negotiation
204 This routine calls ::Ax88772PhyWrite to start the PHY's link
207 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
209 @retval EFI_SUCCESS The link negotiation was started.
210 @retval other Failed to start the link negotiation.
214 Ax88772NegotiateLinkStart (
215 IN NIC_DEVICE
* pNicDevice
222 // Set the supported capabilities.
224 Status
= Ax88772PhyWrite ( pNicDevice
,
227 | AN_TX_FDX
| AN_TX_HDX
228 | AN_10_FDX
| AN_10_HDX
);
229 if ( !EFI_ERROR ( Status
)) {
231 // Set the link speed and duplex
233 Control
= BMCR_AUTONEGOTIATION_ENABLE
234 | BMCR_RESTART_AUTONEGOTIATION
;
235 if ( pNicDevice
->b100Mbps
) {
236 Control
|= BMCR_100MBPS
;
238 if ( pNicDevice
->bFullDuplex
) {
239 Control
|= BMCR_FULL_DUPLEX
;
241 Status
= Ax88772PhyWrite ( pNicDevice
, PHY_BMCR
, Control
);
244 if (!EFI_ERROR(Status
)) {
248 if (pNicDevice
->bComplete
&& pNicDevice
->bLinkUp
) {
249 pNicDevice
->SimpleNetwork
.Mode
->MediaPresent
250 = pNicDevice
->bLinkUp
& pNicDevice
->bComplete
;
254 gBS
->Stall(AUTONEG_DELAY
);
255 Status
= Ax88772NegotiateLinkComplete ( pNicDevice
,
256 &pNicDevice
->PollCount
,
257 &pNicDevice
->bComplete
,
258 &pNicDevice
->bLinkUp
,
259 &pNicDevice
->b100Mbps
,
260 &pNicDevice
->bFullDuplex
);
263 }while(!pNicDevice
->bLinkUp
&& i
< AUTONEG_POLLCNT
);
270 Complete the negotiation of the PHY link
272 This routine calls ::Ax88772PhyRead to determine if the
273 link negotiation is complete.
275 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
276 @param [in, out] pPollCount Address of number of times this routine was polled
277 @param [out] pbComplete Address of boolean to receive complate status.
278 @param [out] pbLinkUp Address of boolean to receive link status, TRUE=up.
279 @param [out] pbHiSpeed Address of boolean to receive link speed, TRUE=100Mbps.
280 @param [out] pbFullDuplex Address of boolean to receive link duplex, TRUE=full.
282 @retval EFI_SUCCESS The MAC address is available.
283 @retval other The MAC address is not valid.
287 Ax88772NegotiateLinkComplete (
288 IN NIC_DEVICE
* pNicDevice
,
289 IN OUT UINTN
* pPollCount
,
290 OUT BOOLEAN
* pbComplete
,
291 OUT BOOLEAN
* pbLinkUp
,
292 OUT BOOLEAN
* pbHiSpeed
,
293 OUT BOOLEAN
* pbFullDuplex
301 // Determine if the link is up.
306 // Get the link status
308 Status
= Ax88772PhyRead ( pNicDevice
,
312 if ( !EFI_ERROR ( Status
)) {
313 *pbLinkUp
= (BOOLEAN
)( 0 != ( PhyData
& BMSR_LINKST
));
314 if ( 0 == *pbLinkUp
) {
315 DEBUG (( EFI_D_INFO
, "Link Down\n" ));
318 *pbComplete
= (BOOLEAN
)( 0 != ( PhyData
& 0x20 ));
319 if ( 0 == *pbComplete
) {
320 DEBUG (( EFI_D_INFO
, "Autoneg is not yet Complete\n" ));
323 Status
= Ax88772PhyRead ( pNicDevice
,
326 if ( !EFI_ERROR ( Status
)) {
328 // Autonegotiation is complete
329 // Determine the link speed.
331 *pbHiSpeed
= (BOOLEAN
)( 0 != ( PhyData
& ( AN_TX_FDX
| AN_TX_HDX
)));
334 // Determine the link duplex.
336 Mask
= ( *pbHiSpeed
) ? AN_TX_FDX
: AN_10_FDX
;
337 *pbFullDuplex
= (BOOLEAN
)( 0 != ( PhyData
& Mask
));
343 DEBUG (( EFI_D_ERROR
, "Failed to read BMCR\n" ));
350 Read a register from the PHY
352 This routine calls ::Ax88772UsbCommand to read a PHY register.
354 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
355 @param [in] RegisterAddress Number of the register to read.
356 @param [in, out] pPhyData Address of a buffer to receive the PHY register value
358 @retval EFI_SUCCESS The PHY data is available.
359 @retval other The PHY data is not valid.
364 IN NIC_DEVICE
* pNicDevice
,
365 IN UINT8 RegisterAddress
,
366 IN OUT UINT16
* pPhyData
369 USB_DEVICE_REQUEST SetupMsg
;
373 // Request access to the PHY
375 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
377 SetupMsg
.Request
= CMD_PHY_ACCESS_SOFTWARE
;
381 Status
= Ax88772UsbCommand ( pNicDevice
,
384 if ( !EFI_ERROR ( Status
)) {
386 // Read the PHY register address.
388 SetupMsg
.RequestType
= USB_ENDPOINT_DIR_IN
389 | USB_REQ_TYPE_VENDOR
391 SetupMsg
.Request
= CMD_PHY_REG_READ
;
392 SetupMsg
.Value
= pNicDevice
->PhyId
;
393 SetupMsg
.Index
= RegisterAddress
;
394 SetupMsg
.Length
= sizeof ( *pPhyData
);
395 Status
= Ax88772UsbCommand ( pNicDevice
,
398 if ( !EFI_ERROR ( Status
)) {
401 // Release the PHY to the hardware
403 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
405 SetupMsg
.Request
= CMD_PHY_ACCESS_HARDWARE
;
409 Status
= Ax88772UsbCommand ( pNicDevice
,
419 Write to a PHY register
421 This routine calls ::Ax88772UsbCommand to write a PHY register.
423 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
424 @param [in] RegisterAddress Number of the register to read.
425 @param [in] PhyData Address of a buffer to receive the PHY register value
427 @retval EFI_SUCCESS The PHY data was written.
428 @retval other Failed to wwrite the PHY register.
433 IN NIC_DEVICE
* pNicDevice
,
434 IN UINT8 RegisterAddress
,
438 USB_DEVICE_REQUEST SetupMsg
;
442 // Request access to the PHY
444 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
446 SetupMsg
.Request
= CMD_PHY_ACCESS_SOFTWARE
;
450 Status
= Ax88772UsbCommand ( pNicDevice
,
453 if ( !EFI_ERROR ( Status
)) {
455 // Write the PHY register
457 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
459 SetupMsg
.Request
= CMD_PHY_REG_WRITE
;
460 SetupMsg
.Value
= pNicDevice
->PhyId
;
461 SetupMsg
.Index
= RegisterAddress
;
462 SetupMsg
.Length
= sizeof ( PhyData
);
463 Status
= Ax88772UsbCommand ( pNicDevice
,
466 if ( !EFI_ERROR ( Status
)) {
469 // Release the PHY to the hardware
471 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
473 SetupMsg
.Request
= CMD_PHY_ACCESS_HARDWARE
;
477 Status
= Ax88772UsbCommand ( pNicDevice
,
490 This routine uses ::Ax88772UsbCommand to reset the network
491 adapter. This routine also uses ::Ax88772PhyWrite to reset
494 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
496 @retval EFI_SUCCESS The MAC address is available.
497 @retval other The MAC address is not valid.
502 IN NIC_DEVICE
* pNicDevice
505 USB_DEVICE_REQUEST SetupMsg
;
508 EFI_USB_IO_PROTOCOL
*pUsbIo
;
509 EFI_USB_DEVICE_DESCRIPTOR Device
;
511 pUsbIo
= pNicDevice
->pUsbIo
;
512 Status
= pUsbIo
->UsbGetDeviceDescriptor ( pUsbIo
, &Device
);
514 if (EFI_ERROR(Status
)) goto err
;
516 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
518 SetupMsg
.Request
= CMD_PHY_ACCESS_HARDWARE
;
522 Status
= Ax88772UsbCommand ( pNicDevice
,
526 if (EFI_ERROR(Status
)) goto err
;
528 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
530 SetupMsg
.Request
= CMD_PHY_SELECT
;
531 SetupMsg
.Value
= SPHY_PSEL
;
534 Status
= Ax88772UsbCommand ( pNicDevice
,
538 if (EFI_ERROR(Status
)) goto err
;
540 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
542 SetupMsg
.Request
= CMD_RESET
;
543 SetupMsg
.Value
= SRR_IPRL
;
546 Status
= Ax88772UsbCommand ( pNicDevice
,
550 if (EFI_ERROR(Status
)) goto err
;
552 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
554 SetupMsg
.Request
= CMD_RESET
;
555 SetupMsg
.Value
= SRR_IPPD
| SRR_IPRL
;
558 Status
= Ax88772UsbCommand ( pNicDevice
,
562 gBS
->Stall ( 200000 );
564 if (EFI_ERROR(Status
)) goto err
;
566 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
568 SetupMsg
.Request
= CMD_RESET
;
569 SetupMsg
.Value
= SRR_IPRL
;
572 Status
= Ax88772UsbCommand ( pNicDevice
,
576 gBS
->Stall ( 200000 );
578 if (EFI_ERROR(Status
)) goto err
;
580 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
582 SetupMsg
.Request
= CMD_RESET
;
586 Status
= Ax88772UsbCommand ( pNicDevice
,
590 if (EFI_ERROR(Status
)) goto err
;
592 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
594 SetupMsg
.Request
= CMD_PHY_SELECT
;
595 SetupMsg
.Value
= SPHY_PSEL
;
598 Status
= Ax88772UsbCommand ( pNicDevice
,
602 if (EFI_ERROR(Status
)) goto err
;
604 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
606 SetupMsg
.Request
= CMD_RESET
;
607 SetupMsg
.Value
= SRR_IPRL
| SRR_BZ
| SRR_BZTYPE
;
610 Status
= Ax88772UsbCommand ( pNicDevice
,
614 if (EFI_ERROR(Status
)) goto err
;
616 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
618 SetupMsg
.Request
= CMD_RX_CONTROL_WRITE
;
622 Status
= Ax88772UsbCommand ( pNicDevice
,
626 if (EFI_ERROR(Status
)) goto err
;
628 if (pNicDevice
->Flags
!= FLAG_TYPE_AX88772
) {
629 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
631 SetupMsg
.Request
= CMD_RXQTC
;
632 SetupMsg
.Value
= 0x8000;
633 SetupMsg
.Index
= 0x8001;
635 Status
= Ax88772UsbCommand ( pNicDevice
,
645 Enable or disable the receiver
647 This routine calls ::Ax88772UsbCommand to update the
648 receiver state. This routine also calls ::Ax88772MacAddressSet
649 to establish the MAC address for the network adapter.
651 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
652 @param [in] RxFilter Simple network RX filter mask value
654 @retval EFI_SUCCESS The MAC address was set.
655 @retval other The MAC address was not set.
660 IN NIC_DEVICE
* pNicDevice
,
666 USB_DEVICE_REQUEST SetupMsg
;
668 EFI_USB_IO_PROTOCOL
*pUsbIo
;
669 EFI_USB_DEVICE_DESCRIPTOR Device
;
671 pUsbIo
= pNicDevice
->pUsbIo
;
672 Status
= pUsbIo
->UsbGetDeviceDescriptor ( pUsbIo
, &Device
);
674 if (EFI_ERROR(Status
)) {
675 DEBUG (( EFI_D_ERROR
, "Failed to get device descriptor\n" ));
680 // Enable the receiver if something is to be received
683 if ( 0 != RxFilter
) {
685 // Enable the receiver
687 SetupMsg
.RequestType
= USB_ENDPOINT_DIR_IN
688 | USB_REQ_TYPE_VENDOR
690 SetupMsg
.Request
= CMD_MEDIUM_STATUS_READ
;
693 SetupMsg
.Length
= sizeof ( MediumStatus
);
694 Status
= Ax88772UsbCommand ( pNicDevice
,
697 if ( !EFI_ERROR ( Status
)) {
698 if ( 0 == ( MediumStatus
& MS_RE
)) {
699 MediumStatus
|= MS_RE
| MS_ONE
;
701 if ( pNicDevice
->bFullDuplex
)
702 MediumStatus
|= MS_TFC
| MS_RFC
| MS_FD
;
704 MediumStatus
&= ~(MS_TFC
| MS_RFC
| MS_FD
);
706 if ( pNicDevice
->b100Mbps
)
707 MediumStatus
|= MS_PS
;
709 MediumStatus
&= ~MS_PS
;
711 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
713 SetupMsg
.Request
= CMD_MEDIUM_STATUS_WRITE
;
714 SetupMsg
.Value
= MediumStatus
;
717 Status
= Ax88772UsbCommand ( pNicDevice
,
720 if ( EFI_ERROR ( Status
)) {
721 DEBUG (( EFI_D_ERROR
, "Failed to enable receiver, Status: %r\r\n",
727 DEBUG (( EFI_D_ERROR
, "Failed to read receiver status, Status: %r\r\n",
732 RxControl
= RXC_SO
| RXC_RH1M
;
734 // Enable multicast if requested
736 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
)) {
739 // Update the multicast hash table
741 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
743 SetupMsg
.Request
= CMD_MULTICAST_HASH_WRITE
;
746 SetupMsg
.Length
= sizeof ( pNicDevice
->MulticastHash
);
747 Status
= Ax88772UsbCommand ( pNicDevice
,
749 &pNicDevice
->MulticastHash
);
752 // Enable all multicast if requested
754 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST
)) {
755 RxControl
|= RXC_AMALL
;
759 // Enable broadcast if requested
761 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
)) {
766 // Enable promiscuous mode if requested
768 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
)) {
769 RxControl
|= RXC_PRO
;
773 // Update the receiver control
775 if (pNicDevice
->CurRxControl
!= RxControl
) {
776 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
778 SetupMsg
.Request
= CMD_RX_CONTROL_WRITE
;
779 SetupMsg
.Value
= RxControl
;
782 Status
= Ax88772UsbCommand ( pNicDevice
,
785 if ( !EFI_ERROR ( Status
)) {
786 pNicDevice
->CurRxControl
= RxControl
;
790 DEBUG (( EFI_D_ERROR
, "ERROR - Failed to set receiver control, Status: %r\r\n",
799 Read an SROM location
801 This routine calls ::Ax88772UsbCommand to read data from the
804 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
805 @param [in] Address SROM address
806 @param [out] pData Buffer to receive the data
808 @retval EFI_SUCCESS The read was successful
809 @retval other The read failed
814 IN NIC_DEVICE
* pNicDevice
,
819 return EFI_UNSUPPORTED
;
823 Send a command to the USB device.
825 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
826 @param [in] pRequest Pointer to the request structure
827 @param [in, out] pBuffer Data buffer address
829 @retval EFI_SUCCESS The USB transfer was successful
830 @retval other The USB transfer failed
835 IN NIC_DEVICE
* pNicDevice
,
836 IN USB_DEVICE_REQUEST
* pRequest
,
837 IN OUT VOID
* pBuffer
841 EFI_USB_DATA_DIRECTION Direction
;
842 EFI_USB_IO_PROTOCOL
* pUsbIo
;
846 // Determine the transfer direction
848 Direction
= EfiUsbNoData
;
849 if ( 0 != pRequest
->Length
) {
850 Direction
= ( 0 != ( pRequest
->RequestType
& USB_ENDPOINT_DIR_IN
))
851 ? EfiUsbDataIn
: EfiUsbDataOut
;
857 pUsbIo
= pNicDevice
->pUsbIo
;
858 Status
= pUsbIo
->UsbControlTransfer ( pUsbIo
,
866 // Determine the operation status
868 if ( !EFI_ERROR ( Status
)) {
873 // Only use status values associated with the Simple Network protocol
875 if ( EFI_TIMEOUT
== Status
) {
876 Status
= EFI_DEVICE_ERROR
;