blob: c3f165125a4728ae5082299a781228e2771526cc [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.
*
*
*/
#include "modules.h"
#include "channels.h"
#include "events.h"
#include "module_tx.h"
#include "system.h"
#include "fpart.h"
#include "fpool.h"
#include "fpp.h"
#include "module_hidrv.h"
#if !defined(COMCERTO_2000) || defined(COMCERTO_2000_CONTROL)
U32 FCODE_TO_EVENT(U32 fcode)
{
U32 eventid;
switch((fcode & 0xFF00) >> 8)
{
case FC_RX:
if (fcode >= L2BRIDGE_FIRST_COMMAND && fcode <= L2BRIDGE_LAST_COMMAND)
eventid = EVENT_BRIDGE;
else
eventid = EVENT_PKT_RX;
break;
case FC_IPV4: eventid = EVENT_IPV4; break;
case FC_IPV6: eventid = EVENT_IPV6; break;
case FC_QM: eventid = EVENT_QM; break;
case FC_TX: eventid = EVENT_PKT_TX; break;
case FC_PPPOE: eventid = EVENT_PPPOE; break;
case FC_MC: eventid = EVENT_MC6; break;
case FC_RTP: eventid = EVENT_RTP_RELAY; break;
case FC_VLAN: eventid = EVENT_VLAN; break;
case FC_IPSEC: eventid = EVENT_IPS_IN; break;
case FC_TRC: eventid = EVENT_IPS_OUT; break;
case FC_TNL:eventid = EVENT_TNL_IN; break;
#ifdef CFG_MACVLAN
case FC_MACVLAN: eventid = EVENT_MACVLAN; break;
#endif
#ifdef CFG_STATS
case FC_STAT:eventid = EVENT_STAT; break;
#endif
case FC_ALTCONF: eventid = EVENT_IPV4; break;
#ifdef CFG_WIFI_OFFLOAD
case FC_WIFI_RX: eventid = EVENT_PKT_WIFIRX; break;
#endif
case FC_NATPT: eventid = EVENT_NATPT; break;
#ifdef CFG_PCAP
case FC_PKTCAP: eventid = EVENT_PKTCAP; break;
#endif
#ifdef CFG_DIAGS
case FC_FPPDIAG: eventid = EVENT_IPV4; break;
#endif
#if defined(COMCERTO_2000_CONTROL) && !defined(ICC_DISABLE)
case FC_ICC: eventid = EVENT_ICC; break;
#endif
case FC_L2TP: eventid = EVENT_L2TP; break;
default: eventid = 0; break;
}
return eventid;
}
#endif /* !defined(COMCERTO_2000) || defined(COMCERTO_2000_CONTROL) */
#if !defined(COMCERTO_2000)
BOOL M_hidrv_init(PModuleDesc pModule)
{
/* module entry point and channels registration */
pModule->entry = &M_hidrv_entry;
pModule->cmdproc = NULL;
HAL_arm1_fiq_enable_1(IRQM_FROMHOST);
host_cmd.code = 0xFFFF;
return 0;
}
void msg_send(HostMessage *pmsg)
{
DISABLE_INTERRUPTS();
pmsg->next = NULL;
if (hostmsg_queue.head) {
HostMessage *ptail = hostmsg_queue.tail;
ptail->next = pmsg;
hostmsg_queue.tail = pmsg;
}
else {
hostmsg_queue.tail = hostmsg_queue.head = pmsg;
set_event(gEventStatusReg, 1 << EVENT_HIDRV);
}
ENABLE_INTERRUPTS();
}
void M_hidrv_entry(void)
{
U32 tmp;
// process host command
if (host_cmd.code != 0xFFFF)
{
CmdProc cmdproc;
U16 retlen;
U32 eventid;
eventid = FCODE_TO_EVENT(host_cmd.code);
cmdproc = gCmdProcTable[eventid];
if (cmdproc)
{
retlen = (*cmdproc)(host_cmd.code, host_cmd.length, host_cmd.data);
if (retlen == 0)
{
host_cmd.data[0] = NO_ERR;
retlen = 2;
}
}
else
{
host_cmd.data[0] = ERR_UNKNOWN_COMMAND;
retlen = 2;
}
tmp = (U32)retlen | (((U32)host_cmd.code) << 16);
*(V32*)CMD_MBOX_1_ADDR = tmp;
SFL_memcpy((U32*)CMD_DATA_ADDR, host_cmd.data, retlen);
*(V32*)CMD_MBOX_0_ADDR |= M0_ACK;
DISABLE_INTERRUPTS();
HAL_arm1_fiq_enable_1(IRQM_FROMHOST);
ENABLE_INTERRUPTS();
host_cmd.code = 0xFFFF; // mark no host command
}
// process host messages
DISABLE_INTERRUPTS();
while (hostmsg_queue.head)
{
HostMessage *pmsg;
if ( *(V32*)EVENT_MBOX_0_ADDR & M0_EVENT) {
// SMI is busy (pending event in SMI)
// enable interrupt raised when available
HAL_arm1_fiq_enable_1(IRQM_TOHOST);
break;
}
else {
pmsg = hostmsg_queue.head;
tmp = (U32)pmsg->length | ( ((U32)pmsg->code) << 16);
*(V32*)EVENT_MBOX_1_ADDR = tmp;
SFL_memcpy((U32*)EVENT_DATA_ADDR, pmsg->data, pmsg->length);
HAL_clear_interrupt_1(IRQM_TOHOST);
*(V32*)EVENT_MBOX_0_ADDR |= M0_EVENT;
HAL_generate_int_1(IRQM_CSP_HIDRV);
hostmsg_queue.head = pmsg->next;
msg_free(pmsg);
}
}
ENABLE_INTERRUPTS();
}
HostMessage *msg_alloc(void)
{
return SFL_alloc_part_lock(&HostmsgPart);
}
void msg_free(HostMessage *msg)
{
SFL_free_part(&HostmsgPart, msg);
}
#endif