UEFI下的Gmac驱动实现

1.mac的分类:
mac按照传输的速率可以分为 emac 和 gmac.

mac: 它是一个controller,它的主要的作用有两个方面:
	 帧发送: 接受来自协议层的数据,加上控制信息,然后以位数据流的形式传到物理层.
	 帧接受: 接受物理层的数据流,检查是否有效,然后发送给上层协议,或者丢弃.
	 所以从上述描述来看,gmac控制器主要完成的工作是数据流的过滤

phy: gmac 有对应的phy, 而phy是实际上操作数据的收发的.

在这里插入图片描述
2. mac的工作模式:

工作模式可以分为半双工和全双工
半双工:
		GMAC Client 将数据传送给Gmac后,Gmac先给数据加上Preamble, FSD,FCS组成以太网帧; 
		然后检查载波侦听信号 (CRS) 若有载波信号,表示有数据正在本地网段上传播,就等待直到载波信号消失.
		载波信号消失后,Gmac还要等待一个帧间延时,若在帧间延时期间,一直没有载波信号,该以太网帧就可以
		开始向物理层传输数据.
		
全双工:
		全双工模式: Gmac从Gmac Client 接收到数据后,不需要载波帧听,直接向物理层传递,
		其它操作与半双工相同.
  1. 通过下面两个寄存器读写Phy芯片的寄存器,完成对phy的控制
    在这里插入图片描述
    在这里插入图片描述
  2. Uefi中Gmac驱动的实现:
EFI_STATUS
EFIAPI
InitializeGmacUNDIDriver (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  if(NetworkProtocolIsDisable())
    return EFI_SUCCESS;
    
  Status = EfiLibInstallDriverBinding (ImageHandle, SystemTable, 
  										&gUndiDriverBinding, ImageHandle);
  										
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &gUndiDriverBinding.DriverBindingHandle,
                  &gEfiComponentNameProtocolGuid,
                  &gUndiComponentName,
                  &gEfiDriverDiagnosticsProtocolGuid,
                  &gGmacUndiDriverDiagnostics,
                  &gEfiComponentName2ProtocolGuid,
                  &gUndiComponentName2,
                  &gEfiDriverDiagnostics2ProtocolGuid,
                  &gGmacUndiDriverDiagnostics2,
                  &gEfiDriverConfigurationProtocolGuid,
                  &gGmacUndiDriverConfiguration,
                  &gEfiDriverHealthProtocolGuid,
                  &gUndiDriverHealthProtocol,
                  NULL
                );
  // This protocol does not need to be closed because it uses the GET_PROTOCOL attribute
  Status = gBS->OpenProtocol (
                  ImageHandle,
                  &gEfiLoadedImageProtocolGuid,
                  (VOID *) &LoadedImageInterface,
                  ImageHandle,
                  NULL,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                );

  if (EFI_ERROR (Status)) {
    DEBUGPRINT (CRITICAL, ("OpenProtocol returns %r\n", Status));
    return Status;
  }

  LoadedImageInterface->Unload = GmacUndiUnload;
    Status = gBS->CreateEvent (
                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
                  TPL_NOTIFY,
                  GmacUndiNotifyExitBs,
                  NULL,
                  &mEventNotifyExitBs
                );
  if (EFI_ERROR (Status)) {
    DEBUGPRINT (CRITICAL, ("CreateEvent returns %r\n", Status));
    return Status;
  }
  Status = InitializePxeStruct ();

  return Status;
}

