#ifndef PHSTBNETDEV_INTERNAL_H    /* Multi-include protection.   <FILENAME>_H */
#define PHSTBNETDEV_INTERNAL_H

/*****************************************************************************/
/* Copyright (c) 2008 NXP B.V.                                               */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation, using version 2 of the License.             */
/*                                                                           */
/* This program is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
/* GNU General Public License for more details.                              */
/*                                                                           */
/* You should have received a copy of the GNU General Public License         */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307       */
/* USA.                                                                      */
/*                                                                           */
/*****************************************************************************/
/*  Copyright (C) 2008 NXP B.V.
    All Rights Reserved.
*//**
    @file   phStbNetDev_Internal.h
    @brief  Internal header file for this component.

@b  Component:  phStbNetDev

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20061207   batelaan    Initial
  2 20070501   batelaan    Use mutex instead of disabling interrupts, since we
                           don't lock from interrupt context anymore.
  3 20070611   steel       fix cache race condition
  4 20070919   batelaan    Refactor common things
  5 20070921   batelaan    Portability improvement
  6 20070925   batelaan    Add phStbNetDev_CreatePool.
  7 20071030   batelaan    Add MAC address macros
  8 20071217   batelaan    Add phStbNetDev_SetupPool
8.1.1 20080422 batelaan    Update file header
  9 20080418   batelaan    Change use of volatile.
 10 20080423   batelaan    Merge 8.1.1
 11 20080529   batelaan    Fix comment warning
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/*******************
* INCLUDE FILES    *
********************/

#include <tmNxTypes.h>
#if !PH_STBNETDEV_DEBUG
  #define MSG_DBG_ENABLE 0
#endif
#include <phStbCommon.h>

#include <phStbNetDev.h>
#include <phStbNetDev_Mailbox.h>
#if TMFL_OS_IS_LINUX
  #include <linux/phStbNetDev_Linux_Internal.h>
#endif
#if TMFL_OS_IS_CE
  #include <ce/phStbNetDev_CE_Internal.h>
#endif

/**************************************************************************
* EXPORTED MACROS                          PH_STBTEMPLATE_<_WORD>+        *
***************************************************************************/

#define MSG_LPRINT_LEVEL gphStbNetDev_Debug
#define ERRPRINT(_expr) MSG_PRINT(_expr)

/** Default maximum percentage of the total packet count that any cpu can use.
    @see share */
#define PH_STBNETDEV_SHARE_DEFAULT 85U

/** Mapped uncached (KSEG1) address of ::gpStbNetDev_Pool. This is a
    cast to ::pphStbNetDev_Pool_t of ::gpStbNetDev_PoolPhys, which stores the actual
    physical address. */
#define PH_STBNETDEV_POOL_HEADER ((pphStbNetDev_Pool_t)gpStbNetDev_PoolPhys)->header

/** @def PH_STBNETDEV_ID_SELF
    Process id (0 or 1) for the phStbNetDev_Lock() / phStbNetDev_Unlock() functionality.
    The control CPU is 0, the dsp is 1.*/
/** @def PH_STBNETDEV_ID_PEER
    Opposite of #PH_STBNETDEV_ID_SELF.
    The control CPU is 1, the dsp is 0.*/
#if PH_STBNETDEV_DSP
  #define PH_STBNETDEV_ID_SELF 1
  #define PH_STBNETDEV_ID_PEER 0
#else
  #define PH_STBNETDEV_ID_SELF 0
  #define PH_STBNETDEV_ID_PEER 1
#endif

/** @def PH_STBNETDEV_SOURCE_ADDR
    A string containing 6 bytes giving the device source MAC address.
    For the control CPU this is "\0 IPCC".
    For the dsp CPU this is "\0 IPCD".
*/
/** @def PH_STBNETDEV_DEST_ADDR
    A string containing 6 bytes giving the device destination MAC address.
    For the control CPU this is "\0 IPCD".
    For the dsp CPU this is "\0 IPCC".
*/
#if PH_STBNETDEV_DSP
  #define PH_STBNETDEV_SOURCE_ADDR "\0 IPCD"
  #define PH_STBNETDEV_DEST_ADDR "\0 IPCC"
#else
  #define PH_STBNETDEV_SOURCE_ADDR "\0 IPCC"
  #define PH_STBNETDEV_DEST_ADDR "\0 IPCD"
#endif

/** Locks the packet pool from modification by peer CPU or other threads.
    @see PH_STBNETDEV_POOL_UNLOCK*/
