149 строки
4.2 KiB
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);
|
|
}
|