/* **********************************************************
 * Copyright 1998 - 2010 VMware, Inc.  All rights reserved.
 * **********************************************************/

/*
 * @VMKAPIMOD_LICENSE@
 */

/*
 ***********************************************************************
 * Slabs                                                          */ /**
 * \defgroup Slab Slab Allocation
 * @{
 *
 * ESX Server supports slab allocation for high performance driver/stack
 * implementations:
 * - Reduces memory fragmentation, especially for smaller data structures
 *   allocated in high volume.
 * - Reduces CPU consumption for data structure initialization/teardown.
 * - Improves CPU hardware cache performance.
 * - Provides finer grained control of memory consumption.
 *
 ***********************************************************************
 */

#ifndef _VMKAPI_SLAB_H_
#define _VMKAPI_SLAB_H_

/** \cond never */
#ifndef VMK_HEADER_INCLUDED_FROM_VMKAPI_H
#error This vmkapi file should never be included directly but only via vmkapi.h
#endif
/** \endcond never */

/**
 * \brief Opaque handle for a slab cache.
 */
typedef struct vmk_SlabIDInt *vmk_SlabID;

#define VMK_INVALID_SLAB_ID ((vmk_SlabID)NULL)

/**
 * \brief Constant for specifying an unlimited number of slab objects.
 */
#define VMK_SLAB_MAX_UNLIMITED ((vmk_ByteCountSmall) -1)

/*
 ***********************************************************************
 * vmk_SlabItemConstructor --                                     */ /**
 *
 * \brief Item constructor - optional user defined function.  Runs for
 *                           each object when a cluster of memory is
 *                           allocated from the heap.
 *
 * \note   When the control structure is placed inside the free object,
 *         then the constructor must take care not to modify the control
 *         structure.
 *
 * \note   A callback of this type must not block or call any API
 *         functions that may block.
 *
 * \param[in] object     Object to be constructed.
 * \param[in] size       Size of buffer (possibly greater than objSize).
 * \param[in] arg        constructorArg (see vmk_SlabCreateProps).
 * \param[in] flags      Currently unused (reserved for future use).
 *
 * \retval VMK_OK to indicate object construction has succeded.
 * \return Other To indicate failure.
 *
 ***********************************************************************
 */
typedef VMK_ReturnStatus (*vmk_SlabItemConstructor)(void *object,
                                                    vmk_ByteCountSmall size,
                                                    vmk_AddrCookie arg,
                                                    int flags);


/*
 ***********************************************************************
 *  vmk_SlabItemDestructor --                                     */ /**
 *
 * \brief Item destructor - optional user defined function.  Runs for
 *                          each buffer just before a cluster of memory
 *                          is returned to the heap.
 *
 * \note   When the control structure is placed inside the free object,
 *         then the destructor must take care not to modify the control
 *         structure.
 *
 * \note   A callback of this type must not block or call any API
 *         functions that may block.
 *
 * \param[in] object     Object to be destroyed.
 * \param[in] size       Size of buffer (possibly greater than objSize).
 * \param[in] arg        constructorArg (see vmk_SlabCreateProps).
 *
 ***********************************************************************
 */
typedef void (*vmk_SlabItemDestructor)(void *object, vmk_ByteCountSmall size,
                                       vmk_AddrCookie arg);

/**
 * \brief Memory requirements for slabs.
 */
typedef struct vmk_SlabMemSize {
   /** \brief Minimum number of memory pages this slab will occupy. */
   vmk_uint32 minPages;
   
   /** \brief Maximum number of memory pages this slab will occupy. */
   vmk_uint32 maxPages;
} vmk_SlabMemSize;


/**
 * \brief Types of slab
 */
typedef enum vmk_SlabType {
   /** 
    * \brief Slabs that get their own memory pool. 
    *
    * Slabs of type VMK_SLAB_TYPE_SIMPLE get a contiguity of
    * VMK_MEM_PHYS_ANY_CONTIGUITY and a physical address constraint
    * of VMK_PHYS_ADDR_ANY.  For slabs with different constraints,
    * use type VMK_SLAB_TYPE_CUSTOM or VMK_SLAB_TYPE_MEMPOOL.
    */
   VMK_SLAB_TYPE_SIMPLE = 0,

   /** \brief Slabs with custom memory properties. */
   VMK_SLAB_TYPE_CUSTOM = 1,

   /** \brief Slabs whose memory comes from an existing memPool. */
   VMK_SLAB_TYPE_MEMPOOL = 2,
   
} vmk_SlabType;

/**
 * \brief Properties of a slab allocator
 */