#define PH_STBNETDEV_POOL_LOCK \
    do { \
        PH_STBNETDEV_POOL_LOCAL_LOCK; \
        phStbNetDev_Lock(&PH_STBNETDEV_POOL_HEADER.lock, PH_STBNETDEV_ID_SELF); \
    } while (0)

/** Unlocks the packet pool from modification by peer CPU or
    other threads.
    @see PH_STBNETDEV_POOL_LOCK */
#define PH_STBNETDEV_POOL_UNLOCK \
    do { \
        phStbNetDev_Unlock(&PH_STBNETDEV_POOL_HEADER.lock, PH_STBNETDEV_ID_SELF); \
        PH_STBNETDEV_POOL_LOCAL_UNLOCK; \
    } while (0)

/** MMIO access for an address. */
#ifndef MMIO
  #define MMIO(addr) (*((volatile ulong *)(addr)))
#endif

/** Size of header info in a ::phStbNetDev_Packet_t. */
#define PH_STBNETDEV_PACKET_HEADER_SIZE (sizeof(phStbNetDev_PacketHeader_t))

#ifdef ETH_DATA_LEN
  #if ETH_DATA_LEN != 1500
    #error Expecting ETH_DATA_LEN to be 1500
  #endif
#else
  #define ETH_DATA_LEN 1500
#endif

/*********************************************************************
* EXPORTED TYPEDEFS                      [p]phStbTemplate_<Word>+_t  *
**********************************************************************/

/** Mutual exclusion lock for 2 processes. */
typedef struct phStbNetDev_Lock {
    /* Set by a process if they want to get the lock. Value is the processId (0 or 1). */
    volatile Int turn;

    /* Stores whether a process is interested in the lock.
       Indexed by processId (0 or 1). */
    volatile Int interested[2];
    /* Create 32 byte separation between fields to prevent
       CDMMU caching. */
    unsigned char space[32];
    volatile Int guard;
} phStbNetDev_Lock_t;
typedef phStbNetDev_Lock_t *pphStbNetDev_Lock_t;

/**
 * The header of a packet (::phStbNetDev_Packet_t) in-flight between CPUs.
 */
typedef struct phStbNetDev_PacketHeader {
    /** For building packet lists. */
    struct phStbNetDev_Packet *next;
    /** Counting from 1, sequence number of packets sent. */
    ulong seqNr;
    /** Length of the packet's payload data array. */
    size_t datalen;
} phStbNetDev_PacketHeader_t;

/**
 * An packet in-flight between CPUs.
 */
typedef struct phStbNetDev_Packet {
    /** Header. */
    phStbNetDev_PacketHeader_t header;
    /** Payload data. The actual length is ::mtu + ETH_HLEN. */
    u8 data[1];
} phStbNetDev_Packet_t;

/** Header structure containing information about a packet pool ::phStbNetDev_Pool_t.
    The packet pool should be in memory accessible by both CPUs.
 */
typedef struct phStbNetDev_PoolHeader {
    /** Magic value for identifying a pool. Used only as a software
        reliability check.
        @see PH_STBNETDEV_POOL_MAGIC */
    UInt32 magic;
    /** Number of packets allocated in this pool. */
    unsigned int numPackets;
    /** Packet size, includes overhead. */
    size_t packetSize;
    /** Maximum transmission unit. */
    size_t mtu;
    /** The maximum number of packets that each CPU can use. This is to prevent
        one CPU to use all of them, and denying the peer CPU from sending any packets.
      */
    uint packetsAllocation;

    /* The rest is volatile, i.e. changable by the peer CPU. */

    /** Inter-CPU access control lock. */
    volatile phStbNetDev_Lock_t lock;
    /** The free packet list. */
    phStbNetDev_Packet_t * volatile packetListFree;
    /** The head pointers to the packet lists. */
    phStbNetDev_Packet_t * volatile packetListHeads[2];
    /** The tail pointers to the packet lists. */
    phStbNetDev_Packet_t * volatile packetListTails[2];
    /** The amount of packets that each CPU has allocated for transmit.
        Counts are indexed by #PH_STBNETDEV_ID_SELF and #PH_STBNETDEV_ID_PEER.
        We always increment the #PH_STBNETDEV_ID_SELF entry, and decrement
        the #PH_STBNETDEV_ID_PEER entry. */
    uint volatile packetsAllocated[2];
} phStbNetDev_PoolHeader_t;

/** Packet pool. Contains meta information, and lists of packets used
 * to transfer data between source and destination CPUs.
 */