首先是安装gUndiDriverBinding,实例化的时候:
EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = {
  GmacUndiDriverSupported, // Supported
  GmacUndiDriverStart,     // Start
  GmacUndiDriverStop,      // Stop
  VERSION_TO_HEX,         // Driver Version
  NULL,                   // ImageHandle
  NULL                    // Driver Binding Handle
};
首先我们分析一下Support函数:
/**
Test to see if this driver supports ControllerHandle.
**/
EFI_STATUS
EFIAPI
GmacUndiDriverSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL *   RemainingDevicePath
  )
{
  EFI_STATUS           Status;
  EFI_PCI_IO_PROTOCOL *PciIo;
  PCI_TYPE00           Pci;
  UNDI_PRIVATE_DATA   *UndiPrivateData;

  UndiPrivateData = GetControllerPrivateData (Controller);

  if (UndiPrivateData == NULL) {
  	DbgPrint (EFI_D_INFO,"LY_TEST------The UndiPrivateData is NULL---\n");
    Status = gBS->OpenProtocol (
                    Controller,
                    &gEfiPciIoProtocolGuid,
                    (VOID **) &PciIo,
                    This->DriverBindingHandle,
                    Controller,
                    EFI_OPEN_PROTOCOL_BY_DRIVER
                  );

    if (EFI_ERROR (Status)) {
      return Status;
    }    
  } else {
    PciIo = UndiPrivateData->NicInfo.PciIo;
    if (PciIo == NULL) {
      return EFI_INVALID_PARAMETER;
    }    
  }
  Status = PciIo->Pci.Read (
                        PciIo,
                        EfiPciIoWidthUint8,
                        0,
                        sizeof (PCI_CONFIG_HEADER),
                        &Pci
                      );
  if (EFI_ERROR (Status)) {
    goto ExitSupported;
  }

  if (Status == EFI_SUCCESS) {
    DbgPrint (EFI_D_INFO,"ly_test----Pci.Hdr.VendorId = %lx--Pci.Hdr.DeviceId = %lx-----\n",Pci.Hdr.VendorId,Pci.Hdr.DeviceId);
  }

  if (!IsDeviceIdSupported (Pci.Hdr.VendorId, Pci.Hdr.DeviceId)) {
    Status = EFI_UNSUPPORTED;
    goto ExitSupported;
  }

  Status = AnalyzeRemainingDevicePath (
             UndiPrivateData,
             RemainingDevicePath
           );
  if (EFI_ERROR (Status)) {
    goto ExitSupported;
  }

ExitSupported:
  if (UndiPrivateData == NULL) {
    gBS->CloseProtocol (
           Controller,
           &gEfiPciIoProtocolGuid,
           This->DriverBindingHandle,
           Controller
         );
  }

  return Status;
}

Support函数里面需要注意的有两个地方:
1. 首先得到Undi的私有数据
UNDI_PRIVATE_DATA *UndiPrivateData; 
UndiPrivateData = GetControllerPrivateData (Controller);
UNDI_PRIVATE_DATA*
GetControllerPrivateData (
  IN  EFI_HANDLE ControllerHandle
  )
{
  UINT32 i = 0; 

  for (i = 0; i < mActiveControllers; i++) {
    if (mGMACUndi32DeviceList[i] != NULL) {
      if (mGMACUndi32DeviceList[i]->ControllerHandle == ControllerHandle) {
        return mGMACUndi32DeviceList[i];
      }    
    }    
  }
  return NULL;
}

mGMACUndi32DeviceList 是一个全局变量,类型是UNDI_PRIVATE_DATA *的一个数组.
UNDI_PRIVATE_DATA *mGMACUndi32DeviceList[MAX_NIC_INTERFACES];
我们看一下UNDI_PRIVATE_DATA 的结构:
typedef struct UNDI_PRIVATE_DATA_S {                                                                                                                                                                                                        
  UINTN                                     Signature;
  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol31;
  EFI_NII_POINTER_PROTOCOL                  NIIPointerProtocol;
  EFI_HANDLE                                ControllerHandle;
  EFI_HANDLE                                DeviceHandle;
  EFI_HANDLE                                HiiInstallHandle;
  EFI_HANDLE                                FmpInstallHandle;
  EFI_DEVICE_PATH_PROTOCOL *                Undi32BaseDevPath;
  EFI_DEVICE_PATH_PROTOCOL *                Undi32DevPath;
  GIG_DRIVER_DATA                           NicInfo;
  EFI_UNICODE_STRING_TABLE *                ControllerNameTable;
  CHAR16 *                                  Brand;
  BOOLEAN                                   IsChildInitialized;
  // HII Configuration
  EFI_HII_HANDLE                            HiiHandle;
  UNDI_DRIVER_CONFIGURATION                 Configuration;
  /* HII Configuration parameters start here
   depending on these settings some of HII menus are disabled */
  BOOLEAN                   LinkSpeedSettingsSupported;
  UINT8 AltMacAddrSupported;
  // Consumed protocol
  EFI_HII_DATABASE_PROTOCOL *      HiiDatabase;
  EFI_HII_STRING_PROTOCOL *        HiiString;
  EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
  EFI_FORM_BROWSER2_PROTOCOL *     FormBrowser2;
  EFI_GUID                         HiiFormGuid;
  // Produced protocol
  EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
  EFI_DRIVER_STOP_PROTOCOL       DriverStop;
  EFI_ADAPTER_INFORMATION_PROTOCOL AdapterInformation;
  UINT32                           LastAttemptVersion;
  UINT32                           LastAttemptStatus;
} UNDI_PRIVATE_DATA;

