1
1
network/hardware/devnp/e100/e100_interrupt.c

149 строки
4.2 KiB
C

/*
* (c) 2017-2018, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*****************************************************************************
* *
* Driver for the Intel 8255x 10/100 Mbps Ethernet Controller Family *
* Network controller interrupt routines *
* *
*****************************************************************************/
#include "e100.h"
const struct sigevent * e100_isr_kermask(void *arg, int iid)
{
e100_dev_t *e100 = arg;
struct _iopkt_inter *ient;
u8 stat_ack = ioread8(&e100->csr->scb.stat_ack);
ient = &e100->inter;
if (ient->on_list == 0 &&
(stat_ack == stat_ack_not_ours || /* Not our interrupt */
stat_ack == stat_ack_not_present /* Hardware is ejected */)) {
/* IRQ not caused by this card. */
ient->spurious++;
return NULL;
}
/*
* Close window where this is referenced in e100_process_interrupt().
* We may get an interrupt, return a sigevent and have another
* thread start processing on SMP before the InterruptAttach()
* has returned.
*/
/* Ack interrupt(s) */
iowrite8(stat_ack, &e100->csr->scb.stat_ack);
/* We hit Receive No Resource (RNR); restart RU after cleaning */
if (stat_ack & stat_ack_rnr)
e100->ru_running = RU_SUSPENDED;
InterruptMask(e100->cfg.irq[0], iid);
e100->iid = iid;
return interrupt_queue(e100->iopkt, ient);
}
const struct sigevent *e100_isr(void *arg, int iid)
{
e100_dev_t *e100 = arg;
struct _iopkt_inter *ient;
u8 stat_ack = ioread8(&e100->csr->scb.stat_ack);
ient = &e100->inter;
if (ient->on_list == 0 &&
(stat_ack == stat_ack_not_ours || /* Not our interrupt */
stat_ack == stat_ack_not_present /* Hardware is ejected */)) {
/* IRQ not caused by this card. */
ient->spurious++;
return NULL;
}
/*
* Close window where this is referenced in e100_enable_interrupt().
* We may get an interrupt, return a sigevent and have another
* thread start processing on SMP before the InterruptAttach()
* has returned.
*/
/* Ack interrupt(s) */
iowrite8(stat_ack, &e100->csr->scb.stat_ack);
e100->stat_ack = stat_ack;
/* We hit Receive No Resource (RNR); restart RU after cleaning */
if (stat_ack & stat_ack_rnr)
e100->ru_running = RU_SUSPENDED;
e100_disable_irq(e100);
e100->iid = iid;
#ifdef VARIANT_norx
// TODO norx variant
while ( (stat_ack) ) {
e100->pkts_received = 1; // set activity flag for phy probe
e100_rx_clean(e100, &work_done, E100_NAPI_WEIGHT);
stat_ack = ioread8(&e100->csr->scb.stat_ack);
/* Ack interrupt(s) */
iowrite8(stat_ack, &e100->csr->scb.stat_ack);
}
e100_enable_irq(e100);
return NULL;
#endif
return interrupt_queue(e100->iopkt, ient);
}
int e100_enable_interrupt_kermask(void *arg)
{
e100_dev_t *e100 = (e100_dev_t *)arg;
InterruptUnmask(e100->cfg.irq[0], e100->iid);
return 1;
}
int e100_enable_interrupt(void *arg)
{
e100_dev_t *e100 = (e100_dev_t *)arg;
E100_DEBUG(log(LOG_DEBUG, "%s: %s() start", __devname__, __func__));
e100_enable_irq(e100);
E100_DEBUG(log(LOG_DEBUG, "%s: %s() done", __devname__, __func__));
return 1;
}
int e100_process_interrupt(void *arg, struct nw_work_thread *wtp)
{
uint32_t work_done;
e100_dev_t *e100 = (e100_dev_t *)arg;
struct ifnet *ifp;
ifp = &e100->ecom.ec_if;
if ( e100->stopping ) {
return 1;
}
do {
work_done = 0;
e100->pkts_received = 1;
E100_DEBUG(log(LOG_DEBUG, "%s: %s() stack_ack %02X status %02X", __devname__, __func__, e100->stat_ack, ioread8(&e100->csr->scb.status)));
e100_rx_clean(e100, wtp, &work_done, E100_NAPI_WEIGHT);
e100->pkts_received = 0;
// if the transmit side is quiet, process txd descriptors now
if (!(ifp->if_flags_tx & IFF_OACTIVE)) {
NW_SIGLOCK_P(&ifp->if_snd_ex, e100->iopkt, wtp);
e100_tx_clean(e100);
NW_SIGUNLOCK_P(&ifp->if_snd_ex, e100->iopkt, wtp);
}
if ( work_done >= E100_NAPI_WEIGHT && e100->cfg.verbose > 1 ) {
log(LOG_DEBUG, "%s: receive budget has been exceeded %d/%d", __devname__, work_done, E100_NAPI_WEIGHT);
}
} while ( work_done >= E100_NAPI_WEIGHT );
E100_DEBUG(log(LOG_DEBUG, "%s: %s() done", __devname__, __func__));
return (work_done < E100_NAPI_WEIGHT ? 1 : 0);
}