typedef struct phStbNetDev_Pool {
    /** Meta information. */
    phStbNetDev_PoolHeader_t header;
    /** An array of packets, normally bigger than 1. */
    phStbNetDev_Packet_t packets[1];
} phStbNetDev_Pool_t;

/** Pointer to a ::phStbNetDev_Pool_t */
typedef phStbNetDev_Pool_t *pphStbNetDev_Pool_t;

/**************************************************************************
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phStbTemplate_<Word>+ *
***************************************************************************/

/** Pool of packets. Shared with destination device.  The uncached physical
    address of this is stored in ::gpStbNetDev_PoolPhys.
*/
extern pphStbNetDev_Pool_t gpStbNetDev_Pool;

/** Physical uncached equivalent of ::gpStbNetDev_Pool.
    Should reside in KSEG1.
*/
extern UInt32 gpStbNetDev_PoolPhys;

/** Base address for doing MMIO of the Mailbox IP block
    connected to the current CPU. */
extern UInt32 gphStbNetDev_MailboxBase;

#if PH_STBNETDEV_DEBUG
/** Set true if the driver should print verbose output. */
extern UInt32 gphStbNetDev_Debug;
#endif

/****************************************************************************
* EXPORTED FUNCTION PROTOTYPES                    phStbTemplate[_<Word>+]   *
*****************************************************************************/

#ifdef __cplusplus
extern "C"
{
#endif

/******************************************************************************/

void phStbNetDev_LockInitUnlocked(volatile phStbNetDev_Lock_t *lock);

void phStbNetDev_Lock(volatile phStbNetDev_Lock_t *lock, Int processId);

void phStbNetDev_Unlock(volatile phStbNetDev_Lock_t *lock, Int processId);

#if !PH_STBNETDEV_DSP

/** Set up the devices' packet pool ::gpStbNetDev_Pool.
    Calls phStbNetDev_CreatePool().
 */
int phStbNetDev_SetupPool(void);

/** Creates the interface packet pool.
    @param mtu IN Max transmission unit. Use the default (1500) if 0.
    @param share IN The maximum percentage of packets that each CPU can use.
    This is to prevent one CPU to use all of them, and denying the peer CPU
    from sending any packets.
 */
int phStbNetDev_CreatePool(
    size_t mtu,
    UInt32 share);

/** Initialises the structure of the interface packet pool.
    @param pPoolVirt IN Virtual or physical, cached address of the pool.
    @param pPoolPhys IN Physical, uncached address of the pool.
    @param poolSize IN Size in bytes of the packet pool.
    @param mtu IN Max transmission unit. Use the default (1500) if 0.
    @param share IN The maximum percentage of packets that each CPU can use.
    This is to prevent one CPU to use all of them, and denying the peer CPU
    from sending any packets.
 */
int phStbNetDev_InitPool(
    phStbNetDev_Pool_t *pPoolVirt,
    UInt32 pPoolPhys,
    size_t poolSize,
    size_t mtu,
    UInt32 share);
#endif /* #if !PH_STBNETDEV_DSP */

/**
 * Get a free buffer packet.
 * @return NULL if the free packet list is empty,
 * or the packet allocation share was already reached.
 */
phStbNetDev_Packet_t *phStbNetDev_GetFreeBuffer(
    pphStbNetDev_Device_t dev);

/** Put a buffer into the free packet list.
    If the peer cpu had reached its packet allocation limit, we interrupt it
    because there is now a free packet available for use and the limit is now cleared.
    If our own transmit device queue is stopped, AND the free list was totally empty
    then we can wake it up again, since we now have a free packet usable (if we are
    quick, since the peer CPU may grab it instead :-) for transmission.
 */
void phStbNetDev_PutFreeBuffer(
    pphStbNetDev_Device_t dev,
    phStbNetDev_Packet_t *pkt);

/**
 * Get a buffer from the full (incoming) packet buffer list.
 * The packet returned has its memory cache invalidated.
 * @return NULL if the full packet list is empty.
 */
phStbNetDev_Packet_t *phStbNetDev_GetFullBuffer(
    pphStbNetDev_Device_t dev);

/** Put a full buffer into the receive list for the peer cpu.
    The packet has its memory cache flushed.
    Interrupt the peer cpu.
*/
void phStbNetDev_PutFullBuffer(
    pphStbNetDev_Device_t dev,
    phStbNetDev_Packet_t *pkt);

/**
 * Enable and disable receive interrupts.
 */
void phStbNetDev_ReceiveInterruptsEnable(int enable);
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/

/******************************************************************************/
#ifdef __cplusplus
}
#endif

#endif /* PHSTBNETDEV_INTERNAL_H      Do not add any thing below this line */
