0

ここ数週間、Linux/MIPS カーネルの SGI Octane (IP30) へのポートで SMP サポートを再び動作させようと試みてきました。ユニプロセッサ サポートは正常に動作しますが、2 番目の CPU を使用すると多くの問題が発生します。マシンをinitプロセスで起動できますが、ほとんどの場合、SIGSEGV または SIGBUS で停止します。私は 5 年以上前に書かれたパッチからのサポート コードのほとんどを適切に配置していますが、適切にロックしていないか、予期せず IRQ を再度有効にしていると思われます。


ハードウェアの背景:

MIPS R10000 シリーズ CPU は、次の目的で 8 つの割り込みを実装IP0していIP7ます。

  • IP0およびIP1: ソフトウェア割り込みのみで、現在あまり使用されていません。
  • IP2to IP6: 通常、処理のために他のハードウェア関数にルーティングされます。
  • IP7: R10K タイマー/カウンター/コンペア割り込み。

  • R10K は MIPS-IV ISA をサポートし、I キャッシュと D キャッシュの両方を備えています。

    • I キャッシュは 32kB、VIPT、2 ウェイ、および 64 バイトのラインサイズです。
    • D キャッシュは 32kB、VIPT、2 ウェイ、エイリアスなし、32 バイトのラインサイズです。
  • R10K L2 キャッシュは 2MB、双方向、128 バイトのラインサイズです。
  • R10K はスーパースカラーであり、投機的実行を採用し、順不同で実行できます。
  • Octane はキャッシュ コヒーレントであるため、投機的実行の影響を受けません。
  • 具体的には、このシステムには R14000 デュアル モジュールがあります。主に R10K であり、ダイの縮小とより高速なクロック速度を備えていること以外は、あまり知られていません。SGI は、このプロセッサのハードウェア データシートやエラッタ情報を公開したことはありません。


HEARTOctane には、メモリ コントローラーと割り込みコントローラーの両方 と呼ばれる ASIC があります。HEART最大 4 つのプロセッサをサポートするように設計されており、64 の割り込み (IRQ) が利用可能です。これらの 64 の IRQ は、いくつかの優先度レベルに分割され、上記の R10K CPU IPx IRQ にマップされます。

  • 0レベル 0 、IRQ 15-> CPUIP2
  • レベル 1、IRQ 16- 31> CPUIP3
  • レベル 2、IRQ 31- 49> CPUIP4
  • レベル 3、IRQ 50-> CPUIP5
  • 51レベル 4 、IRQ 63-> CPUIP6


これらの優先度レベルについて、いくつかの注意事項があります。

  • レベル 0 およびレベル 1 の IRQ は、主にシステム内のデバイス (SCSI、イーサネットなど) に割り当てられます。

  • レベル 2 にはいくつかの用途があります。

    • IRQ3240、システム内のデバイス (特に、より高い優先度が必要なデバイス) で使用することもできます。
    • IRQ41は、電源ボタンを押すために配線されています。
    • IRQは、4 つの可能な CPU4245のデバッガー信号用です。
    • IRQ4649、可能な 4 つの CPU の SMP プロセッサ間割り込み (IPI) です。

  • レベル 3 の IRQ50は、それ自体のカウンター/比較タイマー専用ですHEART。12.5MHz (80ns だと思います) で動作します。シングルカウントレジスタとコンペアレジスタを持っています。Linux のclockevent観点からは、これはシステム タイマー (52 ビット カウンター、24 ビット コンペア) として使用するのに適した分解能のタイマーだと思います。

  • レベル 4 はエラー IRQ 用です。

    • IRQ 51toは、XIO バス (スター トポロジーに配置され、 ASICによって処理される高速バス) 上58の 8 つの使用可能なウィジェットのそれぞれに対するエラー IRQ です。XtalkXBOW
    • IRQ 59to62は、可能な 4 つの CPU のバス エラー IRQ です。
    • IRQ63は、それ自体の例外エラー IRQ ですHEART

