Thanks Andrew,

I did a simple experiment on Dellr720 server for allocating PCIe DMA
capable memory. This server has 64GB of physical memory.

First experiment:
--------------------------

In option ROM driver  start function, i tried  allocating different sizes
of memory allocation ( from 128MB to 4GB of memory) with PCI AllocateBuffer
and Map function. Driver successfully allocated and maped  up to 2GB.  But
It failed to allocate 3GB of memory.

Attached the driver source code file.

Here is my question:
1) Why i am not able to allocate more than 3GB of memory eventhough system
has 64GB of physical memory?


Thanks
Sateesh



On Thu, May 9, 2013 at 10:07 PM, Andrew Fish <[email protected]> wrote:

>
> On May 9, 2013, at 6:50 AM, satish kondapalli <[email protected]>
> wrote:
>
> > Hi,
> >
> > I have DellR720 server with 16GB of physical Memory. I am testing the
> option ROM driver on this server and my  driver is executed successfully.
>  But while booting Linux from hard disk it failed with the following error
> message on screen
> > "can not allocate memory Failed to allocate scratch mem!".
> >
> > If i remove my card from server its booted fine.
> >
> > Here is my question:
> > 1) In UEFI, is there any memory allocation size restriction?(In my
> driver i allocated  EfiBootServicesData memory.)
> > 2) is it possible to allocate 4GB of pcie DMA capable memory? In my case
> it failed for 64MB.
>
> The only legal way to allocate a DMA buffer is to use
> EFI_PCI_IO_PROTOCOL.AllocateBuffer() and then call
> EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Map() with an Operation like
> EfiPciOperationBusMasterCommonBuffer64.
>
>
> > 3) if i want a 4GB of PCIe DMA capable memory how to allocate?
> >
>
>
> 13.4 EFI PCI I/O Protocol - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Map()
>
> Bus master operations that require both read and write access or require
> multiple host device interactions within the same mapped region must use
> EfiPciOperation- BusMasterCommonBuffer or
> EfiPciOperationBusMasterCommonBuffer64. However, only memory allocated via
> the AllocateBuffer() interface can be mapped for this type of operation.
>
> In all mapping requests the resulting NumberOfBytes actually mapped may be
> less than the requested amount. In this case, the DMA operation will have
> to be broken up into smaller chunks. The Map() function will map as much of
> the DMA operation as it can at one time. The caller may have to loop on
> Map() and Unmap() in order to complete a large DMA transfer.
>
>
> Note: If you map as EfiPciOperationBusMasterCommonBuffer or
> EfiPciOperationBusMasterCommonBuffer64 you don't need to Map() and Unmap()
> on each DMA transfer.
>
> Thanks,
>
> Andrew Fish
>
> PS DMA coherency is for the most part handled in hardware on a PC so not
> following the rules may appear to work. But if you port that driver to ARM
> it will fail horribly. Not to mention a massively parallel high end X64
> system could fail too if you don't follow the rules.
>
> PPS Don't assume that the address of the DMA buffer is the same from the
> CPU and PCI perspective. The PCI card needs to use DeviceAddress, and it
> does not have to be the same as the HostAddress. The EFI DMA flows our
> outlined in13.2 PCI Root Bridge I/O Protocol:
>
> DMA Bus Master Read Operation
> • Call Map() for EfiPciOperationBusMasterRead or
> EfiPciOperationBusMasterRead64.
> • Program the DMA Bus Master with the DeviceAddress returned by Map().
> • Start the DMA Bus Master.
> • Wait for DMA Bus Master to complete the read operation.
> • Call Unmap().
>
> DMA Bus Master Write Operation
> • Call Map() for EfiPciOperationBusMasterWrite or
> EfiPciOperationBusMasterRead64.
> • Program the DMA Bus Master with the DeviceAddress returned by Map().
> • Start the DMA Bus Master.
> • Wait for DMA Bus Master to complete the write operation.
> • Perform a PCI controller specific read transaction to flush all PCI
> write buffers (See PCI Specification Section 3.2.5.2) .
> • Call Flush().
> • Call Unmap().
>
> DMA Bus Master Common Buffer Operation
> • Call AllocateBuffer() to allocate a common buffer.
> • Call Map() for EfiPciOperationBusMasterCommonBuffer or
> EfiPciOperationBusMasterCommonBuffer64.
> • Program the DMA Bus Master with the DeviceAddress returned by Map().
> • The common buffer can now be accessed equally by the processor and the
> DMA bus master.
> • Call Unmap().
> • Call FreeBuffer().
>
>
> > Thanks
> > Sateesh
> >
> >
> ------------------------------------------------------------------------------
> > Learn Graph Databases - Download FREE O'Reilly Book
> > "Graph Databases" is the definitive new guide to graph databases and
> > their applications. This 200-page book is written by three acclaimed
> > leaders in the field. The early access version is available now.
> > Download your free book today!
> http://p.sf.net/sfu/neotech_d2d_may_______________________________________________
> > edk2-devel mailing list
> > [email protected]
> > https://lists.sourceforge.net/lists/listinfo/edk2-devel
>
>
>
> ------------------------------------------------------------------------------
> Learn Graph Databases - Download FREE O'Reilly Book
> "Graph Databases" is the definitive new guide to graph databases and
> their applications. This 200-page book is written by three acclaimed
> leaders in the field. The early access version is available now.
> Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
> _______________________________________________
> edk2-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/edk2-devel
>
/*
 * Copyright (c) 2009-2011
 *     Virident Systems, Inc., Milpitas, CA 95034
 *  
 * Copying is strictly prohibited without explicit written permission
 * from Virident Systems, Inc. 
 * 
 * Description: 
 *   This file is to validate the Vendor ID, Device ID and registers 
 *   BLOCK_IO_PROTOCOL for MC-NOR flash.
 *
 */



