diff driver/interrupt.c @ 0:42f240cc4bc6

From: 太田 篤志 <atoc@namikilab.tuat.ac.jp>
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Sep 2009 13:44:18 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/interrupt.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,253 @@
+/**
+ * interrupt.c
+ * SPE プロセスマネージャ spe_manager
+ * 割り込みハンドラ
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/kernel.h>      // printk
+#include <linux/slab.h>        // kmalloc, kfree
+#include <linux/interrupt.h>   // request_irq, free_irq
+#include <asm/ps3.h>           // ps3_irq_plug_setup, ps3_irq_plug_destroy
+#include <asm/io.h>            // ioremap, iounmap, in_xx, out_xx
+
+#include <asm/pgtable-ppc64.h> // 暫定
+#include <asm/mmu-hash64.h>    // 暫定
+
+#include "../include/hvcalls/spe.h"
+#include "interrupt.h"
+#include "lspe.h"
+#include "main.h"
+#include "critical.h"
+#include "process_list.h"
+
+
+
+
+
+
+
+
+//================================================================================================== interrupt_handler()
+/**
+ * interrupt_handler
+ * 割り込みハンドラ
+ *
+ * @param  int     irq
+ * @param  void *  dev_id
+ * @return irqreturn_t
+ */
+irqreturn_t interrupt_handler(int irq, void *dev_id)
+{
+	int           i, lspe_count = get_lspe_count();
+	unsigned long int_stat;
+
+
+	for (i = 0; i < lspe_count; i++)
+	{
+		lspe_data_t *lspe = get_lspe_data(i);
+		if (lspe == NULL) continue;
+
+		if (lspe->virq[0] == (unsigned int)irq)
+		{
+			/**
+			 *  クラス 0 割り込み
+			 *  (エラー)
+			 */
+
+			// 割り込みステータスを取得
+			hvc_get_spe_int_stat(lspe->spe_id, 0, &int_stat);
+			int_stat &= spe_int_mask[0];
+			printk(KERN_INFO "[%s] INT_Stat_class0 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat);
+
+
+			/*
+			 * とりあえず今はやることなし
+			 */
+
+
+			// 割り込みステータスをクリア
+			hvc_clear_spe_int_stat(lspe->spe_id, 0, int_stat);
+			break;
+		}
+
+		if (lspe->virq[1] == (unsigned int)irq)
+		{
+			/**
+			 *  クラス 1 割り込み
+			 *  (変換)
+			 */
+			unsigned long mfc_dsisr, mfc_dar;
+
+			// 割り込みステータスを取得
+			hvc_get_spe_int_stat(lspe->spe_id, 1, &int_stat);
+			int_stat &= spe_int_mask[1];
+//			printk(KERN_INFO "[%s] INT_Stat_class1 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat);
+
+
+			// MFC データ・ストレージ割り込みステータス・レジスタおよび
+			// MFC データ・アドレス・レジスタの値を取得
+			mfc_dsisr = in_be64(lspe->shadow + 0x0610 /*MFC_DSISR*/);
+			mfc_dar   = in_be64(lspe->shadow + 0x0620 /*MFC_DAR*/);
+//			printk(KERN_INFO "  MFC_DSISR = 0x%016lx\n", mfc_dsisr);
+//			printk(KERN_INFO "  MFC_DAR   = 0x%016lx\n", mfc_dar);
+
+
+
+
+
+
+			if (int_stat & 1)   // MFC データ・セグメントエラー
+			{
+				unsigned long esid = (mfc_dar & 0xFFFFFFFFF0000000UL) | 0x8000000UL /*[V]*/;
+
+				if (REGION_ID(mfc_dar) == USER_REGION_ID)
+				{
+					unsigned long vsid = get_vsid(lspe->mm->context.id, mfc_dar, MMU_SEGSIZE_256M);
+
+					// vsid を SLB エントリに登録
+					out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, lspe->slb_index);
+					out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid << 12 | 0xc00 /*Ks|Kp*/ | 0x80 /*C*/ | 0x000 /*L|LP*/);
+					out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, esid);
+
+					lspe->slb_index++;
+					if (lspe->slb_index >= 8) lspe->slb_index = 2;
+
+					// MFC コマンドの再始動
+					out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, 1UL<<32 /*[R]*/);
+				}
+			}
+
+
+
+
+
+
+
+
+
+#if 0
+			// 割り込みステータスをクリア
+			if (int_stat & 2)
+			{
+				lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0610UL /*MFC_DSISR*/, 0UL);
+			}
+			hvc_clear_spe_int_stat(lspe->spe_id, 1, int_stat);
+
+
+			if (int_stat & 2)   // MFC データ・ストレージエラー
+			{
+				if (mfc_dsisr & 0x40000000 /*MFC_DSISR[M]*/)
+				{
+					if (REGION_ID(mfc_dar) != USER_REGION_ID)
+					{
+						int ret = hash_page(mfc_dar, _PAGE_PRESENT, 0x300);
+//						printk(KERN_INFO "hash_page() [kernel side] = %d\n", ret);
+						if (!ret)
+						{
+							// MFC コマンドの再始動
+							out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, 1UL<<32 /*[R]*/);
+						}
+					}
+				}
+			}
+#endif
+
+
+
+
+
+
+
+
+			// 割り込みステータスをクリア
+			if (int_stat & 2)
+				lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0610UL /*MFC_DSISR*/, 0UL);
+			hvc_clear_spe_int_stat(lspe->spe_id, 1, int_stat);
+			break;
+		}
+
+		if (lspe->virq[2] == (unsigned int)irq)
+		{
+			/**
+			 *  クラス 2 割り込み
+			 *  (アプリケーション)
+			 */
+			unsigned int spu_status, spu_npc, spu_stop_code;
+
+			// 割り込みステータスを取得
+			hvc_get_spe_int_stat(lspe->spe_id, 2, &int_stat);
+			int_stat &= spe_int_mask[2];
+//			printk(KERN_INFO "[%s] INT_Stat_class2 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat);
+
+
+			// SPU ステータスおよびネクスト・プログラム・カウンタを取得
+			asm volatile("eieio");   // cf. Cell Broadband Engine アーキテクチャ version 1.01 (p.93)
+			spu_status    = in_be32(lspe->problem + 0x04024UL /*SPU_Status*/);
+			spu_stop_code = spu_status >> 16;
+			spu_npc       = in_be32(lspe->problem + 0x04034UL /*SPU_NPC*/);
+//			printk(KERN_INFO "  SPU_Status = 0x%08x\n", spu_status);
+//			printk(KERN_INFO "  StopCode   = 0x%04x\n", spu_stop_code);
+//			printk(KERN_INFO "  SPU_NPC    = 0x%08x\n", spu_npc);
+
+
+			if (spu_status & 1<<1 /*[P]*/)
+			{
+				switch (spu_stop_code)
+				{
+				case SPE_PROCESS_STOP_CODE_FINISH:
+					{
+						spe_process_context_list_t *this_process = get_running_process(i), *next_process = NULL;
+						spinlock_t                 *spinlock_for_process_list = get_spinlock_for_process_list();
+
+
+//						Critical Section (spinlock) >>>
+						spin_lock(spinlock_for_process_list);
+						{
+							next_process = get_next_waiting_process();
+
+/*
+							unsigned long addr;
+							for (addr = 0x0; addr < 0x0 + 0x60; addr+= 0x10)
+							{
+								printk(KERN_INFO "0x%04lx | %016lx %016lx\n", addr, in_be64(lspe->ls + addr), in_be64(lspe->ls + addr + 8));
+							}
+*/
+
+							// 実行プロセスコンテキストをクリア
+							clear_running_process(i);
+
+							// このプロセスのコンテキストを更新
+							this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED;
+							increment_not_released();
+
+							// 実行待ちプロセスがあるか
+							if (next_process != NULL)
+							{
+								// このプロセスを実行中にする
+								remove_process_from_waiting(next_process);
+//								next_process->context.read.spe_no = i;
+								next_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_RUNNING;
+
+								set_running_process(i, next_process);
+							}
+						}
+						spin_unlock(spinlock_for_process_list);
+//						<<< Critical Section (spinlock)
+
+
+						// SPE プロセス開始
+						if (next_process != NULL) start_spe_process(i, next_process);
+					}
+				}
+			}
+
+			// 割り込みステータスをクリア
+			hvc_clear_spe_int_stat(lspe->spe_id, 2, int_stat);
+			break;
+		}
+	}
+
+	return IRQ_HANDLED;
+//	return int_stat ? IRQ_HANDLED : IRQ_NONE;
+}