到这里,很多朋友会有疑问,UNDI是什么? 以及我们为什么要用UndiPrivateData.
首先解释一下什么是UNDI:
	UNDI的全称是Universal Network Driver Interface
	它并不是UEFI网络框架的一部分,甚至也可以不是UEFI的一部分。
	不过目前UEFI下的网络驱动都会实现UNDI,这样UEFI就可以通过SNP来调用网卡的底层驱动。
	UNDI说到底是定义了一系列的接口,然后SNP来访问这些接口。
	这需要实现了UNDI的网络设备驱动中安装一个NetworkInterfaceIdentifier(NII)协议.
	而Gmac驱动本身来说也是Gmac网卡的驱动,所以实现UNDI来完成对Gmac的调用.
所以在访问PCI的IO空间时,如果UndiPrivateData 为空,那么我们就用驱动所绑定的句柄
上的PciIo去访问,否则的话: PciIo = UndiPrivateData->NicInfo.PciIo;
就用网卡信息中的PciIo去访问IO空间.

2.   if (!IsDeviceIdSupported (Pci.Hdr.VendorId, Pci.Hdr.DeviceId)) {
		Status = EFI_UNSUPPORTED;
		goto ExitSupported;
	}
	检查VendorId和DeviceId,我们龙芯3A571(3A5000+7A1000,胡老师叫3A571,
	哈哈,虽然听着土,但是还是很好理解的哈) 上面的 GMAC 的VerdorId 是0x 0014,
	DeviceId 是 0x7a03.
	
总结: Support函数主要作用是扫描主板上的所有PCI设备,如果存在
	 和Gmac设备匹配的DeviceId和VendorId的话,说明这个驱动是支持控制器
	 的句柄的安装的.


接下来再来分析一下 Start函数:
/** Start this driver on Controller by opening PciIo and DevicePath protocol.

   Initialize PXE structures, create a copy of the Controller Device Path with the
   NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
   on the newly created Device Path.
   通过打开PciIo和DevicePath协议在Controller上启动这个驱动程序。
   初始化PXE结构,创建一个带有网卡MAC地址的控制器设备路径的副本,在新创建的设备路径上安装	   NetworkInterfaceIdentifier协议。
**/

EFI_STATUS
EFIAPI
GmacUndiDriverStart (
  IN EFI_DRIVER_BINDING_PROTOCOL *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL *   RemainingDevicePath
  )
{
  UNDI_PRIVATE_DATA *UndiPrivateData      = NULL;
  EFI_STATUS         Status               = EFI_SUCCESS;
  BOOLEAN            InitializeChild      = TRUE;
  BOOLEAN            InitializeController = TRUE;
  ...
  if (InitializeController) {
    DbgPrint (EFI_D_INFO,"ly_test------------GmacUndiDriverStart InitializeController---\n");
    Status = InitUndiPrivateData (
               Controller,
               &UndiPrivateData
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("InitUndiPrivateData returns %r\n", Status));
      DEBUGWAIT (CRITICAL);
      goto UndiError;
    }
        Status = OpenControllerProtocols (
               Controller,
               This,
               UndiPrivateData
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("OpenContollerProtocols returns %r\n", Status));
      DEBUGWAIT (CRITICAL);
      goto UndiError;
    }
    Status = InitController (UndiPrivateData);
    if (EFI_ERROR (Status) &&
      (Status != EFI_ACCESS_DENIED))
    {
      DEBUGPRINT (CRITICAL, ("InitController fails: %r", Status));
      goto UndiErrorDeleteDevicePath;
    }
    Status = InitControllerProtocols (
               UndiPrivateData,
               Controller
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("InitControllerProtocols failed with %r\n", Status));
      goto UndiErrorDeleteDevicePath;
    }
  }
  if (InitializeChild) {
    InitUndiStructures (UndiPrivateData);

    Status = InitChild (UndiPrivateData);
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("InitChild failed with %r\n", Status));
      goto UndiErrorDeleteDevicePath;
    }

    Status = InitChildProtocols (
               UndiPrivateData
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("InitChildProtocols failed with %r\n", Status));
      goto UndiErrorDeleteDevicePath;
    }
    Status = OpenChildProtocols (
               UndiPrivateData,
               This,
               Controller
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("OpenChildProtocols failed with %r\n", Status));
    }
    UndiPrivateData->IsChildInitialized = TRUE;
  }

  Status = gBS->CreateEvent (
                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  GmacReInit,
                  (UndiPrivateData->NicInfo.GmacHw),
                  &(UndiPrivateData->NicInfo.GmacHw->synopGMACdev->ReInit)
                  );

  if (EFI_ERROR (Status)) {
    ASSERT(0);
    return Status;
  }
  Status = gBS->SetTimer (UndiPrivateData->NicInfo.GmacHw->synopGMACdev->ReInit, TimerPeriodic, (UINT64)CHECK_INIT_PERIOD);
   if (EFI_ERROR (Status)) {
    ASSERT(0);
    return Status;
   }

  return EFI_SUCCESS;