#include "SpDrv.h"


EFI_DRIVER_BINDING_PROTOCOL gSpDriverBinding = {
  SpDriverBindingSupported,
  SpDriverBindingStart,
  SpDriverBindingStop,
  0xa,
  NULL,
  NULL
};


/**
  The user code starts with this function.

  @param  ImageHandle    The firmware allocated handle for the EFI image.  
  @param  SystemTable    A pointer to the EFI System Table.
  
  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
SpMain(
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
    EFI_STATUS          Status=0;
  //
  // Install driver model protocol(s).
  //
  Status = EfiLibInstallDriverBinding (
		  ImageHandle,
		  SystemTable,
		  &gSpDriverBinding,
		  ImageHandle);

  ASSERT_EFI_ERROR (Status);
     
  return Status;
}


/**
  Test to see if this driver supports ControllerHandle.

  This service is called by the EFI boot service ConnectController(). In order
  to make drivers as small as possible, there are a few calling restrictions for
  this service. ConnectController() must follow these calling restrictions.
  If any other agent wishes to call Supported() it must also follow these
  calling restrictions.

  @param  This                Protocol instance pointer.
  @param  ControllerHandle    Handle of device to test
  @param  RemainingDevicePath Optional parameter use to pick a specific child
                              device to start.

  @retval EFI_SUCCESS         This driver supports this device
  @retval EFI_ALREADY_STARTED This driver is already running on this device
  @retval other               This driver does not support this device

**/
EFI_STATUS
EFIAPI
SpDriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
  )
{

  EFI_STATUS            Status;
  UINT16 VendorID = 0;
  UINT16 DeviceID = 0;
  EFI_PCI_IO_PROTOCOL  *PciIo;

  

  // open PCI protocol
  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiPciIoProtocolGuid,
		  (VOID **) &PciIo,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  
  //Read deviceID and vendorID
  PciIo->Pci.Read (
  		PciIo,
  		EfiPciIoWidthUint16,
  		0,  // word 0,1 = VendorID
		1,
  		&VendorID
  		);

  PciIo->Pci.Read (
  		PciIo,
  		EfiPciIoWidthUint16,
 		2,  // words 2,3 = DeviceID
		1,
  		&DeviceID
  		);

  gBS->CloseProtocol (
         Controller,
         &gEfiPciIoProtocolGuid,
         This->DriverBindingHandle,
         Controller
         );

	if (VendorID == my_vendor_id) {
		return EFI_SUCCESS;
	} else {
		return EFI_UNSUPPORTED;
	}
	
}


