Mercurial > hg > Game > Atoc
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; +}