UndiErrorDeleteDevicePath:
  GigUndiPxeUpdate (NULL, mGMACPxe31);
  gBS->FreePool (UndiPrivateData->Undi32DevPath);

UndiError:
  mGMACUndi32DeviceList[mActiveControllers - 1] = NULL;
  mActiveControllers--;

  CloseControllerProtocols (
    Controller,
    This
  );
  gBS->FreePool ((VOID **) UndiPrivateData);
  return Status;
}

start 函数里面可以看到首先是:
    Status = InitUndiPrivateData (
               Controller,
               &UndiPrivateData
             );
	然后根据UndiPrivateData去:
    Status = OpenControllerProtocols (
               Controller,
               This,
               UndiPrivateData
             );
	再然后就是初始化控制器:
Status = InitController (UndiPrivateData);
	初始化控制器这里面主要是:
	1.获取此控制器支持的PCI命令选项。
	2.设置PCI命令选项以启用设备内存映射IO、端口IO和总线母版。
	3.为传输和接收资源分配内存。
	4.执行第一次硬件初始化 
	这里我们重点分析一下第4点:
	Status = GmacFirstTimeInit (&UndiPrivateData->NicInfo);
	
	在UNDI_PRIVATE_DATA结构体中我们可以看到NicIfo的类型是: 
	GIG_DRIVER_DATA                           NicInfo; 
	GIG_DRIVER_DATA 的结构如下:
typedef struct DRIVER_DATA_S {
  UINT16                State; // stopped, started or initialized
  synopGMACNetworkAdapter  *GmacHw;
  UINTN                 Segment;
  UINTN                 Bus;
  UINTN                 Device;
  UINTN                 Function;
  UINT8                 PciClass;
  UINT8                 PciSubClass;
  UINTN                 LanFunction;
  SERIAL_FLASH_OFFSETS  SerialFlashOffsets;
  UINT8                 BroadcastNodeAddress[PXE_MAC_LENGTH];
  UINT32                PciConfig[MAX_PCI_CONFIG_LEN];
  UINT32                NvData[MAX_EEPROM_LEN];
  UINTN                 HwInitialized;
  UINTN                 DriverBusy;
  UINT16                LinkSpeed; // requested (forced) link speed
  UINT8                 DuplexMode; // requested duplex
  UINT8                 CableDetect; // 1 to detect and 0 not to detect the cable
  UINT8                 LoopBack;
  UINT8                 UndiEnabled; // When 0 only HII and FMP are avaliable,
                                     // NII is not installed on ControllerHandle
                                     // (e.g. in case iSCSI driver loaded on port)
  UINT64               UniqueId;
  EFI_PCI_IO_PROTOCOL *PciIo;
  // UNDI callbacks
  BS_PTR               Delay;
  VIRT_PHYS            Virt2Phys;
  BLOCK                Block;
  MEM_IO               MemIo;
  MAP_MEM              MapMem;
  UNMAP_MEM            UnMapMem;
  SYNC_MEM             SyncMem;
  UINT8                IoBarIndex;
  UINT64               MemoryPtr;
  UINT32               MemoryLength;
  UINT16               RxFilter;
  UINT16               IntMask;
  UINT16               IntStatus;
  MCAST_LIST           McastList;
  UINT16                     CurRxInd;
  UINT16                     CurTxInd;
  UINT8                      ReceiveStarted;
  DmaDesc                    *RxRing;
  DmaDesc                    *TxRing;

  LOCAL_RX_BUFFER *          LocalRxBuffer;
  UINT16                     XmitDoneHead;
  UINT64                     TxBufferUnmappedAddr[DEFAULT_TX_DESCRIPTORS];
  BOOLEAN                    MacAddrOverride;
  UINT64                     DebugRxBuffer[DEFAULT_RX_DESCRIPTORS];
  BOOLEAN                    FlashWriteInProgress;
  BOOLEAN                    SurpriseRemoval;
  UINTN                      VersionFlag; // Indicates UNDI version 3.0 or 3.1
} GIG_DRIVER_DATA, *PADAPTER_STRUCT;
再看第一次初始化Gmac硬件的代码:
/** This function is called as early as possible during driver start 
	to ensure the
   hardware has enough time to autonegotiate when the 
   real SNP device initialize call is made.
   这个函数在驱动程序启动期间尽可能早地被调用,以确保在真正的SNP设备初始化调用时,
   硬件有足够的时间进行自动协商。
**/
EFI_STATUS
GmacFirstTimeInit (
  GIG_DRIVER_DATA *GigAdapter
  )
{
  PCI_CONFIG_HEADER *PciConfigHeader;
  UINT32 *           TempBar;
  UINT8              BarIndex;
  EFI_STATUS         Status;
  UINT32             ScStatus;

  DEBUGPRINT (E1000, ("GmacFirstTimeInit\n"));

  GigAdapter->DriverBusy = FALSE;

  // Read all the registers from the device's PCI Configuration space
  GigAdapter->PciIo->Pci.Read (
                           GigAdapter->PciIo,
                           EfiPciIoWidthUint32,
                           0,   
                           MAX_PCI_CONFIG_LEN,
                           GigAdapter->PciConfig
                         );

  PciConfigHeader = (PCI_CONFIG_HEADER *) GigAdapter->PciConfig;

  // Enumerate through the PCI BARs for the device to determine which one is
  // the IO BAR.  Save the index of the BAR into the adapter info structure.
  //通过设备的PCI BAR枚举,以确定哪个是IO BAR。将BAR的索引保存到适配器信息结构中。
  TempBar = &PciConfigHeader->BaseAddressReg0;
  for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
    DEBUGPRINT (E1000, ("BAR = %X\n", *TempBar));
    if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {

      // This is a 64-bit memory bar, skip this and the
      // next bar as well.
      TempBar++;
    }    

    // Find the IO BAR and save it's number into IoBar
    if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {

      // Here is the IO Bar - save it to the Gigabit adapter struct.
      GigAdapter->IoBarIndex = BarIndex;
      break;
    }    

    // Advance the pointer to the next bar in PCI config space
    TempBar++;
  }
    GigAdapter->PciIo->GetLocation (
                       GigAdapter->PciIo,
                       &GigAdapter->Segment,
                       &GigAdapter->Bus,
                       &GigAdapter->Device,
                       &GigAdapter->Function
                     );

  DbgPrint (DEBUG_INFO,"  GigAdapter->IoBarIndex = %X\n", GigAdapter->IoBarIndex); //0
  DbgPrint (DEBUG_INFO,"  PCI Command Register   = %X\n", PciConfigHeader->Command);
  //67 根据这里面的数据,结合Command寄存器里面的各个位的含义可知Gmac控制器支持IO请求,响应存储器请求,可以作为主设备等
  DbgPrint (DEBUG_INFO,"  PCI Status Register    = %X\n", PciConfigHeader->Status);//0
  DbgPrint (DEBUG_INFO,"  PCI VendorID           = %X\n", PciConfigHeader->VendorId);//14
  DbgPrint (DEBUG_INFO,"  PCI DeviceID           = %X\n", PciConfigHeader->DeviceId);//7A03
  DbgPrint (DEBUG_INFO,"  PCI SubVendorID        = %X\n", PciConfigHeader->SubVendorId);//0
  DbgPrint (DEBUG_INFO,"  PCI SubSystemID        = %X\n", PciConfigHeader->SubSystemId);//0
  DbgPrint (DEBUG_INFO,"  PCI Segment            = %X\n", GigAdapter->Segment);//0
  DbgPrint (DEBUG_INFO,"  PCI Bus                = %X\n", GigAdapter->Bus);//0
  DbgPrint (DEBUG_INFO,"  PCI Device             = %X\n", GigAdapter->Device);//3
  DbgPrint (DEBUG_INFO,"  PCI Function           = %X\n", GigAdapter->Function);//0
  ZeroMem (GigAdapter->BroadcastNodeAddress, PXE_MAC_LENGTH);
  SetMem (GigAdapter->BroadcastNodeAddress, PXE_HWADDR_LEN_ETHER, 0xFF);

  GigAdapter->GmacHw->synopGMACdev->MacBase             = (UINTN) (((PciConfigHeader->BaseAddressReg0)& 0xFFFFFFF0) | PCI_REG_BASE);
  
  GigAdapter->GmacHw->synopGMACdev->DmaBase             = GigAdapter->GmacHw->synopGMACdev->MacBase + DMABASE;

  GigAdapter->GmacHw->synopGMACdev->Version             = synopGMAC_read_version(GigAdapter->GmacHw->synopGMACdev);
  GigAdapter->GmacHw->synopGMACdev->vendor_id           = PciConfigHeader->VendorId;
  GigAdapter->GmacHw->synopGMACdev->device_id           = PciConfigHeader->DeviceId;
  GigAdapter->GmacHw->synopGMACdev->subsystem_vendor_id = PciConfigHeader->SubVendorId;
  GigAdapter->GmacHw->synopGMACdev->subsystem_device_id = PciConfigHeader->SubSystemId;
  GigAdapter->GmacHw->synopGMACdev->revision_id         = (UINT8) PciConfigHeader->RevId;
  GigAdapter->GmacHw->synopGMACdev->function_id         = GigAdapter->Function;
  GigAdapter->GmacHw->synopGMACdev->MaxReinitCnt        = 0;
  