typedef struct vmk_SlabCreateProps {
   /** \brief Type of slab */
   vmk_SlabType type;

   /**
    * \brief Name of the slab.
    */
   vmk_Name name;

   /** \brief Module ID of the module creating this slab. */
   vmk_ModuleID module;

   /** 
    * \brief Byte Size of each object 
    *
    * objSize must be at least 1 byte and not more than the value
    * returned by vmk_SlabGetMaxObjectSize().
    **/
   vmk_ByteCountSmall objSize;

   /** 
    * \brief Byte alignment for each object 
    *
    * The alignment must be a power of 2, and it must be less than or
    * equal to VMK_PAGE_SIZE.
    */
   vmk_ByteCountSmall alignment;

   /** \brief Called after an object is allocated (or NULL for no action) */
   vmk_SlabItemConstructor constructor;
   
   /** \brief Called before an object is freed (or NULL for no action) */
   vmk_SlabItemDestructor destructor;

   /** \brief Argument for constructor/destructor calls */
   vmk_AddrCookie constructorArg;

   /** 
    * \brief Offset in allocation for slab control structure.
    * \sa vmk_SlabControlSize
    */
   vmk_ByteCountSmall ctrlOffset;

   /** \brief Minimum number of objects allocatable from this slab. */
   vmk_uint32 minObj;
   
   /** \brief Maximum number of objects allocatable from this slab. */
   vmk_uint32 maxObj;

   /** \brief How long to wait for memory during slab creation. */
   vmk_uint32 creationTimeoutMS;

   /** \brief Type-specific slab properties */
   union {
      /** \brief Properties for VMK_SLAB_TYPE_CUSTOM. */
      struct {
         /** \brief Physical contiguity of objects allocated from this slab. */
         vmk_MemPhysContiguity physContiguity;
         
         /** \brief Physical address restrictions. */
         vmk_MemPhysAddrConstraint physRange;
      } custom;

      /** \brief Properties for VMK_SLAB_TYPE_MEMPOOL. */
      struct {
         /** \brief Physical contiguity allocated from this slab. */
         vmk_MemPhysContiguity physContiguity;
         
         /** \brief Physical address restrictions. */
         vmk_MemPhysAddrConstraint physRange;

         /** \brief Memory pool. */
         vmk_MemPool memPool;
      } memPool;

   } typeSpecific;
} vmk_SlabCreateProps;


/**
 * \brief Properties structure for querying a slab allocator.
 */
typedef struct vmk_SlabGetProps {
   /** \brief Name of the slab. */
   vmk_Name name;

   /** \brief Module ID of the module creating this slab. */
   vmk_ModuleID module;

   /** \brief Byte Size of each object. */
   vmk_ByteCountSmall objSize;

   /** 
    * \brief Byte alignment for each object 
    */
   vmk_ByteCountSmall alignment;

   /** \brief Called after an object is allocated (or NULL for no action) */
   vmk_SlabItemConstructor constructor;
   
   /** \brief Called before an object is freed (or NULL for no action) */
   vmk_SlabItemDestructor destructor;

   /** \brief Argument for constructor/destructor calls */
   vmk_AddrCookie constructorArg;

   /** \brief Offset in allocation for slab control structure. */
   vmk_ByteCountSmall ctrlOffset;

   /** \brief Minimum number of objects allocatable from this slab. */
   vmk_uint32 minObj;
   
   /** \brief Maximum number of objects allocatable from this slab. */
   vmk_uint32 maxObj;

   /** \brief Physical contiguity allocated from this slab. */
   vmk_MemPhysContiguity physContiguity;

   /** \brief Physical address restrictions. */
   vmk_MemPhysAddrConstraint physRange;

   /** \brief Memory pool. */
   vmk_MemPool memPool;
} vmk_SlabGetProps;


/*
 ***********************************************************************
 *  vmk_SlabCreate --                                             */ /**
 *
 * \brief Create a slab allocator cache.
 *
 * A slab is created with the specified creation properties.  Enough 
 * memory is allocated for props->minObj to be created.  Slab creation 
 * will fail if enough memory cannot be allocated.
 *
 * \note   This function may block if creationTimeoutMS is not 
 *         VMK_TIMEOUT_NONBLOCKING.
 *
 * \param [in]  props      Properties of the new cache.
 * \param [out] cache      For use with vmk_SlabAlloc, etc.
 *
 * \retval VMK_OK          indicates that the slab was created.
 * \retval VMK_BAD_PARAM   indicates that some slab parameters were
 *                         invalid.
 * \retval VMK_NO_MEMORY   indicates that insufficient memory was
 *                         available.
 * \retval VMK_TIMEOUT     indicates that the timeout was reached before
 *                         enough memory could be allocated.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_SlabCreate(vmk_SlabCreateProps *props,
                                vmk_SlabID *cache);


/*
 ***********************************************************************
 *  vmk_SlabAlloc --                                              */ /**
 *
 * \brief Allocate an item from a slab.
 *
 * The vmk_SlabItemConstructor (if defined) was previously called,
 * or the object was previously freed via vmk_SlabFree().
 *
 * If the slab is not yet at maximum size, this function may attempt to
 * allocate additional physical memory to satisfy the allocation request.
 * If physical memory is not currently available, this function will not
 * block to wait for memory to become available.
 *
 * \note   When the control structure is placed inside the free object,
 *         the caller of vmk_SlabAlloc() must assume this portion of
 *         the object is uninitialized.
 *
 * \note   This function will not block.
 *
 * \param[in] cache      Slab from which allocation will take place.
 *
 * \retval NULL   Memory could not be allocated.
 *
 ***********************************************************************
 */