/**
  Start this driver on ControllerHandle.

  This service is called by the EFI boot service ConnectController(). In order
  to make drivers as small as possible, there are a few calling restrictions for
  this service. ConnectController() must follow these calling restrictions. If
  any other agent wishes to call Start() it must also follow these calling
  restrictions.

  @param  This                 Protocol instance pointer.
  @param  ControllerHandle     Handle of device to bind driver to
  @param  RemainingDevicePath  Optional parameter use to pick a specific child
                               device to start.

  @retval EFI_SUCCESS          This driver is added to ControllerHandle
  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
  @retval other                This driver does not support this device

**/


EFI_STATUS
EFIAPI
SpDriverBindingStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
  )
{
	EFI_STATUS 	     Status;
	EFI_PCI_IO_PROTOCOL  *PciIo;
	UINTN   NumPages;
	VOID *HostAddr,*Mapping;
	EFI_PHYSICAL_ADDRESS DeviceAddr;
	UINTN NumberOfBytes,Length;

Print(L"INSIDE START Function\n");
	Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiPciIoProtocolGuid,
		  (VOID **) &PciIo,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
	
	if (EFI_ERROR (Status)) {
		return Status;
	}


	// Enable PCI device.

        Status = PciIo->Attributes(
                        PciIo,
                        EfiPciIoAttributeOperationEnable,
                        EFI_PCI_DEVICE_ENABLE,
                        NULL
                        );

        if (EFI_ERROR (Status)) {
                return Status;
        }
	
	//Length = 0x200000000; //8GB
	//Length = 0x100000000; //4GB
	Length = 0xC0000000; //3GB
	//Length = 0x80000000; //2GB
	//Length = 0x40000000; //1GB
	//Length = 0x20000000; //512MB
	//Length = 0x8000000; //128MB
	//Length = 0x4000000; //64MB
	NumPages = EFI_SIZE_TO_PAGES(Length);
	Status    = PciIo->AllocateBuffer(
			PciIo, 
			AllocateAnyPages, 
			EfiBootServicesData, 
			NumPages,
                        &HostAddr, 
			0);
        if (EFI_ERROR (Status)) {
                Print(L"\n AllocateBuffer Failed::******\n");
                return Status;
        }

	NumberOfBytes = Length;

	Status= PciIo->Map ( PciIo,
			EfiPciIoOperationBusMasterCommonBuffer,
			HostAddr,
			&NumberOfBytes,
			&DeviceAddr,
			&Mapping );

	if (!EFI_ERROR (Status) && NumberOfBytes != Length) {
		Print(L"Map Failed**************\n");
		PciIo->Unmap (PciIo, Mapping);
		Status = EFI_OUT_OF_RESOURCES;
	}
	if (EFI_ERROR (Status)) {
		PciIo->FreeBuffer (
				PciIo,
				EFI_SIZE_TO_PAGES (Length),
				HostAddr
				);
		return Status;
	}
	//
	// Write the DMA start add

	Print(L"Allocated successfully\n");
 	return EFI_SUCCESS;

}


/**
  Stop this driver on ControllerHandle.

  This service is called by the EFI boot service DisconnectController().
  In order to make drivers as small as possible, there are a few calling
  restrictions for this service. DisconnectController() must follow these
  calling restrictions. If any other agent wishes to call Stop() it must
  also follow these calling restrictions.
  
  @param  This              Protocol instance pointer.
  @param  ControllerHandle  Handle of device to stop driver on
  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
                            children is zero stop the entire bus driver.
  @param  ChildHandleBuffer List of Child Handles to Stop.

  @retval EFI_SUCCESS       This driver is removed ControllerHandle
  @retval other             This driver was not removed from this device

**/
EFI_STATUS
EFIAPI
SpDriverBindingStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
  IN  EFI_HANDLE                      Controller,
  IN  UINTN                           NumberOfChildren,
  IN  EFI_HANDLE                      *ChildHandleBuffer   OPTIONAL
  )
{
	
	gBS->CloseProtocol (
			Controller,
			&gEfiPciIoProtocolGuid,
			This->DriverBindingHandle,
			Controller
			);

	return EFI_SUCCESS;
}
------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and 
their applications. This 200-page book is written by three acclaimed 
leaders in the field. The early access version is available now. 
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to