#define DEBUG_PRINT
#ifdef DEBUG_PRINT
  DbgPrint(DEBUG_INFO,"  GigAdapter->Hw.GmacDev.MacBase:0x%llx\n",GigAdapter->GmacHw->synopGMACdev->MacBase);
  //0x80000e0027278000
  DbgPrint(DEBUG_INFO,"  GigAdapter->Hw.GmacDev.DmaBase:0x%llx\n",GigAdapter->GmacHw->synopGMACdev->DmaBase);
  //0x80000E0027279000
  DbgPrint(DEBUG_INFO,"  subsystem_vendor_id           :0x%08x\n",PciConfigHeader->SubVendorId);//0x00000000 
  DbgPrint(DEBUG_INFO,"  subsystem_device_id           :0x%08x\n",PciConfigHeader->SubSystemId);//0x00000000
  DbgPrint(DEBUG_INFO,"  Version                       :0x%08x\n",GigAdapter->GmacHw->synopGMACdev->Version);//0x0000D137
#endif
  GigAdapter->GmacHw->synopGMACdev->mac.autoneg            = TRUE;
  GigAdapter->GmacHw->synopGMACdev->phy.autoneg_wait_to_complete = FALSE;
  GigAdapter->GmacHw->synopGMACdev->phy.reset_disable      = FALSE;
  GigAdapter->GmacHw->synopGMACdev->phy.autoneg_advertised = GMAC_ALL_SPEED_DUPLEX;
  //全双工
  GigAdapter->GmacHw->synopGMACdev->phy.autoneg_mask       = AUTONEG_ADVERTISE_SPEED_DEFAULT;

  GigAdapter->PciClass    = (UINT8) ((PciConfigHeader->ClassId & PCI_CLASS_MASK) >> 8);
  GigAdapter->PciSubClass = (UINT8) (PciConfigHeader->ClassId) & PCI_SUBCLASS_MASK;
  
  GigAdapter->PciClass    = (UINT8) ((PciConfigHeader->ClassId & PCI_CLASS_MASK) >> 8);
  GigAdapter->PciSubClass = (UINT8) (PciConfigHeader->ClassId) & PCI_SUBCLASS_MASK;

  if (gmac_set_mac_type (GigAdapter->GmacHw->synopGMACdev) != GMAC_SUCCESS) {
    DEBUGPRINT (CRITICAL, ("Unsupported MAC type!\n"));
    return EFI_UNSUPPORTED;
  }

  if (gmac_setup_init_funcs (GigAdapter->GmacHw) != GMAC_SUCCESS) {
    DEBUGPRINT (CRITICAL, ("gmac_setup_init_funcs failed!\n"));
    return EFI_UNSUPPORTED;
  }

  ScStatus = gmac_init_hw (GigAdapter->GmacHw);
  if (ScStatus == GMAC_SUCCESS) {
    Status = EFI_SUCCESS;
    GigAdapter->HwInitialized = TRUE;
  } else {
    GigAdapter->HwInitialized = FALSE;
    Status = EFI_DEVICE_ERROR;
  }

  GigAdapter->CurTxInd = 0;
  GigAdapter->XmitDoneHead = 0;
  GigAdapter->CurRxInd = 0;


  return Status;
}
这里面重点说一下: gmac_setup_init_funcs
s32 gmac_setup_init_funcs(synopGMACNetworkAdapter *hw)
{
  s32 ret_val = -1;
  synopGMACdevice *Hw;

  ASSERT(hw != NULL);

  Hw = hw->synopGMACdev;

  ret_val = gmac_set_mac_type(Hw);
  if (ret_val) {
    DbgPrint(DEBUG_INFO,"mac type error!\n");
    return ret_val;
  }

  gmac_init_mac_info(Hw);
  gmac_init_phy_info(Hw);
  gmac_init_drv_info(Hw);

  return 0;
} 

