MFS: synchronize the code with the version in -stable, specifically:

+ SYSCTL_ULONG -> SYSCTL_UINT
 + some procedure renaming and variable rearrangement
 + fix the 'interface going deaf' problem same as in -stable.
This commit is contained in:
Luigi Rizzo 2002-02-11 23:56:18 +00:00
parent 27d5f39f68
commit daccb6386b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=90550
3 changed files with 102 additions and 67 deletions

View File

@ -70,9 +70,7 @@
#endif
#ifdef DEVICE_POLLING
#include <net/netisr.h> /* for NETISR_POLL */
extern void ether_poll1(void);
extern void init_device_poll(void);
extern void hardclock_device_poll(void);
#endif /* DEVICE_POLLING */
@ -147,7 +145,7 @@ initclocks(dummy)
cpu_initclocks();
#ifdef DEVICE_POLLING
register_netisr(NETISR_POLL, ether_poll1);
init_device_poll();
#endif
/*
* Compute profhz/stathz, and fix profhz if needed.
@ -222,7 +220,7 @@ hardclock(frame)
tc_windup();
#ifdef DEVICE_POLLING
hardclock_device_poll();
hardclock_device_poll(); /* this is very short and quick */
#endif /* DEVICE_POLLING */
/*

View File

@ -644,7 +644,7 @@ swi_net(void *dummy)
}
#ifdef DEVICE_POLLING
if (pollmore)
ether_pollmore();
netisr_pollmore();
}
#endif
}

View File

@ -1,5 +1,7 @@
/*-
* Copyright (c) 2001 Luigi Rizzo
* Copyright (c) 2001-2002 Luigi Rizzo
*
* Supported by: the Xorp Project (www.xorp.org)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -42,10 +44,12 @@
#error DEVICE_POLLING is not compatible with SMP
#endif
void ether_poll1(void);
static void netisr_poll(void); /* the two netisr handlers */
void netisr_pollmore(void);
void init_device_poll(void); /* init routine */
void hardclock_device_poll(void); /* hook from hardclock */
void ether_poll(int); /* polling while in trap */
void ether_pollmore(void);
void hardclock_device_poll(void);
/*
* Polling support for [network] device drivers.
@ -101,56 +105,73 @@ SYSCTL_NODE(_kern, OID_AUTO, polling, CTLFLAG_RW, 0,
"Device polling parameters");
static u_int32_t poll_burst = 5;
SYSCTL_ULONG(_kern_polling, OID_AUTO, burst, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, burst, CTLFLAG_RW,
&poll_burst, 0, "Current polling burst size");
static u_int32_t poll_each_burst = 5;
SYSCTL_ULONG(_kern_polling, OID_AUTO, each_burst, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, each_burst, CTLFLAG_RW,
&poll_each_burst, 0, "Max size of each burst");
static u_int32_t poll_burst_max = 150; /* good for 100Mbit net and HZ=1000 */
SYSCTL_ULONG(_kern_polling, OID_AUTO, burst_max, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, burst_max, CTLFLAG_RW,
&poll_burst_max, 0, "Max Polling burst size");
static u_int32_t poll_in_idle_loop=1; /* do we poll in idle loop ? */
SYSCTL_UINT(_kern_polling, OID_AUTO, idle_poll, CTLFLAG_RW,
&poll_in_idle_loop, 0, "Enable device polling in idle loop");
u_int32_t poll_in_trap; /* used in trap.c */
SYSCTL_ULONG(_kern_polling, OID_AUTO, poll_in_trap, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, poll_in_trap, CTLFLAG_RW,
&poll_in_trap, 0, "Poll burst size during a trap");
static u_int32_t user_frac = 50;
SYSCTL_ULONG(_kern_polling, OID_AUTO, user_frac, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, user_frac, CTLFLAG_RW,
&user_frac, 0, "Desired user fraction of cpu time");
static u_int32_t reg_frac = 20 ;
SYSCTL_ULONG(_kern_polling, OID_AUTO, reg_frac, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, reg_frac, CTLFLAG_RW,
&reg_frac, 0, "Every this many cycles poll register");
static u_int32_t short_ticks;
SYSCTL_ULONG(_kern_polling, OID_AUTO, short_ticks, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, short_ticks, CTLFLAG_RW,
&short_ticks, 0, "Hardclock ticks shorter than they should be");
static u_int32_t lost_polls;
SYSCTL_ULONG(_kern_polling, OID_AUTO, lost_polls, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, lost_polls, CTLFLAG_RW,
&lost_polls, 0, "How many times we would have lost a poll tick");
static u_int32_t pending_polls;
SYSCTL_UINT(_kern_polling, OID_AUTO, pending_polls, CTLFLAG_RW,
&pending_polls, 0, "Do we need to poll again");
static int residual_burst = 0;
SYSCTL_INT(_kern_polling, OID_AUTO, residual_burst, CTLFLAG_RW,
&residual_burst, 0, "# of residual cycles in burst");
static u_int32_t poll_handlers; /* next free entry in pr[]. */
SYSCTL_ULONG(_kern_polling, OID_AUTO, handlers, CTLFLAG_RD,
SYSCTL_UINT(_kern_polling, OID_AUTO, handlers, CTLFLAG_RD,
&poll_handlers, 0, "Number of registered poll handlers");
static u_int32_t poll_in_idle=1; /* boolean */
SYSCTL_ULONG(_kern_polling, OID_AUTO, poll_in_idle, CTLFLAG_RW,
&poll_in_idle, 0, "Poll during idle loop");
static u_int32_t idlepoll_sleeping; /* idlepoll is sleeping */
SYSCTL_ULONG(_kern_polling, OID_AUTO, idlepoll_sleeping, CTLFLAG_RD,
&idlepoll_sleeping, 0, "idlepoll is sleeping");
static int polling = 0; /* global polling enable */
SYSCTL_ULONG(_kern_polling, OID_AUTO, enable, CTLFLAG_RW,
SYSCTL_UINT(_kern_polling, OID_AUTO, enable, CTLFLAG_RW,
&polling, 0, "Polling enabled");
static volatile u_int32_t phase;
SYSCTL_UINT(_kern_polling, OID_AUTO, phase, CTLFLAG_RW,
&phase, 0, "Polling phase");
static u_int32_t suspect;
SYSCTL_UINT(_kern_polling, OID_AUTO, suspect, CTLFLAG_RW,
&suspect, 0, "suspect event");
static volatile u_int32_t stalled;
SYSCTL_UINT(_kern_polling, OID_AUTO, stalled, CTLFLAG_RW,
&stalled, 0, "potential stalls");
static u_int32_t idlepoll_sleeping; /* idlepoll is sleeping */
SYSCTL_UINT(_kern_polling, OID_AUTO, idlepoll_sleeping, CTLFLAG_RD,
&idlepoll_sleeping, 0, "idlepoll is sleeping");
static u_int32_t poll1_active;
static u_int32_t need_poll_again;
#define POLL_LIST_LEN 128
struct pollrec {
@ -160,6 +181,15 @@ struct pollrec {
static struct pollrec pr[POLL_LIST_LEN];
/*
* register relevant netisr. Called from kern_clock.c:
*/
void
init_device_poll(void)
{
register_netisr(NETISR_POLL, netisr_poll);
}
/*
* Hook from hardclock. Tries to schedule a netisr, but keeps track
* of lost ticks due to the previous handler taking too long.
@ -173,6 +203,9 @@ hardclock_device_poll(void)
static struct timeval prev_t, t;
int delta;
if (poll_handlers == 0)
return;
microuptime(&t);
delta = (t.tv_usec - prev_t.tv_usec) +
(t.tv_sec - prev_t.tv_sec)*1000000;
@ -181,15 +214,24 @@ hardclock_device_poll(void)
else
prev_t = t;
if (poll_handlers > 0) {
if (poll1_active) {
lost_polls++;
need_poll_again++;
} else {
poll1_active = 1;
schednetisr(NETISR_POLL);
}
if (pending_polls > 100) {
/* too much, assume it has stalled */
stalled++;
printf("poll stalled [%d] in phase %d\n",
stalled, phase);
pending_polls = 0;
phase = 0;
}
if (phase <= 2) {
if (phase != 0)
suspect++;
phase = 1;
schednetisr(NETISR_POLL);
phase = 2;
}
if (pending_polls++ > 0)
lost_polls++;
}
/*
@ -199,7 +241,6 @@ void
ether_poll(int count)
{
int i;
int s = splimp();
mtx_lock(&Giant);
@ -210,18 +251,17 @@ ether_poll(int count)
(pr[i].ifp->if_flags & (IFF_UP|IFF_RUNNING)) )
pr[i].handler(pr[i].ifp, 0, count); /* quick check */
mtx_unlock(&Giant);
splx(s);
}
/*
* ether_pollmore is called after other netisr's, possibly scheduling
* netisr_pollmore is called after other netisr's, possibly scheduling
* another NETISR_POLL call, or adapting the burst size for the next cycle.
*
* It is very bad to fetch large bursts of packets from a single card at once,
* because the burst could take a long time to be completely processed, or
* could saturate the intermediate queue (ipintrq or similar) leading to
* losses or unfairness. To reduce the problem, and also to account better for
* time spent in network-related processnig, we split the burst in smaller
* time spent in network-related processing, we split the burst in smaller
* chunks of fixed size, giving control to the other netisr's between chunks.
* This helps in improving the fairness, reducing livelock (because we
* emulate more closely the "process to completion" that we have with
@ -229,21 +269,19 @@ ether_poll(int count)
* handling and forwarding.
*/
static int residual_burst = 0;
static struct timeval poll_start_t;
void
ether_pollmore()
netisr_pollmore()
{
struct timeval t;
int kern_load;
int s = splhigh();
/* XXX run at splhigh() or equivalent */
phase = 5;
if (residual_burst > 0) {
schednetisr(NETISR_POLL);
/* will run immediately on return, followed by netisrs */
splx(s);
return ;
}
/* here we can account time spent in netisr's in this tick */
@ -259,36 +297,37 @@ ether_pollmore()
poll_burst++;
}
if (need_poll_again) {
pending_polls--;
if (pending_polls == 0) /* we are done */
phase = 0;
else {
/*
* Last cycle was long and caused us to miss one or more
* hardclock ticks. Restart processnig again, but slightly
* hardclock ticks. Restart processing again, but slightly
* reduce the burst size to prevent that this happens again.
*/
need_poll_again--;
poll_burst -= (poll_burst / 8);
if (poll_burst < 1)
poll_burst = 1;
schednetisr(NETISR_POLL);
} else
poll1_active = 0;
splx(s);
phase = 6;
}
}
/*
* ether_poll1 is called by schednetisr when appropriate, typically once
* netisr_poll is scheduled by schednetisr when appropriate, typically once
* per tick. It is called at splnet() so first thing to do is to upgrade to
* splimp(), and call all registered handlers.
*/
void
ether_poll1(void)
static void
netisr_poll(void)
{
static int reg_frac_count;
int i, cycles;
enum poll_cmd arg = POLL_ONLY;
int s=splimp();
mtx_lock(&Giant);
phase = 3;
if (residual_burst == 0) { /* first call in this tick */
microuptime(&poll_start_t);
/*
@ -344,8 +383,8 @@ ether_poll1(void)
poll_handlers = 0;
}
/* on -stable, schednetisr(NETISR_POLLMORE); */
phase = 4;
mtx_unlock(&Giant);
splx(s);
}
/*
@ -353,8 +392,8 @@ ether_poll1(void)
* (and polling should be enabled), 0 otherwise.
* A device is not supposed to register itself multiple times.
*
* This is called from within the *_intr() function, so we should
* probably not need further locking. XXX
* This is called from within the *_intr() functions, so we do not need
* further locking.
*/
int
ether_poll_register(poll_handler_t *h, struct ifnet *ifp)
@ -400,12 +439,10 @@ ether_poll_register(poll_handler_t *h, struct ifnet *ifp)
}
/*
* Remove the interface from the list of polling ones.
* Normally run by *_stop().
* We allow it being called with IFF_POLLING clear, the
* call is sufficiently rare so it is preferable to save the
* space for the extra test in each device in exchange of one
* additional function call.
* Remove interface from the polling list. Normally called by *_stop().
* It is not an error to call it with IFF_POLLING clear, the call is
* sufficiently rare to be preferable to save the space for the extra
* test in each driver in exchange of one additional function call.
*/
int
ether_poll_deregister(struct ifnet *ifp)
@ -450,7 +487,7 @@ poll_idle(void)
mtx_unlock_spin(&sched_lock);
for (;;) {
if (poll_in_idle && poll_handlers > 0) {
if (poll_in_idle_loop && poll_handlers > 0) {
idlepoll_sleeping = 0;
mtx_lock(&Giant);
ether_poll(poll_each_burst);