HEART割り込みを操作するためのいくつかのレジスタを示します。各レジスタは 64 ビット幅で、割り込みごとに 1 ビットです。

  • HEART_ISR- 保留中の割り込みのリストを取得するための読み取り専用レジスタ。
  • HEART_SET_ISR- 特定の割り込みビットを設定するための書き込み専用レジスタ。
  • HEART_CLR_ISR- 特定の割り込みビットをクリアするための書き込み専用レジスタ
  • HEAR_IMR(x)- で表される、特定の CPU 上の特定の割り込みの割り込みマスクを設定またはクリアする読み取り/書き込みレジスタx


基本的な IRQ ack/mask/unmasking 操作に次のコードを使用します。

u64 *imr;                       /* Address of the mask register to work on */
static int heart_irq_owner[64]; /* Which CPU owns which IRQ? (global) */

Ack:    writeq((1UL << irq), HEART_CLR_ISR);

Mask:   imr = HEART_IMR(heart_irq_owner[irq]);
        writeq(readq(imr) & (~(1UL << irq)), imr);

Unmask: imr = HEART_IMR(heart_irq_owner[irq]);
        writeq(readq(imr) | (1UL << irq), imr);


これらの基本的な操作はstruct irq_chip、3.1x シリーズの Linux カーネル内のアクセサーを使用して実装され、HEARTレジスターへのアクセスを および を使用spin_lock_irqsaveして保護しますspin_unlock_irqrestore。これらのアクセサーでこれらのロック機能を使用する必要があるかどうかは、100% 確信が持てません。



すべての割り込みを処理するために、標準の Linux/MIPS プラットフォームのディスパッチ関数は次のアクションを実行します。

  • IP7do_IRQ()-> CPU タイマー IRQ を処理するための呼び出し。
  • IP6->エラーを syslogip30_do_error_irq()に報告するための呼び出し。HEART
  • IP5->タイマーdo_IRQ()に割り当てられたクロック イベント IRQ を処理するための呼び出しHEART
  • IP4IP3、および-> 0 から 49 までのすべての IRQ を処理するためのIP2呼び出し。ip30_do_heart_irq()HEART


これは、現在使用されているコードですip30_do_heart_irq():

static noinline void ip30_do_heart_irq(void)
{
    int irqnum = 49;
    int cpu = smp_processor_id();
    u64 heart_isr = readq(HEART_ISR);
    u64 heart_imr = readq(HEART_IMR(cpu));
    u64 irqs = (heart_isr & 0x0003ffffffffffffULL &
                heart_imr);

    /* Poll all IRQs in decreasing priority order */
    do {
        if (irqs & (1UL << irqnum))
            do_IRQ(irqnum);
        irqnum--;
    } while (likely(irqnum >= 0));
}


SMP サポートに関しては、他の Linux/MIPS プラットフォームとは異なり、どのような IPI アクションを実行する必要があるかを格納するメールボックス レジスタのようなものをハードウェアに持っていません。ip30_ipi_mailbox元のコードは、他のプロセッサに渡す IPI アクションを指定するために、CPUID でインデックス付けされたグローバル int 配列 ( ) を使用します。

さらに、HEARTSGI は最大 4 つのプロセッサをサポートするように設計されていましたが、デュアル CPU モジュールしか製造していませんでした。したがって、IRQ 44- 4548- 49、および61-62が実際に使用されることはありません。

これらのグローバル変数が与えられた場合:

#define IPI_CPU(x) (46 + (x))
static DEFINE_SPINLOCK(ip30_ipi_lock);
static u32 ip30_ipi_mailbox[4];


これは、IPI を他の CPU に送信するために現在使用されているコードです。

static void ip30_send_ipi_single(int cpu, u32 action)
{
    unsigned long flags;

    spin_lock_irqsave(&ip30_ipi_lock, flags);
    ip30_ipi_mailbox[cpu] |= action;
    spin_unlock_irqrestore(&ip30_ipi_lock, flags);
    writeq(1UL << IPI_CPU(cpu)), HEART_SET_ISR);
}


IPI に応答するために、各 CPU はrequest_irq初期化コードを呼び出し、割り込みハンドラを登録します。これは、IPI 割り込みを処理するためにハンドラーで現在使用されているコードです。

