summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/xgi_misc.c260
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;
}