void gmac_init_mac_info(synopGMACdevice *hw)
{
  u32 offset = 0, i = 0;
  u8  function = 0;
  bool InvalidMac = FALSE;
  EFI_LS_SERVICE_PROTOCOL   *Interface = NULL;
  EFI_STATUS  Status;

  gmac_mac_info *mac = &hw->mac;
  function = hw->function_id;

  ASSERT(mac != NULL );

  mac->ops.init       = synopGMAC_mac_init;
  mac->ops.reset      = synopGMAC_reset;
  mac->ops.power_up   = synopGMAC_linux_powerup_mac;
  mac->ops.power_down = synopGMAC_linux_powerdown_mac;

  Status = gBS->LocateProtocol (&gEfiLsServiceProtocolGuid, NULL, (VOID **)&Interface);
  ASSERT_EFI_ERROR (Status);

  offset = function == 0 ? 0x0:0x10;

  Status = Interface->ChipsetSpi.Read((EFI_LS_SPI_PROTOCOL *)&(Interface->ChipsetSpi),EfiDataWidthUint8,ETH_ADDR_LEN,offset,(VOID *)mac->addr);
  Status = Interface->ChipsetSpi.Read((EFI_LS_SPI_PROTOCOL *)&(Interface->ChipsetSpi),EfiDataWidthUint8,ETH_ADDR_LEN,offset,(VOID *)mac->perm_addr);

  CHECK_MACADDR(mac->addr,InvalidMac);

  if(InvalidMac) {
    DbgPrint(DEBUG_INFO,"  ###Read Mac Addr from 7a spi is invalid, Use Default Mac Addr!\n ");
    if(function == 0 ){
      CopyMem(mac->addr,mac0_addr,ETH_ADDR_LEN);
      CopyMem(mac->perm_addr,mac0_addr,ETH_ADDR_LEN);
    }else if( function == 1){
      CopyMem(mac->addr,mac1_addr,ETH_ADDR_LEN);
      CopyMem(mac->perm_addr,mac1_addr,ETH_ADDR_LEN);
    }else{
      ASSERT(0);
    }
  }

  DbgPrint(DEBUG_INFO,"  Gmac%d MAC ADDR:",function);
  for(i = 0; i< ETH_ADDR_LEN; i++){
    DbgPrint(DEBUG_INFO," 0x%x",mac->addr[i]);                                                                                                                                                                                              
  }
  DbgPrint(DEBUG_INFO,"\n");
}

可以看出来通过spi设置了mac地址.

再简要看一下:
void gmac_init_phy_info(synopGMACdevice *hw)
{
  gmac_phy_info *phy = &hw->phy;
  ASSERT( phy != NULL);

  phy->ops.init   = init_phy;
  phy->media_type = gmac_media_type_copper;
}

void gmac_init_drv_info(synopGMACdevice *hw)
{
  gmac_drv_info *drv = &hw->drv;
  ASSERT( drv != NULL);

  drv->attach  = synopGMAC_attach;
  drv->open    = synopGMAC_linux_open;
  drv->close    = synopGMAC_linux_close;
}

GmacFirstTimeInit 里面最后一个函数是:
ScStatus = gmac_init_hw (GigAdapter->GmacHw);
它主要完成了硬件的初始化,这里不再细说.
这样GmacFirstTimeInit就执行完了.
InitController函数执行完毕之后,还执行了:
    Status = InitControllerProtocols (
               UndiPrivateData,
               Controller
             );

InitControllerProtocols 里面安装了gEfiNiiPointerGuid协议
那么Status = InitController (UndiPrivateData);这个函数也就基本上执行完毕了.

