blob: 77d78bd65cd1298e03d54661964e5c320539784a [file] [log] [blame]
/*
* Copyright (c) 2009 Mindspeed Technologies, Inc.
*
* 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; either version 2
* of the License, or (at your option) any later version.
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef _CHANNELS_H_
#define _CHANNELS_H_
#include "types.h"
#include "events.h"
#include "system.h"
#include "fpp_globals.h"
#include "fpart.h"
#include "fpool.h"
#include "gemac.h"
#include "mtd.h"
#ifdef COMCERTO_100
extern FASTPOOL PktBufferPool;
extern FASTPOOL PktBufferDDRPool;
#endif
// pktqueue_put -- put packet onto packet queue
// returns TRUE if queue was previously empty
static __inline BOOL pktqueue_put(PDataQueue pQueue, struct tMetadata *pMetadata)
{
pMetadata->next = NULL;
/* add new metadata to the list tail*/
if (pQueue->head) {
PMetadata ptail = pQueue->tail;
ptail->next = pMetadata;
pQueue->tail = pMetadata;
return FALSE;
}
else {
pQueue->tail = pQueue->head = pMetadata;
return TRUE;
}
}
// pktqueue_get -- get packet from packet queue
// returns NULL if queue was empty
static __inline PMetadata pktqueue_get(PDataQueue pQueue)
{
PMetadata pMetadata;
/* get next metadata from list head */
pMetadata = pQueue->head;
if (pMetadata) {
pQueue->head = pMetadata->next;
}
return pMetadata;
}
// pktqueue_isempty -- test if packet queue is empty
// returns TRUE if queue is empty
static __inline int pktqueue_isempty(PDataQueue pQueue)
{
return pQueue->head == NULL;
}
// pktqueue_put_multiple -- put packet list onto packet queue
// returns TRUE if queue was previously empty
#if !defined (COMCERTO_2000_UTIL)
static __inline BOOL pktqueue_put_multiple(PDataQueue pQueue, struct tMetadata *pBeg, struct tMetadata *pEnd)
{
PMetadata mtd;
mtd = pBeg;
while (mtd != pEnd)
{
mtd->flags |= MTD_MULTIPLE;
mtd = mtd->next;
}
pEnd->next = NULL;
/* add new metadata to the list tail*/
if (pQueue->head) {
PMetadata ptail = pQueue->tail;
ptail->next = pBeg;
pQueue->tail = pEnd;
return FALSE;
}
else {
pQueue->head = pBeg;
pQueue->tail = pEnd;
return TRUE;
}
}
#endif
extern void free_packet(struct tMetadata *, int counter);
#if defined(COMCERTO_100)
static __inline PVOID pktbuffer_alloc(void)
{
PVOID pktbuf;
pktbuf = SFL_alloc_pool(&PktBufferPool);
if (pktbuf == NULL)
pktbuf = SFL_alloc_pool(&PktBufferDDRPool);
return pktbuf;
}
static __inline void pktbuffer_free(PVOID pktbuf)
{
if (SFL_free_pool(&PktBufferPool, pktbuf, 1))
SFL_free_pool(&PktBufferDDRPool, pktbuf, 0);
}
static __inline void pktbuffer_free_noclean(PVOID pktbuf)
{
if (SFL_free_pool(&PktBufferPool, pktbuf, 0))
SFL_free_pool(&PktBufferDDRPool, pktbuf, 0);
}
#elif defined(COMCERTO_1000)
static __inline void *pktbuffer_alloc(void)
{
return buffer_get(POOLA);
}
static __inline void pktbuffer_free(void *bufp)
{
buffer_put(bufp, POOLA, 1);
}
#elif defined(COMCERTO_2000_CLASS) || defined(COMCERTO_2000_UTIL)
void __free_packet(struct tMetadata *mtd);
static __inline void *pktbuffer_alloc(void)
{
void *buf;
/* allocate new buffer from BMU2 */
do {
buf =(void *)readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL);
} while (!buf);
return buf;
}
static __inline void pktbuffer_free(PVOID pktbuf)
{
/*Free buffer to BMU2 pool */
writel(((U32)pktbuf & ~(DDR_BUF_SIZE - 1)), (BMU2_BASE_ADDR + BMU_FREE_CTRL));
}
void free_buffer(void *pkt_start, int counter);
#endif
#if defined(COMCERTO_100) || defined(COMCERTO_1000)
typedef struct tCtldata {
struct tCtldata* next;
U16 length;
U16 code;
U16 data[128];
} CtlData, *PCtldata;
#define PDataChannel PDataQueue
extern DataQueue gCH_table[NUM_CHANNEL];
__attribute__((always_inline))
static inline void data_channel_put_event(U32 eventnum, struct tMetadata *pMetadata, BOOL do_set_event)
{
PDataChannel pChannel = &gCH_table[eventnum];
if (pktqueue_put(pChannel, pMetadata) && do_set_event)
set_event(gEventStatusReg, 1 << eventnum);
}
static __inline U32 data_channel_count(PDataChannel pChannel)
{
U32 n = 0;
PMetadata mtd;
mtd = pChannel->head;
while (mtd)
{
n++;
mtd = mtd->next;
}
return n;
}
static __inline void data_channel_put_event_multiple(U32 eventnum, struct tMetadata *pBeg, struct tMetadata *pEnd, BOOL do_set_event)
{
PDataChannel pChannel = &gCH_table[eventnum];
if (pktqueue_put_multiple(pChannel, pBeg, pEnd) && do_set_event)
set_event(gEventStatusReg, 1 << eventnum);
}
static __inline PMetadata data_channel_get_event(U32 eventnum)
{
PDataChannel pChannel = &gCH_table[eventnum];
PMetadata pMetadata;
/* get next metadata from list head */
pMetadata = pChannel->head;
if (pMetadata) {
pChannel->head = pMetadata->next;
}
return pMetadata;
}
static __inline void data_channel_limit(U32 eventnum, int maxqsize)
{
PDataChannel pChannel = &gCH_table[eventnum];
PMetadata pMtd;
pMtd = pChannel->head;
while (pMtd && (--maxqsize > 0 || (pMtd->flags & MTD_MULTIPLE)))
{
pMtd = pMtd->next;
}
if (pMtd)
{
PMetadata pNext;
pNext = pMtd->next;
pChannel->tail = pMtd;
pMtd->next = NULL;
while (pNext)
{
pMtd = pNext;
pNext = pMtd->next;
free_packet(pMtd);
COUNTER_INCREMENT(packets_dropped_channel_full);
}
}
}
static __inline void drop_fragments(PMetadata mtd)
{
PMetadata next;
while (mtd)
{
next = mtd->next;
COUNTER_INCREMENT(packets_dropped_fragments);
free_packet(mtd);
mtd = next;
}
}
static __inline int data_channel_isempty(U32 eventnum)
{
return gCH_table[eventnum].head == NULL;
}
#define CHANNEL_NULL ((channel_t)-1)
#define OUTPUT_CHANNEL(modname) EVENT_##modname
#define SEND_TO(modname, pmtd) data_channel_put_event(OUTPUT_CHANNEL(modname), pmtd, TRUE)
#define SEND_TO_CHANNEL(eventnum, pmtd) data_channel_put_event(eventnum, pmtd, TRUE)
#define SEND_TO_MULTIPLE(modname, pmtd1, pmtd2) data_channel_put_event_multiple(OUTPUT_CHANNEL(modname), pmtd1, pmtd2, TRUE)
#define SEND_TO_CHANNEL_MULTIPLE(eventnum, pmtd1, pmtd2) data_channel_put_event_multiple(eventnum, pmtd1, pmtd2, TRUE)
#define CHANNEL_GET(eventnum) data_channel_get_event(eventnum)
#define CHANNEL_ISEMPTY(eventnum) data_channel_isempty(eventnum)
#define CHANNEL_LIMIT(eventnum, maxqsize) data_channel_limit(eventnum, maxqsize)
#elif defined(COMCERTO_2000_UTIL)
#define OUTPUT_CHANNEL(modname) M_##modname##_process_packet
#define SEND_TO(modname, pmtd) OUTPUT_CHANNEL(modname)(pmtd)
#define SEND_TO_MULTIPLE(modname, pmtd1, pmtd2) \
{ \
PMetadata tmpmtd, head = pmtd1; \
while (head) { \
tmpmtd = head; \
head = head->next; \
SEND_TO(modname, tmpmtd); \
} \
} \
#define PDataChannel PDataQueue
extern DataQueue gCH_table[NUM_CHANNEL];
extern EVENTHANDLER gEventDataTable[EVENT_MAX];
/* TODO avoid dpulicating functions between C1k/C2k Util */
static __inline PMetadata data_channel_get_event(U32 eventnum)
{
PDataChannel pChannel = &gCH_table[eventnum];
PMetadata pMetadata;
/* get next metadata from list head */
pMetadata = pChannel->head;
if (pMetadata) {
pChannel->head = pMetadata->next;
}
return pMetadata;
}
extern U32 gEventStatusReg;
static __inline void data_channel_put_event(U32 eventnum, struct tMetadata *pMetadata, BOOL do_set_event)
{
PDataChannel pChannel = &gCH_table[eventnum];
if (pktqueue_put(pChannel, pMetadata) && do_set_event)
gEventStatusReg = 1;
}
static __inline int data_channel_isempty(U32 eventnum)
{
return gCH_table[eventnum].head == NULL;
}
static __inline void drop_fragments(PMetadata mtd)
{
PMetadata next;
while (mtd)
{
next = mtd->next;
DROP_PACKET(mtd, FRAGMENTER);
mtd = next;
}
}
#define SEND_TO_CHANNEL(eventnum, pmtd) data_channel_put_event(eventnum, pmtd, TRUE)
#define CHANNEL_GET(eventnum) data_channel_get_event(eventnum)
#define CHANNEL_ISEMPTY(eventnum) data_channel_isempty(eventnum)
#elif defined(COMCERTO_2000)
#define CHANNEL_NULL ((channel_t)NULL)
#define OUTPUT_CHANNEL(modname) M_##modname##_process_packet
#define SEND_TO(modname, pmtd) OUTPUT_CHANNEL(modname)(pmtd)
#define SEND_TO_CHANNEL(modname, pmtd) (*modname)(pmtd)
#define SEND_TO_MULTIPLE(modname, pmtd1, pmtd2) \
{ \
PMetadata tmpmtd, head = pmtd1; \
while (head) { \
tmpmtd = head; \
head = head->next; \
SEND_TO(modname, tmpmtd); \
} \
} \
#define SEND_TO_CHANNEL_MULTIPLE(modname, pmtd1, pmtd2) \
{ \
PMetadata tmpmtd, head = pmtd1; \
while (head) { \
tmpmtd = head; \
head = head->next; \
SEND_TO_CHANNEL(modname, tmpmtd); \
} \
} \
#endif
#endif /* _CHANNELS_H_ */