Mercurial > hg > Game > Atoc
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:42f240cc4bc6 |
---|---|
1 /** | |
2 * interrupt.c | |
3 * SPE プロセスマネージャ spe_manager | |
4 * 割り込みハンドラ | |
5 */ | |
6 | |
7 #include <linux/module.h> // カーネルモジュール全般 | |
8 #include <linux/kernel.h> // printk | |
9 #include <linux/slab.h> // kmalloc, kfree | |
10 #include <linux/interrupt.h> // request_irq, free_irq | |
11 #include <asm/ps3.h> // ps3_irq_plug_setup, ps3_irq_plug_destroy | |
12 #include <asm/io.h> // ioremap, iounmap, in_xx, out_xx | |
13 | |
14 #include <asm/pgtable-ppc64.h> // 暫定 | |
15 #include <asm/mmu-hash64.h> // 暫定 | |
16 | |
17 #include "../include/hvcalls/spe.h" | |
18 #include "interrupt.h" | |
19 #include "lspe.h" | |
20 #include "main.h" | |
21 #include "critical.h" | |
22 #include "process_list.h" | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 //================================================================================================== interrupt_handler() | |
32 /** | |
33 * interrupt_handler | |
34 * 割り込みハンドラ | |
35 * | |
36 * @param int irq | |
37 * @param void * dev_id | |
38 * @return irqreturn_t | |
39 */ | |
40 irqreturn_t interrupt_handler(int irq, void *dev_id) | |
41 { | |
42 int i, lspe_count = get_lspe_count(); | |
43 unsigned long int_stat; | |
44 | |
45 | |
46 for (i = 0; i < lspe_count; i++) | |
47 { | |
48 lspe_data_t *lspe = get_lspe_data(i); | |
49 if (lspe == NULL) continue; | |
50 | |
51 if (lspe->virq[0] == (unsigned int)irq) | |
52 { | |
53 /** | |
54 * クラス 0 割り込み | |
55 * (エラー) | |
56 */ | |
57 | |
58 // 割り込みステータスを取得 | |
59 hvc_get_spe_int_stat(lspe->spe_id, 0, &int_stat); | |
60 int_stat &= spe_int_mask[0]; | |
61 printk(KERN_INFO "[%s] INT_Stat_class0 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat); | |
62 | |
63 | |
64 /* | |
65 * とりあえず今はやることなし | |
66 */ | |
67 | |
68 | |
69 // 割り込みステータスをクリア | |
70 hvc_clear_spe_int_stat(lspe->spe_id, 0, int_stat); | |
71 break; | |
72 } | |
73 | |
74 if (lspe->virq[1] == (unsigned int)irq) | |
75 { | |
76 /** | |
77 * クラス 1 割り込み | |
78 * (変換) | |
79 */ | |
80 unsigned long mfc_dsisr, mfc_dar; | |
81 | |
82 // 割り込みステータスを取得 | |
83 hvc_get_spe_int_stat(lspe->spe_id, 1, &int_stat); | |
84 int_stat &= spe_int_mask[1]; | |
85 // printk(KERN_INFO "[%s] INT_Stat_class1 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat); | |
86 | |
87 | |
88 // MFC データ・ストレージ割り込みステータス・レジスタおよび | |
89 // MFC データ・アドレス・レジスタの値を取得 | |
90 mfc_dsisr = in_be64(lspe->shadow + 0x0610 /*MFC_DSISR*/); | |
91 mfc_dar = in_be64(lspe->shadow + 0x0620 /*MFC_DAR*/); | |
92 // printk(KERN_INFO " MFC_DSISR = 0x%016lx\n", mfc_dsisr); | |
93 // printk(KERN_INFO " MFC_DAR = 0x%016lx\n", mfc_dar); | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 if (int_stat & 1) // MFC データ・セグメントエラー | |
101 { | |
102 unsigned long esid = (mfc_dar & 0xFFFFFFFFF0000000UL) | 0x8000000UL /*[V]*/; | |
103 | |
104 if (REGION_ID(mfc_dar) == USER_REGION_ID) | |
105 { | |
106 unsigned long vsid = get_vsid(lspe->mm->context.id, mfc_dar, MMU_SEGSIZE_256M); | |
107 | |
108 // vsid を SLB エントリに登録 | |
109 out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, lspe->slb_index); | |
110 out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid << 12 | 0xc00 /*Ks|Kp*/ | 0x80 /*C*/ | 0x000 /*L|LP*/); | |
111 out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, esid); | |
112 | |
113 lspe->slb_index++; | |
114 if (lspe->slb_index >= 8) lspe->slb_index = 2; | |
115 | |
116 // MFC コマンドの再始動 | |
117 out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, 1UL<<32 /*[R]*/); | |
118 } | |
119 } | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
129 #if 0 | |
130 // 割り込みステータスをクリア | |
131 if (int_stat & 2) | |
132 { | |
133 lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0610UL /*MFC_DSISR*/, 0UL); | |
134 } | |
135 hvc_clear_spe_int_stat(lspe->spe_id, 1, int_stat); | |
136 | |
137 | |
138 if (int_stat & 2) // MFC データ・ストレージエラー | |
139 { | |
140 if (mfc_dsisr & 0x40000000 /*MFC_DSISR[M]*/) | |
141 { | |
142 if (REGION_ID(mfc_dar) != USER_REGION_ID) | |
143 { | |
144 int ret = hash_page(mfc_dar, _PAGE_PRESENT, 0x300); | |
145 // printk(KERN_INFO "hash_page() [kernel side] = %d\n", ret); | |
146 if (!ret) | |
147 { | |
148 // MFC コマンドの再始動 | |
149 out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, 1UL<<32 /*[R]*/); | |
150 } | |
151 } | |
152 } | |
153 } | |
154 #endif | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | |
163 // 割り込みステータスをクリア | |
164 if (int_stat & 2) | |
165 lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0610UL /*MFC_DSISR*/, 0UL); | |
166 hvc_clear_spe_int_stat(lspe->spe_id, 1, int_stat); | |
167 break; | |
168 } | |
169 | |
170 if (lspe->virq[2] == (unsigned int)irq) | |
171 { | |
172 /** | |
173 * クラス 2 割り込み | |
174 * (アプリケーション) | |
175 */ | |
176 unsigned int spu_status, spu_npc, spu_stop_code; | |
177 | |
178 // 割り込みステータスを取得 | |
179 hvc_get_spe_int_stat(lspe->spe_id, 2, &int_stat); | |
180 int_stat &= spe_int_mask[2]; | |
181 // printk(KERN_INFO "[%s] INT_Stat_class2 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat); | |
182 | |
183 | |
184 // SPU ステータスおよびネクスト・プログラム・カウンタを取得 | |
185 asm volatile("eieio"); // cf. Cell Broadband Engine アーキテクチャ version 1.01 (p.93) | |
186 spu_status = in_be32(lspe->problem + 0x04024UL /*SPU_Status*/); | |
187 spu_stop_code = spu_status >> 16; | |
188 spu_npc = in_be32(lspe->problem + 0x04034UL /*SPU_NPC*/); | |
189 // printk(KERN_INFO " SPU_Status = 0x%08x\n", spu_status); | |
190 // printk(KERN_INFO " StopCode = 0x%04x\n", spu_stop_code); | |
191 // printk(KERN_INFO " SPU_NPC = 0x%08x\n", spu_npc); | |
192 | |
193 | |
194 if (spu_status & 1<<1 /*[P]*/) | |
195 { | |
196 switch (spu_stop_code) | |
197 { | |
198 case SPE_PROCESS_STOP_CODE_FINISH: | |
199 { | |
200 spe_process_context_list_t *this_process = get_running_process(i), *next_process = NULL; | |
201 spinlock_t *spinlock_for_process_list = get_spinlock_for_process_list(); | |
202 | |
203 | |
204 // Critical Section (spinlock) >>> | |
205 spin_lock(spinlock_for_process_list); | |
206 { | |
207 next_process = get_next_waiting_process(); | |
208 | |
209 /* | |
210 unsigned long addr; | |
211 for (addr = 0x0; addr < 0x0 + 0x60; addr+= 0x10) | |
212 { | |
213 printk(KERN_INFO "0x%04lx | %016lx %016lx\n", addr, in_be64(lspe->ls + addr), in_be64(lspe->ls + addr + 8)); | |
214 } | |
215 */ | |
216 | |
217 // 実行プロセスコンテキストをクリア | |
218 clear_running_process(i); | |
219 | |
220 // このプロセスのコンテキストを更新 | |
221 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED; | |
222 increment_not_released(); | |
223 | |
224 // 実行待ちプロセスがあるか | |
225 if (next_process != NULL) | |
226 { | |
227 // このプロセスを実行中にする | |
228 remove_process_from_waiting(next_process); | |
229 // next_process->context.read.spe_no = i; | |
230 next_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_RUNNING; | |
231 | |
232 set_running_process(i, next_process); | |
233 } | |
234 } | |
235 spin_unlock(spinlock_for_process_list); | |
236 // <<< Critical Section (spinlock) | |
237 | |
238 | |
239 // SPE プロセス開始 | |
240 if (next_process != NULL) start_spe_process(i, next_process); | |
241 } | |
242 } | |
243 } | |
244 | |
245 // 割り込みステータスをクリア | |
246 hvc_clear_spe_int_stat(lspe->spe_id, 2, int_stat); | |
247 break; | |
248 } | |
249 } | |
250 | |
251 return IRQ_HANDLED; | |
252 // return int_stat ? IRQ_HANDLED : IRQ_NONE; | |
253 } |