void *vmk_SlabAlloc(vmk_SlabID cache);


/*
 ***********************************************************************
 *  vmk_SlabAllocWithTimeout --                                   */ /**
 *
 * \brief Allocate an item, possibly waiting for physical memory.
 *
 * The vmk_SlabItemConstructor (if defined) was previously called,
 * or the object was previously freed via vmk_SlabFree().
 *
 * If the slab is not yet at maximum size, this function may attempt to
 * allocate additional physical memory to satisfy the allocation request.
 * If physical memory is not currently available, this function will use
 * the value of timeout to determine if it may block until memory is
 * available, and if so, for how long.
 *
 * \note   When the control structure is placed inside the free object,
 *         the caller of vmk_SlabAlloc() must assume this portion of
 *         the object is uninitialized.
 *
 * \note   This function may block.
 *
 * \param[in] cache      Slab from which allocation will take place.
 * \param[in] timeoutMS  Timeout specifying how long the call may wait.
 *
 * \retval NULL   Memory could not be allocated.
 *
 ***********************************************************************
 */
void *vmk_SlabAllocWithTimeout(
   vmk_SlabID cache,
   vmk_uint32 timeoutMS);

/*
 ***********************************************************************
 *  vmk_SlabFree --                                               */ /**
 *
 * \brief Free memory allocated by vmk_SlabAlloc.
 *
 * The memory object will be retained by the slab.  If at some point 
 * the slab chooses to give the memory back to the system, the
 * vmk_SlabItemDestructor (if defined) will be called.
 *
 * \note   This function will not block.
 *
 * \param[in] cache      Slab from which the item was allocated.
 * \param[in] object     object to be freed.
 *
 ***********************************************************************
 */
void vmk_SlabFree(
   vmk_SlabID cache,
   void *object);


/*
 ***********************************************************************
 *  vmk_SlabDestroy --                                            */ /**
 *
 * \brief Destroy a slab cache previously created by vmk_SlabCreate.
 *
 * \note   This function may block.
 *
 * \param[in] cache      The cache to be destroyed.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_SlabDestroy(vmk_SlabID cache);


/*
 ***********************************************************************
 *  vmk_SlabControlSize --                                        */ /**
 *
 * \brief  Get the size of the per-object "control" structure.
 *
 * The slab maintains a control structure for each free object
 * cached by the slab.  When VMK_SLAB_TYPE_SIMPLE properties are
 * used to create the slab, the control structure will be tacked
 * past the end of the client's object.  To save space, the control
 * structure can be placed within the user's free object using the
 * ctrlOffset paramter to VMK_SLAB_TYPE_NOMINAL properties.
 *
 * \note   For best performance, it is recommended that the control structure
 *         offset is a multiple of sizeof (void *), but this is not a
 *         requirement.
 *
 * \note   See vmk_SlabItemConstructor, vmk_SlabItemDestructor and
 *         and vmk_SlabAlloc for the constraints that must be obeyed
 *         when the control structure is placed inside the object.
 *
 * \note   This function will not block.
 *
 * \return Size of the control structure in bytes.
 *
 ***********************************************************************
 */
vmk_ByteCountSmall vmk_SlabControlSize(void);

/*
 ***********************************************************************
 *  vmk_SlabGetMemSize --                                         */ /**
 *
 * \brief  Returns the memory requirements for a slab.
 *
 * This function computes the minimum and maximum required
 * memory for a slab with the provided characteristics.
 *
 * For a slab of type VMK_SLAB_TYPE_MEMPOOL, the provided memPool
 * may be VMK_MEMPOOL_LEGACY_INVALID, so this function can be used
 * to compute needed sizes for constructing a memory pool.
 *
 * \note   This function will not block.
 *
 * \return VMK_BAD_PARAM   minObj and maxObj were inconsistent,
 *                         or maxObj was VMK_SLAB_MAX_UNLIMITED
 *                         for a slab of type VMK_SLAB_TYPE_SIMPLE or
 *                         VMK_SLAB_TYPE_CUSTOM.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_SlabGetMemSize(vmk_SlabCreateProps   *props,
                                    vmk_SlabMemSize *size);


/*
 ***********************************************************************
 *  vmk_SlabGetProperties --                                      */ /**
 *
 * \brief  Returns the allocation properties for a slab.
 *
 * \note   This function will not block.
 *
 * \return VMK_OK          Properties is filled in.
 * \return VMK_NOT_FOUND   slab was not a valid slab handle.
 *
 ***********************************************************************
 */

VMK_ReturnStatus
vmk_SlabGetProperties(vmk_SlabID slab, vmk_SlabGetProps *props);


/*
 ***********************************************************************
 *  vmk_SlabGetMaxObjectSize --                                   */ /**
 *
 * \brief  Returns the maximum allowed size for an object
 *
 * \note   This function will not block.
 *
 * \return Max Object size
 *
 ***********************************************************************
 */

vmk_ByteCountSmall
vmk_SlabGetMaxObjectSize(vmk_ByteCountSmall alignment);


#endif /* _VMKAPI_SLAB_H_ */
/** @} */