start函数里面再往下是:
  if (InitializeChild) {
    DbgPrint (EFI_D_INFO,"ly_test----InitUndiStructures now----\n");
    InitUndiStructures (UndiPrivateData);

    Status = InitChild (UndiPrivateData);
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("InitChild failed with %r\n", Status));
      goto UndiErrorDeleteDevicePath;
    }    

    Status = InitChildProtocols (
               UndiPrivateData
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("InitChildProtocols failed with %r\n", Status));
      goto UndiErrorDeleteDevicePath;
    }    
    Status = OpenChildProtocols (
               UndiPrivateData,
               This,
               Controller
             );
    if (EFI_ERROR (Status)) {
      DEBUGPRINT (CRITICAL, ("OpenChildProtocols failed with %r\n", Status));
    }    
    UndiPrivateData->IsChildInitialized = TRUE;
  }

首先看一下 InitUndiStructures (UndiPrivateData);
/** Initializes UNDI (PXE) structures
	初始化PXE的结构

   @param[in]       UndiPrivateData        Private data structure
  
   @retval          None
**/
VOID
InitUndiStructures (
  IN UNDI_PRIVATE_DATA *UndiPrivateData
  )
{   
  // the IfNum index for the current interface will be the total number
  // of interfaces initialized so far
  GigUndiPxeUpdate (&UndiPrivateData->NicInfo, mGMACPxe31);
  InitUndiCallbackFunctions (&UndiPrivateData->NicInfo);
}

在往下是
Status = InitChild (UndiPrivateData); 和
Status = InitChildProtocols (
           UndiPrivateData
         );
 在子句柄中也安装gEfiNiiPointerGuid协议
 这样我们就可以从父句柄或子句柄中获得NII协议。
 注意在InitChildProtocols 里面又调用了
 Status = InitAdapterInformationProtocol (UndiPrivateData); 
 在 InitAdapterInformationProtocol 里面安装了gEfiAdapterInformationProtocolGuid,
 Status = gBS->InstallProtocolInterface (
              &UndiPrivateData->DeviceHandle,
              &gEfiAdapterInformationProtocolGuid,
              EFI_NATIVE_INTERFACE,
              &UndiPrivateData->AdapterInformation                                                                                                                                                                                      
            );
  
在start函数的最后,创建了一个定时器事件,每隔2秒去调用GmacReInit
  Status = gBS->CreateEvent (
                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  GmacReInit,                                                                                                                                                                                         
                  (UndiPrivateData->NicInfo.GmacHw),
                  &(UndiPrivateData->NicInfo.GmacHw->synopGMACdev->ReInit)
                  );   

  if (EFI_ERROR (Status)) {
    ASSERT(0);
    return Status;
  }

  Status = gBS->SetTimer (UndiPrivateData->NicInfo.GmacHw->synopGMACdev->ReInit, TimerPeriodic, (UINT64)CHECK_INIT_PERIOD);

GmacReInit  里面会不断的检查连接模式和链接速度,如果Phy没有连接成功,则会不断的
初始化硬件,初始化Phy并重启mac.
u32 gmac_init_hw(synopGMACNetworkAdapter * hw)
{
  s32 ret = 0;
  s32 i = 0;                                                                                                                                                                                                          

  ASSERT(hw != NULL);

  for(i = 0; i< RECEIVE_DESC_SIZE; i++){
    if(hw->synopGMACdev->Rxqptr[i] != 0){
      //DbgPrint(DEBUG_INFO,"  FreeRxBuf = 0x%llx\n",hw->synopGMACdev->Rxqptr[i]);
      FreePool((void *)hw->synopGMACdev->Rxqptr[i]);
    }
  }

  DbgPrint(DEBUG_INFO,"  init gmac hardware begin\n");
  if(hw->synopGMACdev->drv.attach != NULL){
    ret = hw->synopGMACdev->drv.attach(hw->synopGMACdev,DEFAULT_PHY_BASE,hw->synopGMACdev->mac.addr);
    if(ret != 0 ){
        DbgPrint(DEBUG_INFO,"### drv.attach Error!\n");
        return ret;
    }
    GmacDelay(0x10000);
  }

  if(hw->synopGMACdev->phy.ops.init != NULL){
    ret = hw->synopGMACdev->phy.ops.init(hw->synopGMACdev);
    if(ret != 0 ){
        DbgPrint(DEBUG_INFO,"### phy.ops.init Error!\n");
        return ret;
    }
    GmacDelay(0x10000);
  }

  if(hw->synopGMACdev->mac.ops.reset != NULL){
    ret = hw->synopGMACdev->mac.ops.reset(hw->synopGMACdev);
    if(ret != 0 ){
        DbgPrint(DEBUG_INFO,"### mac.ops.reset Error!\n");
        return ret;
    }
    GmacDelay(0x10000);
  }

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘德华海淀分华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值