diff options
| -rw-r--r-- | linux-core/xgi_misc.c | 260 | 
1 files changed, 123 insertions, 137 deletions
| diff --git a/linux-core/xgi_misc.c b/linux-core/xgi_misc.c index a0ed18c2..6cc0f107 100644 --- a/linux-core/xgi_misc.c +++ b/linux-core/xgi_misc.c @@ -111,83 +111,136 @@ void xgi_sarea_info(struct xgi_info * info, struct xgi_sarea_info * req)  static unsigned int s_invalid_begin = 0; +static bool xgi_validate_signal(volatile u8 *mmio_vbase) +{ +	volatile u32 *const ge_3d_status =  +		(volatile u32 *)(mmio_vbase + 0x2800); +	const u32 old_ge_status = ge_3d_status[0x00]; + +	if (old_ge_status & 0x001c0000) { +		u16 check; + +		/* Check Read back status */ +		*(mmio_vbase + 0x235c) = 0x80; +		check = *((volatile u16 *)(mmio_vbase + 0x2360)); + +		if ((check & 0x3f) != ((check & 0x3f00) >> 8)) { +			return FALSE; +		} + +		/* Check RO channel */ +		*(mmio_vbase + 0x235c) = 0x83; +		check = *((volatile u16 *)(mmio_vbase + 0x2360)); +		if ((check & 0x0f) != ((check & 0xf0) >> 4)) { +			return FALSE; +		} + +		/* Check RW channel */ +		*(mmio_vbase + 0x235c) = 0x88; +		check = *((volatile u16 *)(mmio_vbase + 0x2360)); +		if ((check & 0x0f) != ((check & 0xf0) >> 4)) { +			return FALSE; +		} + +		/* Check RO channel outstanding */ +		*(mmio_vbase + 0x235c) = 0x8f; +		check = *((volatile u16 *)(mmio_vbase + 0x2360)); +		if (0 != (check & 0x3ff)) { +			return FALSE; +		} + +		/* Check RW channel outstanding */ +		*(mmio_vbase + 0x235c) = 0x90; +		check = *((volatile u16 *)(mmio_vbase + 0x2360)); +		if (0 != (check & 0x3ff)) { +			return FALSE; +		} + +		/* No pending PCIE request. GE stall. */ +	} + +	return TRUE; +} + + +static void xgi_ge_hang_reset(volatile u8 *mmio_vbase) +{ +	volatile u32 *const ge_3d_status = +		(volatile u32 *)(mmio_vbase + 0x2800); +	int time_out = 0xffff; + +	*(mmio_vbase + 0xb057) = 8; +	while (0 != (ge_3d_status[0x00] & 0xf0000000)) { +		while (0 != ((--time_out) & 0xfff))  +			/* empty */ ; + +		if (0 == time_out) { +			u8 old_3ce; +			u8 old_3cf; +			u8 old_index; +			u8 old_36; + +			XGI_INFO("Can not reset back 0x%x!\n", +				 ge_3d_status[0x00]); + +			*(mmio_vbase + 0xb057) = 0; + +			/* Have to use 3x5.36 to reset. */ +			/* Save and close dynamic gating */ + +			old_3ce = *(mmio_vbase + 0x3ce); +			*(mmio_vbase + 0x3ce) = 0x2a; +			old_3cf = *(mmio_vbase + 0x3cf); +			*(mmio_vbase + 0x3cf) = old_3cf & 0xfe; + +			/* Reset GE */ +			old_index = *(mmio_vbase + 0x3d4); +			*(mmio_vbase + 0x3d4) = 0x36; +			old_36 = *(mmio_vbase + 0x3d5); +			*(mmio_vbase + 0x3d5) = old_36 | 0x10; + +			while (0 != ((--time_out) & 0xfff))  +				/* empty */ ; + +			*(mmio_vbase + 0x3d5) = old_36; +			*(mmio_vbase + 0x3d4) = old_index; + +			/* Restore dynamic gating */ +			*(mmio_vbase + 0x3cf) = old_3cf;  +			*(mmio_vbase + 0x3ce) = old_3ce; +			break; +		} +	} + +	*(mmio_vbase + 0xb057) = 0; +} + +	  bool xgi_ge_irq_handler(struct xgi_info * info)  { -	volatile u8 *mmio_vbase = info->mmio.vbase; -	volatile U32 *ge_3d_status = (volatile U32 *)(mmio_vbase + 0x2800); -	U32 int_status = ge_3d_status[4];	// interrupt status -	U32 auto_reset_count = 0; +	volatile u8 *const mmio_vbase = info->mmio.vbase; +	volatile u32 *const ge_3d_status = +		(volatile u32 *)(mmio_vbase + 0x2800); +	const u32 int_status = ge_3d_status[4];  	bool is_support_auto_reset = FALSE; -	// Check GE on/off +	/* Check GE on/off */  	if (0 == (0xffffc0f0 & int_status)) { -		U32 old_ge_status = ge_3d_status[0x00]; -		U32 old_pcie_cmd_fetch_Addr = ge_3d_status[0x0a]; +		u32 old_pcie_cmd_fetch_Addr = ge_3d_status[0x0a]; +  		if (0 != (0x1000 & int_status)) { -			// We got GE stall interrupt. +			/* We got GE stall interrupt.  +			 */  			ge_3d_status[0x04] = int_status | 0x04000000;  			if (is_support_auto_reset) { -				bool is_wrong_signal = FALSE;  				static cycles_t last_tick;  				static unsigned continue_int_count = 0; -				// OE II is busy. -				while (old_ge_status & 0x001c0000) { -					u16 check; -					// Check Read back status -					*(mmio_vbase + 0x235c) = 0x80; -					check = -					    *((volatile u16 *)(mmio_vbase + -							       0x2360)); -					if ((check & 0x3f) != -					    ((check & 0x3f00) >> 8)) { -						is_wrong_signal = TRUE; -						break; -					} -					// Check RO channel -					*(mmio_vbase + 0x235c) = 0x83; -					check = -					    *((volatile u16 *)(mmio_vbase + -							       0x2360)); -					if ((check & 0x0f) != -					    ((check & 0xf0) >> 4)) { -						is_wrong_signal = TRUE; -						break; -					} -					// Check RW channel -					*(mmio_vbase + 0x235c) = 0x88; -					check = -					    *((volatile u16 *)(mmio_vbase + -							       0x2360)); -					if ((check & 0x0f) != -					    ((check & 0xf0) >> 4)) { -						is_wrong_signal = TRUE; -						break; -					} -					// Check RO channel outstanding -					*(mmio_vbase + 0x235c) = 0x8f; -					check = -					    *((volatile u16 *)(mmio_vbase + -							       0x2360)); -					if (0 != (check & 0x3ff)) { -						is_wrong_signal = TRUE; -						break; -					} -					// Check RW channel outstanding -					*(mmio_vbase + 0x235c) = 0x90; -					check = -					    *((volatile u16 *)(mmio_vbase + -							       0x2360)); -					if (0 != (check & 0x3ff)) { -						is_wrong_signal = TRUE; -						break; -					} -					// No pending PCIE request. GE stall. -					break; -				} -				if (is_wrong_signal) { -					// Nothing but skip. +				/* OE II is busy. */ + +				if (!xgi_validate_signal(mmio_vbase)) { +					/* Nothing but skip. */  				} else if (0 == continue_int_count++) {  					last_tick = get_cycles();  				} else { @@ -196,90 +249,23 @@ bool xgi_ge_irq_handler(struct xgi_info * info)  					    STALL_INTERRUPT_RESET_THRESHOLD) {  						continue_int_count = 0;  					} else if (continue_int_count >= 3) { -						int time_out; -  						continue_int_count = 0; -						// GE Hung up, need reset. +						/* GE Hung up, need reset. */  						XGI_INFO("Reset GE!\n"); -						*(mmio_vbase + 0xb057) = 8; -						time_out = 0xffff; -						while (0 != -						       (ge_3d_status[0x00] & -							0xf0000000)) { -							while (0 != -							       ((--time_out) & -								0xfff)) ; -							if (0 == time_out) { -								u8 old_3ce; -								u8 old_3cf; -								u8 old_index; -								u8 old_36; - -								XGI_INFO -								    ("Can not reset back 0x%lx!\n", -								     ge_3d_status -								     [0x00]); -								*(mmio_vbase + -								  0xb057) = 0; -								// Have to use 3x5.36 to reset. -								// Save and close dynamic gating -								old_3ce = -								    *(mmio_vbase -								      + 0x3ce); -								*(mmio_vbase + -								  0x3ce) = 0x2a; -								old_3cf = -								    *(mmio_vbase -								      + 0x3cf); -								*(mmio_vbase + -								  0x3cf) = -						       old_3cf & 0xfe; -								// Reset GE -								old_index = -								    *(mmio_vbase -								      + 0x3d4); -								*(mmio_vbase + -								  0x3d4) = 0x36; -								old_36 = -								    *(mmio_vbase -								      + 0x3d5); -								*(mmio_vbase + -								  0x3d5) = -						       old_36 | 0x10; -								while (0 != -								       ((--time_out) & 0xfff)) ; -								*(mmio_vbase + -								  0x3d5) = -						       old_36; -								*(mmio_vbase + -								  0x3d4) = -						       old_index; -								// Restore dynamic gating -								*(mmio_vbase + -								  0x3cf) = -						       old_3cf; -								*(mmio_vbase + -								  0x3ce) = -						       old_3ce; -								break; -							} -						} -						*(mmio_vbase + 0xb057) = 0; - -						// Increase Reset counter -						auto_reset_count++; +						xgi_ge_hang_reset(mmio_vbase);  					}  				}  			} -			return TRUE;  		} else if (0 != (0x1 & int_status)) {  			s_invalid_begin++;  			ge_3d_status[0x04] = (int_status & ~0x01) | 0x04000000; -			return TRUE;  		} + +		return TRUE;  	} +  	return FALSE;  } | 