static irqreturn_t ip30_ipi_irq(int irq, void *dev_id)
{
    u32 action;
    int cpu = smp_processor_id();
    unsigned long flags;

    spin_lock_irqsave(&ip30_ipi_lock, flags);
    action = ip30_ipi_mailbox[cpu];
    ip30_ipi_mailbox[cpu] = 0;
    spin_unlock_irqrestore(&ip30_ipi_lock, flags);

    if (action & SMP_RESCHEDULE_YOURSELF)
        scheduler_ipi();

    if (action & SMP_CALL_FUNCTION)
        smp_call_function_interrupt();

    return IRQ_HANDLED;
}



そして、それが背景情報です。

私の現在のカーネル構成には、フレームバッファーと「Impact」ビデオドライバーを除くすべてが取り除かれています。PCI なし、ブロック層なし、ネットワークなし、シリアルなし、キーボード/マウスなし。私は〜7年前のinitramfsをロードしています。すべてが機能すれば、bashプロンプトにドロップするはずです。ただし、RAM に読み込まれるため、メモリの破損がすぐに明らかになる可能性があり、その結果、前述の SIGSEGV または SIGBUS エラーが発生します。

リモート GDB または組み込みの KGDB を使用することは、IOC3 PCI デバイスのため、現時点ではオプションではありません。IOC3 は、単一機能デバイスであると主張する多機能 PCI デバイスであり、その背後には、キーボード/マウス、シリアル ポート、リアルタイム クロック、およびイーサネット用のハードウェア ビットがあります。IOC3 を回避してリモート GDB のシリアル ポートに直接アクセスするためのコードはまだ存在しません。また、KGDB は IOC3 上の標準の i8042 キーボード コントローラーと対話する方法も知りません。

標準の PCI シリアル カード (Moschip ベース) を追加しましたが、そのドライバーは明らかにエンディアン セーフではないため、シリアル ポートをプローブするとカーネル パニックが発生します。


次の質問に答えることで、問題のあるコードをより適切に特定し、それを正しく機能させることに集中できるようになり、SMP を機能させるための正しい道に進むことができると思います。

  • スピンロックを正しく使用していますか?
  • 正しいスピンロックバリアントを使用していますか?
  • 同期呼び出しをどこにでも追加する必要がありますか (つまり、smp_rmb()smp_wmb()など)?
  • 私の問題は、このコア プラットフォーム サポート コードの外 (ビデオ ドライバーなど) にあるのでしょうか?
  • メモリを無作為に破壊する未知のハードウェア エラータを見ている可能性はありますか?
  • 上記のコードのいずれかをより適切に実装できますか? (その多くは、Linux 2.6.17 の元のポートから Octane へのコードであり、カーネル内の他の動作とよりインラインになるように更新されたばかりです)

これを理解するための正しい道に私を置くことができる情報は高く評価されます. 私の希望は、SMP を使用可能な状態にすることです (効率は関係ありません。動作するために必要なだけです)。そのため、パッチに分割する作業を開始し、ある時点でそれをメインライン カーネルに含めることを確認できます。SMP を動作させることができない場合は、そのサポートを中止し、代わりにユニプロセッサ コードをアップストリームに送信することに集中します。

4

2 に答える 2

1

このバグは最終的に解決され、IRQ 番号が正しいハンドラに割り当てられなくなりました。最初に 64 個すべての IRQ を使用するように割り当ててhandle_level_irqいましたが、これは SMP プロセッサ間割り込み (IPI) には正しくありません。修正により、代わりに 8 つの CPU 固有の割り込み、42-45 および 46-49 が割り当てられることが判明しましたhandle_percpu_irq

于 2016-04-04T02:59:14.853 に答える
0

このケースは非常に興味深いです: 特にそれを再現する方法がある場合. 残念ながら私はそれを持っていません:)。しかし、問題を修正する必要があるかどうかを確認したいことがたくさんあります。2- すべての割り込みを 1 つの CPU にバインドし、ボードを起動します。問題が発生した場合、SMP の割り込みを処理するために追加したコードに問題はないと思います。irq のアフィニティを 1 つの CPU (cpu0 としましょう) に設定してください。このテストでは、コードをそのままにしておきます... 1 つの CPU に対する割り込みのアフィニティを必ず変更してください。

結果を共有することを躊躇しないでください。それが役立つことを願っています。

アイメン。

于 2014-11-24T22:15:21.183 に答える