|  | @@ -39,8 +39,6 @@
 | 
		
	
		
			
			| 39 | 39 |  
 | 
		
	
		
			
			| 40 | 40 |  /** An UNDI NIC */
 | 
		
	
		
			
			| 41 | 41 |  struct undi_nic {
 | 
		
	
		
			
			| 42 |  | -	/** Entry point */
 | 
		
	
		
			
			| 43 |  | -	SEGOFF16_t entry;
 | 
		
	
		
			
			| 44 | 42 |  	/** Assigned IRQ number */
 | 
		
	
		
			
			| 45 | 43 |  	unsigned int irq;
 | 
		
	
		
			
			| 46 | 44 |  	/** Currently processing ISR */
 | 
		
	
	
		
			
			|  | @@ -167,7 +165,6 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
 | 
		
	
		
			
			| 167 | 165 |  	/* Copy parameter block and entry point */
 | 
		
	
		
			
			| 168 | 166 |  	assert ( params_len <= sizeof ( undinet_params ) );
 | 
		
	
		
			
			| 169 | 167 |  	memcpy ( &undinet_params, params, params_len );
 | 
		
	
		
			
			| 170 |  | -	undinet_entry_point = undinic->entry;
 | 
		
	
		
			
			| 171 | 168 |  
 | 
		
	
		
			
			| 172 | 169 |  	/* Call real-mode entry point.  This calling convention will
 | 
		
	
		
			
			| 173 | 170 |  	 * work with both the !PXE and the PXENV+ entry points.
 | 
		
	
	
		
			
			|  | @@ -222,7 +219,8 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
 | 
		
	
		
			
			| 222 | 219 |  		DBGC ( undinic, "UNDINIC %p parameters at %04x:%04x length "
 | 
		
	
		
			
			| 223 | 220 |  		       "%#02x, entry point at %04x:%04x\n", undinic,
 | 
		
	
		
			
			| 224 | 221 |  		       rm_params.segment, rm_params.offset, params_len,
 | 
		
	
		
			
			| 225 |  | -		       undinic->entry.segment, undinic->entry.offset );
 | 
		
	
		
			
			|  | 222 | +		       undinet_entry_point.segment,
 | 
		
	
		
			
			|  | 223 | +		       undinet_entry_point.offset );
 | 
		
	
		
			
			| 226 | 224 |  		DBGC ( undinic, "UNDINIC %p parameters provided:\n", undinic );
 | 
		
	
		
			
			| 227 | 225 |  		DBGC_HDA ( undinic, rm_params, params, params_len );
 | 
		
	
		
			
			| 228 | 226 |  		DBGC ( undinic, "UNDINIC %p parameters returned:\n", undinic );
 | 
		
	
	
		
			
			|  | @@ -268,13 +266,6 @@ static unsigned int last_trigger_count = 0;
 | 
		
	
		
			
			| 268 | 266 |   * Hook UNDI interrupt service routine
 | 
		
	
		
			
			| 269 | 267 |   *
 | 
		
	
		
			
			| 270 | 268 |   * @v irq		IRQ number
 | 
		
	
		
			
			| 271 |  | - *
 | 
		
	
		
			
			| 272 |  | - * The UNDI ISR specifically does @b not chain to the previous
 | 
		
	
		
			
			| 273 |  | - * interrupt handler.  BIOSes seem to install somewhat perverse
 | 
		
	
		
			
			| 274 |  | - * default interrupt handlers; some do nothing other than an iret (and
 | 
		
	
		
			
			| 275 |  | - * so will cause a screaming interrupt if there really is another
 | 
		
	
		
			
			| 276 |  | - * interrupting device) and some disable the interrupt at the PIC (and
 | 
		
	
		
			
			| 277 |  | - * so will bring our own interrupts to a shuddering halt).
 | 
		
	
		
			
			| 278 | 269 |   */
 | 
		
	
		
			
			| 279 | 270 |  static void undinet_hook_isr ( unsigned int irq ) {
 | 
		
	
		
			
			| 280 | 271 |  
 | 
		
	
	
		
			
			|  | @@ -411,6 +402,15 @@ static int undinet_transmit ( struct net_device *netdev,
 | 
		
	
		
			
			| 411 | 402 |   * so instead of doing it the easy way we have to go to all the hassle
 | 
		
	
		
			
			| 412 | 403 |   * of installing a genuine interrupt service routine and dealing with
 | 
		
	
		
			
			| 413 | 404 |   * the wonderful 8259 Programmable Interrupt Controller.  Joy.
 | 
		
	
		
			
			|  | 405 | + *
 | 
		
	
		
			
			|  | 406 | + * Addendum (10/07/07).  When doing things such as iSCSI boot, in
 | 
		
	
		
			
			|  | 407 | + * which we have to co-operate with a running OS, we can't get away
 | 
		
	
		
			
			|  | 408 | + * with the "ISR-just-increments-a-counter-and-returns" trick at all,
 | 
		
	
		
			
			|  | 409 | + * because it involves tying up the PIC for far too long, and other
 | 
		
	
		
			
			|  | 410 | + * interrupt-dependent components (e.g. local disks) start breaking.
 | 
		
	
		
			
			|  | 411 | + * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
 | 
		
	
		
			
			|  | 412 | + * from within interrupt context in order to deassert the device
 | 
		
	
		
			
			|  | 413 | + * interrupt, and sends EOI if applicable.
 | 
		
	
		
			
			| 414 | 414 |   */
 | 
		
	
		
			
			| 415 | 415 |  static void undinet_poll ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 416 | 416 |  	struct undi_nic *undinic = netdev->priv;
 | 
		
	
	
		
			
			|  | @@ -425,28 +425,6 @@ static void undinet_poll ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 425 | 425 |  		if ( ! undinet_isr_triggered() )
 | 
		
	
		
			
			| 426 | 426 |  			return;
 | 
		
	
		
			
			| 427 | 427 |  
 | 
		
	
		
			
			| 428 |  | -#if 0
 | 
		
	
		
			
			| 429 |  | -		/* See if this was our interrupt */
 | 
		
	
		
			
			| 430 |  | -		memset ( &undi_isr, 0, sizeof ( undi_isr ) );
 | 
		
	
		
			
			| 431 |  | -		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
 | 
		
	
		
			
			| 432 |  | -		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
 | 
		
	
		
			
			| 433 |  | -					   sizeof ( undi_isr ) ) ) != 0 )
 | 
		
	
		
			
			| 434 |  | -			return;
 | 
		
	
		
			
			| 435 |  | -
 | 
		
	
		
			
			| 436 |  | -		/* Send EOI to the PIC.  In an ideal world, we'd do
 | 
		
	
		
			
			| 437 |  | -		 * this only for interrupts which the UNDI stack
 | 
		
	
		
			
			| 438 |  | -		 * reports as "ours".  However, since we don't (can't)
 | 
		
	
		
			
			| 439 |  | -		 * chain to the previous interrupt handler, we have to
 | 
		
	
		
			
			| 440 |  | -		 * acknowledge all interrupts.  See undinet_hook_isr()
 | 
		
	
		
			
			| 441 |  | -		 * for more background.
 | 
		
	
		
			
			| 442 |  | -		 */
 | 
		
	
		
			
			| 443 |  | -		send_eoi ( undinic->irq );
 | 
		
	
		
			
			| 444 |  | -
 | 
		
	
		
			
			| 445 |  | -		/* If this wasn't our interrupt, exit now */
 | 
		
	
		
			
			| 446 |  | -		if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
 | 
		
	
		
			
			| 447 |  | -			return;
 | 
		
	
		
			
			| 448 |  | -#endif
 | 
		
	
		
			
			| 449 |  | -		
 | 
		
	
		
			
			| 450 | 428 |  		/* Start ISR processing */
 | 
		
	
		
			
			| 451 | 429 |  		undinic->isr_processing = 1;
 | 
		
	
		
			
			| 452 | 430 |  		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
 | 
		
	
	
		
			
			|  | @@ -651,7 +629,7 @@ int undinet_probe ( struct undi_device *undi ) {
 | 
		
	
		
			
			| 651 | 629 |  	undi_set_drvdata ( undi, netdev );
 | 
		
	
		
			
			| 652 | 630 |  	netdev->dev = &undi->dev;
 | 
		
	
		
			
			| 653 | 631 |  	memset ( undinic, 0, sizeof ( *undinic ) );
 | 
		
	
		
			
			| 654 |  | -	undinic->entry = undi->entry;
 | 
		
	
		
			
			|  | 632 | +	undinet_entry_point = undi->entry;
 | 
		
	
		
			
			| 655 | 633 |  	DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
 | 
		
	
		
			
			| 656 | 634 |  
 | 
		
	
		
			
			| 657 | 635 |  	/* Hook in UNDI stack */
 | 
		
	
	
		
			
			|  | @@ -770,6 +748,9 @@ void undinet_remove ( struct undi_device *undi ) {
 | 
		
	
		
			
			| 770 | 748 |  		       sizeof ( stop_undi ) );
 | 
		
	
		
			
			| 771 | 749 |  	undi->flags &= ~UNDI_FL_STARTED;
 | 
		
	
		
			
			| 772 | 750 |  
 | 
		
	
		
			
			|  | 751 | +	/* Clear entry point */
 | 
		
	
		
			
			|  | 752 | +	memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
 | 
		
	
		
			
			|  | 753 | +
 | 
		
	
		
			
			| 773 | 754 |  	/* Free network device */
 | 
		
	
		
			
			| 774 | 755 |  	netdev_nullify ( netdev );
 | 
		
	
		
			
			| 775 | 756 |  	netdev_put ( netdev );
 |