Mercurial > hg > Game > Atoc
view driver/lspe.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 source
/** * lspe.c * SPE プロセスマネージャ spe_manager * 論理 SPE に関する処理 */ #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 #include <asm/pgtable-ppc64.h> // 暫定 #include "../include/hvcalls/common.h" #include "../include/hvcalls/spe.h" #include "../include/hvcalls/repository.h" #include "lspe.h" #include "interrupt.h" #include "main.h" // 割り込みマスク値定数 const HVC_u64 spe_int_mask[SPE_VIRQ_CLASS_MAX+1] = { (HVC_u64)0x07, // SPE クラス 0 割り込み (すべての要因をイネーブル) (HVC_u64)0x0F, // SPE クラス 1 割り込み (すべての要因をイネーブル) (HVC_u64)0x0F // SPE クラス 2 割り込み (INT_Mask_class2[B] はイネーブルにするとハング) }; // 論理 SPE 用変数 static int lspe_count = 0; static lspe_data_t lspe_data[SPE_COUNT_MAX]; // 内部で利用する関数 static int initialize_logical_spe(const HVC_u64, const HVC_u64, const int, const HVC_u64, irq_handler_t); static void finalize_logical_spe(const int); //============================================================================================ initialize_logical_spes() /** * initialize_logical_spes * 論理 SPE の確保と初期化 * * @param HVC_u64 lpar_id 論理パーティション識別子 * @param HVC_u64 vas_id 仮想アドレス識別子 * @return int */ int initialize_logical_spes(const HVC_u64 lpar_id, const HVC_u64 vas_id) { for ( lspe_count = 0; (SPE_COUNT_REQ && lspe_count < SPE_COUNT_REQ && lspe_count < SPE_COUNT_MAX) || (!SPE_COUNT_REQ && lspe_count < SPE_COUNT_MAX); lspe_count++ ) { int ret = initialize_logical_spe(lpar_id, vas_id, lspe_count, (HVC_u64)lspe_count, interrupt_handler); if (ret) { printk ( KERN_NOTICE "[%s] Notice: spe%d.initialize_logical_spe() returned %d. (%s:%u)\n", SPE_MANAGER_MODULE_NAME, lspe_count, ret, __FILE__, __LINE__ ); break; } } return lspe_count; } //============================================================================================= initialize_logical_spe() /** * initialize_logical_spe * 論理 SPE の確保と初期化 * * @param HVC_u64 lpar_id 論理パーティション識別子 * @param HVC_u64 vas_id 仮想アドレス空間識別子 * @param int n SPE 番号 (0..x) * @param HVC_u64 spe_reserve_key 論理 SPE 予約キー (0..5) * @param irq_handler_t irq_handler 論理 SPE 割り込みハンドラ * @return int * @static */ static int initialize_logical_spe ( const HVC_u64 lpar_id, const HVC_u64 vas_id, const int n, const HVC_u64 spe_reserve_key, irq_handler_t irq_handler ) { HVC_u64 TMP_spe_id, lpar_ls, lpar_problem, lpar_priv2, lpar_shadow; HVC_u64 value1, spe_rsv; HVC_u64 outlet[SPE_VIRQ_CLASS_MAX+1]; unsigned int TMP_virq[SPE_VIRQ_CLASS_MAX+1]; char *TMP_virq_dev_name[SPE_VIRQ_CLASS_MAX+1]; int i, j; if (n < 0 || n >= SPE_COUNT_MAX) return -1; // 論理 SPE を生成 if (hvc_create_logical_spe(vas_id, &TMP_spe_id, &lpar_ls, &lpar_problem, &lpar_priv2, &lpar_shadow)) { return -2; } // 論理 SPE 予約識別子を取得する if (hvc_get_repository_node ( lpar_id, hvc_make_repository_first_key("bi", 0), hvc_make_repository_key("spursv", 0), spe_reserve_key, 0, &value1, &spe_rsv )) { hvc_destroy_logical_spe(TMP_spe_id); return -3; } // 論理 SPE を利用可能状態にする if (hvc_enable_logical_spe(TMP_spe_id, spe_rsv)) { hvc_destroy_logical_spe(TMP_spe_id); return -4; } // MFC ステート・レジスタ 1 (MFC_SR1) を設定 // lv1_set_spe_privilege_state_area_1_register(TMP_spe_id, 0UL, 0x33UL); // S, R, T, D // lv1_set_spe_privilege_state_area_1_register(TMP_spe_id, 0UL, 0x7bUL); // TL, S, R, PR, T, D for (i = 0; i <= SPE_VIRQ_CLASS_MAX; i++) { // SPE IRQ アウトレットを生成 if (hvc_create_spe_irq_outlet(TMP_spe_id, (HVC_u64)i, &outlet[i])) { for (j = 0; j < i; j++) { free_irq(TMP_virq[j], NULL); kfree(TMP_virq_dev_name[j]); ps3_irq_plug_destroy(TMP_virq[j]); // Note: SPE IRQ アウトレットは解放できない? // (解放するためのハイパーバイザコールがない→論理 SPE を解放すればおk?) } hvc_disable_logical_spe(TMP_spe_id); hvc_destroy_logical_spe(TMP_spe_id); return -5; } // 仮想割り込み番号を生成 (カーネルの手助けを要する) if (ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, outlet[i], &TMP_virq[i])) { for (j = 0; j < i; j++) { free_irq(TMP_virq[j], NULL); kfree(TMP_virq_dev_name[j]); ps3_irq_plug_destroy(TMP_virq[j]); // Note: SPE IRQ アウトレットは解放できない? } hvc_disable_logical_spe(TMP_spe_id); hvc_destroy_logical_spe(TMP_spe_id); return -6; } // 割り込みハンドラの dev_name の準備 if ((TMP_virq_dev_name[i] = (char *)kmalloc(sizeof(char) * 32, GFP_KERNEL)) == NULL) { printk ( KERN_NOTICE "[%s] Notice: spe%d.kmalloc() returned NULL. (%s:%u)\n", SPE_MANAGER_MODULE_NAME, n, __FILE__, __LINE__ ); } else { sprintf(TMP_virq_dev_name[i], SPE_MANAGER_DEVICE_NAME " (spe%d_class%d)", n, i); } // 割り込みハンドラを登録 if (request_irq(TMP_virq[i], irq_handler, IRQF_DISABLED, TMP_virq_dev_name[i], NULL)) { for (j = 0; j < i; j++) { free_irq(TMP_virq[j], NULL); kfree(TMP_virq_dev_name[j]); ps3_irq_plug_destroy(TMP_virq[j]); // Note: SPE IRQ アウトレットは解放できない? } kfree(TMP_virq_dev_name[i]); ps3_irq_plug_destroy(TMP_virq[i]); // Note: SPE IRQ アウトレットは解放できない? hvc_disable_logical_spe(TMP_spe_id); hvc_destroy_logical_spe(TMP_spe_id); return -7; } // SPE の割り込みマスクを設定 hvc_set_spe_int_mask(TMP_spe_id, (HVC_u64)i, spe_int_mask[i]); } // lspe_data の各フィールドに格納 lspe_data[n].spe_id = TMP_spe_id; for (i = 0; i <= SPE_VIRQ_CLASS_MAX; i++) { lspe_data[n].virq[i] = TMP_virq[i]; lspe_data[n].virq_dev_name[i] = TMP_virq_dev_name[i]; } lspe_data[n].ls = ioremap_flags(lpar_ls, lpar_problem - lpar_ls, _PAGE_NO_CACHE); lspe_data[n].problem = ioremap(lpar_problem, lpar_priv2 - lpar_problem); lspe_data[n].priv2 = ioremap(lpar_priv2, SPE_PRIV2_AREA_SIZE); { // Note: シャドウレジスタエリアはこのようにマップしないとレジスタの読み込み時に OS ごと落ちる unsigned long shadow_flags = _PAGE_NO_CACHE | 3; lspe_data[n].shadow = __ioremap(lpar_shadow, SPE_SHADOW_AREA_SIZE, shadow_flags); } // LS エリアを 0 クリア memset(lspe_data[n].ls, 0, SPE_LS_AREA_SIZE); asm volatile("eieio"); return 0; } //===================================================================================================== get_lspe_count() /** * get_lspe_count * 確保・初期化された論理 SPE の数を取得する * * @return int 論理 SPE 数 */ int get_lspe_count(void) { return lspe_count; } //====================================================================================================== get_lspe_data() /** * get_lspe_data * 確保・初期化された論理 SPE データを取得する * * Note: 引数 n に負数や確保した論理 SPE 以上のインデックスを指定した場合は NULL が返る。 * * @param int n SPE 番号 (0..x) * @return lspe_data_t * 論理 SPE データへのポインタ */ lspe_data_t *get_lspe_data(const int n) { return (n >= 0 && n < lspe_count) ? lspe_data + n : NULL; } //============================================================================================== finalize_logical_spes() /** * finalize_logical_spes * 論理 SPE の解放 * * @return void */ void finalize_logical_spes(void) { for (--lspe_count; lspe_count >= 0; lspe_count--) { finalize_logical_spe(lspe_count); } } //=============================================================================================== finalize_logical_spe() /** * finalize_logical_spe * 論理 SPE の解放 * * @param int n SPE 番号 (0..x) * @return void * @static */ static void finalize_logical_spe(const int n) { int i; iounmap(lspe_data[n].ls); iounmap(lspe_data[n].problem); iounmap(lspe_data[n].priv2); for (i = 0; i <= SPE_VIRQ_CLASS_MAX; i++) { free_irq(lspe_data[n].virq[i], NULL); kfree(lspe_data[n].virq_dev_name[i]); ps3_irq_plug_destroy(lspe_data[n].virq[i]); // Note: SPE IRQ アウトレットは解放できない? } hvc_disable_logical_spe(lspe_data[n].spe_id); hvc_destroy_logical_spe(lspe_data[n].spe_id); }