|  | @@ -15,9 +15,13 @@
 | 
		
	
		
			
			| 15 | 15 |   * along with this program; if not, write to the Free Software
 | 
		
	
		
			
			| 16 | 16 |   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
		
	
		
			
			| 17 | 17 |   * 02110-1301, USA.
 | 
		
	
		
			
			|  | 18 | + *
 | 
		
	
		
			
			|  | 19 | + * You can also choose to distribute this program under the terms of
 | 
		
	
		
			
			|  | 20 | + * the Unmodified Binary Distribution Licence (as given in the file
 | 
		
	
		
			
			|  | 21 | + * COPYING.UBDL), provided that you have satisfied its requirements.
 | 
		
	
		
			
			| 18 | 22 |   */
 | 
		
	
		
			
			| 19 | 23 |  
 | 
		
	
		
			
			| 20 |  | -FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			|  | 24 | +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 21 | 25 |  
 | 
		
	
		
			
			| 22 | 26 |  #include <stddef.h>
 | 
		
	
		
			
			| 23 | 27 |  #include <ipxe/timer.h>
 | 
		
	
	
		
			
			|  | @@ -35,7 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 35 | 39 |   *
 | 
		
	
		
			
			| 36 | 40 |   * This implementation of the timer is designed to satisfy RFC 2988
 | 
		
	
		
			
			| 37 | 41 |   * and therefore be usable as a TCP retransmission timer.
 | 
		
	
		
			
			| 38 |  | - *
 | 
		
	
		
			
			| 39 | 42 |   * 
 | 
		
	
		
			
			| 40 | 43 |   */
 | 
		
	
		
			
			| 41 | 44 |  
 | 
		
	
	
		
			
			|  | @@ -49,47 +52,59 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 49 | 52 |  static LIST_HEAD ( timers );
 | 
		
	
		
			
			| 50 | 53 |  
 | 
		
	
		
			
			| 51 | 54 |  /**
 | 
		
	
		
			
			| 52 |  | - * Start timer
 | 
		
	
		
			
			|  | 55 | + * Start timer with a specified timeout
 | 
		
	
		
			
			| 53 | 56 |   *
 | 
		
	
		
			
			| 54 | 57 |   * @v timer		Retry timer
 | 
		
	
		
			
			|  | 58 | + * @v timeout		Timeout, in ticks
 | 
		
	
		
			
			| 55 | 59 |   *
 | 
		
	
		
			
			| 56 |  | - * This starts the timer running with the current timeout value.  If
 | 
		
	
		
			
			|  | 60 | + * This starts the timer running with the specified timeout value.  If
 | 
		
	
		
			
			| 57 | 61 |   * stop_timer() is not called before the timer expires, the timer will
 | 
		
	
		
			
			| 58 | 62 |   * be stopped and the timer's callback function will be called.
 | 
		
	
		
			
			| 59 | 63 |   */
 | 
		
	
		
			
			| 60 |  | -void start_timer ( struct retry_timer *timer ) {
 | 
		
	
		
			
			|  | 64 | +void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
 | 
		
	
		
			
			|  | 65 | +
 | 
		
	
		
			
			|  | 66 | +	/* Add to list of running timers (if applicable) */
 | 
		
	
		
			
			| 61 | 67 |  	if ( ! timer->running ) {
 | 
		
	
		
			
			| 62 | 68 |  		list_add ( &timer->list, &timers );
 | 
		
	
		
			
			| 63 | 69 |  		ref_get ( timer->refcnt );
 | 
		
	
		
			
			|  | 70 | +		timer->running = 1;
 | 
		
	
		
			
			| 64 | 71 |  	}
 | 
		
	
		
			
			|  | 72 | +
 | 
		
	
		
			
			|  | 73 | +	/* Record start time */
 | 
		
	
		
			
			| 65 | 74 |  	timer->start = currticks();
 | 
		
	
		
			
			| 66 |  | -	timer->running = 1;
 | 
		
	
		
			
			| 67 |  | -
 | 
		
	
		
			
			| 68 |  | -	/* 0 means "use default timeout" */
 | 
		
	
		
			
			| 69 |  | -	if ( timer->min_timeout == 0 )
 | 
		
	
		
			
			| 70 |  | -		timer->min_timeout = DEFAULT_MIN_TIMEOUT;
 | 
		
	
		
			
			| 71 |  | -	/* We must never be less than MIN_TIMEOUT under any circumstances */
 | 
		
	
		
			
			| 72 |  | -	if ( timer->min_timeout < MIN_TIMEOUT )
 | 
		
	
		
			
			| 73 |  | -		timer->min_timeout = MIN_TIMEOUT;
 | 
		
	
		
			
			| 74 |  | -	/* Honor user-specified minimum timeout */
 | 
		
	
		
			
			| 75 |  | -	if ( timer->timeout < timer->min_timeout )
 | 
		
	
		
			
			| 76 |  | -		timer->timeout = timer->min_timeout;
 | 
		
	
		
			
			|  | 75 | +
 | 
		
	
		
			
			|  | 76 | +	/* Record timeout */
 | 
		
	
		
			
			|  | 77 | +	timer->timeout = timeout;
 | 
		
	
		
			
			| 77 | 78 |  
 | 
		
	
		
			
			| 78 | 79 |  	DBG2 ( "Timer %p started at time %ld (expires at %ld)\n",
 | 
		
	
		
			
			| 79 | 80 |  	       timer, timer->start, ( timer->start + timer->timeout ) );
 | 
		
	
		
			
			| 80 | 81 |  }
 | 
		
	
		
			
			| 81 | 82 |  
 | 
		
	
		
			
			| 82 | 83 |  /**
 | 
		
	
		
			
			| 83 |  | - * Start timer with a specified fixed timeout
 | 
		
	
		
			
			|  | 84 | + * Start timer
 | 
		
	
		
			
			| 84 | 85 |   *
 | 
		
	
		
			
			| 85 | 86 |   * @v timer		Retry timer
 | 
		
	
		
			
			| 86 |  | - * @v timeout		Timeout, in ticks
 | 
		
	
		
			
			|  | 87 | + *
 | 
		
	
		
			
			|  | 88 | + * This starts the timer running with the current timeout value
 | 
		
	
		
			
			|  | 89 | + * (rounded up to the minimum timeout value).  If stop_timer() is not
 | 
		
	
		
			
			|  | 90 | + * called before the timer expires, the timer will be stopped and the
 | 
		
	
		
			
			|  | 91 | + * timer's callback function will be called.
 | 
		
	
		
			
			| 87 | 92 |   */
 | 
		
	
		
			
			| 88 |  | -void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
 | 
		
	
		
			
			| 89 |  | -	start_timer ( timer );
 | 
		
	
		
			
			| 90 |  | -	timer->timeout = timeout;
 | 
		
	
		
			
			| 91 |  | -	DBG2 ( "Timer %p expiry time changed to %ld\n",
 | 
		
	
		
			
			| 92 |  | -	       timer, ( timer->start + timer->timeout ) );
 | 
		
	
		
			
			|  | 93 | +void start_timer ( struct retry_timer *timer ) {
 | 
		
	
		
			
			|  | 94 | +	unsigned long timeout = timer->timeout;
 | 
		
	
		
			
			|  | 95 | +	unsigned long min;
 | 
		
	
		
			
			|  | 96 | +
 | 
		
	
		
			
			|  | 97 | +	/* Calculate minimum timeout */
 | 
		
	
		
			
			|  | 98 | +	min = ( timer->min ? timer->min : DEFAULT_MIN_TIMEOUT );
 | 
		
	
		
			
			|  | 99 | +	if ( min < MIN_TIMEOUT )
 | 
		
	
		
			
			|  | 100 | +		min = MIN_TIMEOUT;
 | 
		
	
		
			
			|  | 101 | +
 | 
		
	
		
			
			|  | 102 | +	/* Ensure timeout is at least the minimum */
 | 
		
	
		
			
			|  | 103 | +	if ( timeout < min )
 | 
		
	
		
			
			|  | 104 | +		timeout = min;
 | 
		
	
		
			
			|  | 105 | +
 | 
		
	
		
			
			|  | 106 | +	/* Start timer with this timeout */
 | 
		
	
		
			
			|  | 107 | +	start_timer_fixed ( timer, timeout );
 | 
		
	
		
			
			| 93 | 108 |  }
 | 
		
	
		
			
			| 94 | 109 |  
 | 
		
	
		
			
			| 95 | 110 |  /**
 | 
		
	
	
		
			
			|  | @@ -150,6 +165,7 @@ void stop_timer ( struct retry_timer *timer ) {
 | 
		
	
		
			
			| 150 | 165 |   */
 | 
		
	
		
			
			| 151 | 166 |  static void timer_expired ( struct retry_timer *timer ) {
 | 
		
	
		
			
			| 152 | 167 |  	struct refcnt *refcnt = timer->refcnt;
 | 
		
	
		
			
			|  | 168 | +	unsigned long max = ( timer->max ? timer->max : DEFAULT_MAX_TIMEOUT );
 | 
		
	
		
			
			| 153 | 169 |  	int fail;
 | 
		
	
		
			
			| 154 | 170 |  
 | 
		
	
		
			
			| 155 | 171 |  	/* Stop timer without performing RTT calculations */
 | 
		
	
	
		
			
			|  | @@ -162,10 +178,8 @@ static void timer_expired ( struct retry_timer *timer ) {
 | 
		
	
		
			
			| 162 | 178 |  
 | 
		
	
		
			
			| 163 | 179 |  	/* Back off the timeout value */
 | 
		
	
		
			
			| 164 | 180 |  	timer->timeout <<= 1;
 | 
		
	
		
			
			| 165 |  | -	if ( timer->max_timeout == 0 ) /* 0 means "use default timeout" */
 | 
		
	
		
			
			| 166 |  | -		timer->max_timeout = DEFAULT_MAX_TIMEOUT;
 | 
		
	
		
			
			| 167 |  | -	if ( ( fail = ( timer->timeout > timer->max_timeout ) ) )
 | 
		
	
		
			
			| 168 |  | -		timer->timeout = timer->max_timeout;
 | 
		
	
		
			
			|  | 181 | +	if ( ( fail = ( timer->timeout > max ) ) )
 | 
		
	
		
			
			|  | 182 | +		timer->timeout = max;
 | 
		
	
		
			
			| 169 | 183 |  	DBG ( "Timer %p timeout backed off to %ld\n",
 | 
		
	
		
			
			| 170 | 184 |  	      timer, timer->timeout );
 | 
		
	
		
			
			| 171 | 185 |  
 |