المقاطعات من الأجهزة الخارجية في نظام x86. الجزء 3. تكوين توجيه المقاطعة في شرائح باستخدام المثال الأساسية

نستمر في النظر في تكوين المقاطعات من أجهزة خارجية في نظام x86.
في الجزء 1 ( تطور وحدات تحكم المقاطعة ) ، درسنا الأسس النظرية لوحدات التحكم في المقاطعة والمصطلحات العامة ؛ في الجزء 2 ( خيارات التمهيد kernel Linux ) ، بحثنا في كيفية قيام نظام التشغيل باختيار بين وحدات التحكم في الممارسة. في هذا الجزء ، سننظر في كيفية قيام BIOS بتكوين توجيه IRQ لوحدات التحكم في المقاطعة في مجموعة الشرائح.

لا توجد شركات تطوير BIOS حديثة (AwardBIOS / AMIBIOS / Insyde) تكشف عن الكود المصدري لبرامجها. ولكن لحسن الحظ ، يوجد Coreboot ، وهو مشروع لاستبدال BIOS الخاص ببرمجيات مجانية. في الكود ، سنرى كيف يتم تكوين توجيه المقاطعة في مجموعة الشرائح.




النظرية


أولاً ، قم بتحديث واستكمال المعرفة النظرية لدينا. في الجزء 1 ، حددنا مسار مقاطعة مشترك لحالة PIC و APIC.

الموافقة المسبقة عن علم:



APIC:



في هذه الأشكال ، يتم عرض تخطيط PCI → PCI بشكل تجريدي ؛ في الواقع ، هو أكثر تعقيدًا إلى حد ما. في الواقع ، يحتوي كل جهاز PCI على 4 خطوط مقاطعة (INTA # و INTB # و INTC # و INTD #). يمكن أن يحتوي كل جهاز PCI على ما يصل إلى 8 وظائف ولكل وظيفة بالفعل مقاطعة INTx # واحدة. أي سطر من INTx # سيتم سحب كل وظيفة من وظائف الجهاز إما ثابت في الأجهزة أو يتم تحديده من خلال تكوين الجهاز.



في جوهرها ، وظائف هي كتل منطقية منفصلة. على سبيل المثال ، في جهاز PCI واحد ، قد تكون هناك وظيفة جهاز تحكم Smbus ، ووحدة تحكم SATA ، ووظيفة جسر LPC. على جانب نظام التشغيل ، كل وظيفة عبارة عن جهاز منفصل به مساحة تكوين PCI Config الخاصة به.

في أبسط الحالات (وأكثرها شيوعًا) في جهاز PCI ، هناك وظيفة واحدة فقط ، تتم المقاطعة عبر خط INTA #. ولكن بشكل عام ، قد يحتوي الجهاز على أكثر من 4 وظائف (كما قلنا قبل 8) ، ثم سيتعين زرع بعضها على سطر INTx # واحد (مقاطعات PCI يمكن أن تقسم الخط). أيضًا ، بالنسبة لأجهزة PCI المضمنة في مجموعة الشرائح عن طريق الكتابة إلى السجلات الخاصة ، من الممكن غالبًا الإشارة إلى الوظائف التي تستخدم أسطر INTx # (وما إذا كانت تستخدم على الإطلاق).

منهجية معرفتنا ، نشير إلى مسار (التوجيه) من الانقطاعات من أي وظيفة PCI من خلال INTx # → PIRQy → IRQz ، حيث:

  • INTx # - سطر INT # (INTA # ، INTB # ، INTC # ، INTD #) لجهاز PCI الذي ستستخدمه الوظيفة
  • PIRQy - خط PIRQ (PIRQA ، PIRQB ، ...) من PIR الذي يتصل به خط INTx #
  • IRQz - خط IRQ (0 ، 1 ، 2 ، ...) على وحدة تحكم المقاطعة (APIC / PIC) ، وهو متصل بخط PIRQy

لماذا لا يمكنك الاتصال فقط في كل مكان INTA # → PIRQA ، INTB # → PIRQB ، ...؟


لماذا تهتم بإعداد التوجيه على الإطلاق؟ لنفترض أننا قررنا عدم الإزعاج والحصول على جميع خطوط المقاطعة من جميع أجهزة PCI إلى نفس خطوط PIRQ. دعنا نقول هذا:

  • INTA # → PIRQA
  • INTB # → PIRQB
  • INTC # → PIRQC
  • INTD # → PIRQD

كما قلنا أعلاه ، فإن الحالة الأكثر شيوعًا هي عندما يكون لجهاز PCI وظيفة واحدة ، وانقطاعه متصل بخط INTA # (لماذا يجب على مطور الجهاز تشغيله بشكل مختلف؟). لذلك إذا قررنا فجأة بدء جميع الخطوط كما كتبنا ، فسيتم تقسيم جميع المقاطعات من الأجهزة تقريبًا إلى خطوط PIRQA. دعنا نقول أنها أنهت IRQ16. ثم في كل مرة يتم فيها إبلاغ المعالج بحدوث مقاطعة على خط IRQ16 ، سيتعين عليه استجواب برامج تشغيل جميع الأجهزة المتصلة بخط IRQ16 (PIRQA) إذا كانت هناك مقاطعة لها. إذا كان هناك العديد من هذه الأجهزة ، فلن يؤدي ذلك بطبيعة الحال إلى تسريع استجابة النظام للمقاطعة. وستكون خطوط PIRQB-PIRQD في هذه الحالة في معظمها خاملاً. للتوضيح ، يوضح الشكل المشكلة:



ولكن كل شيء يمكن القيام به مثل هذا:



الصورة مربكة بعض الشيء ، لكن النقطة المهمة هي أننا ببساطة نربط خطوط INTx # مع PIRQy بالروبوتات المستديرة (PIRQA ، PIRQB ، PIRQC ، PIRQD ، PIRQA ، PIRQB ، PIRQC ، PIRQD ، PIRQA ، PIRQB ، PIRQD ،. ..)

تجدر الإشارة إلى أنه من الضروري هنا مراعاة ليس فقط تحميل نفس عدد وظائف PCI على كل سطر PIRQ. بعد كل شيء ، يمكن أن تنشئ بعض الوظائف المقاطعات بشكل نادر جدًا ، والبعض الآخر بشكل دائم (وحدة تحكم Ethernet على سبيل المثال). في هذه الحالة ، يمكن حتى تبرير تخصيص خط PIRQ منفصل للمقاطعات مع مثل هذه الوظيفة.

بناءً على ما تقدم ، يتولى مطور BIOS ، من بين أشياء أخرى ، مهمة التأكد من أن خطوط PIRQ يتم تحميلها بشكل موحد مع المقاطعات.

ماذا يجب أن تفعل BIOS على الإطلاق؟


نحن منظمون في الشكل:



  • 1) حدد أي سطر من INTx # لكل وظيفة من أجهزة PCI يسحب
    بالنسبة لأجهزة PCI الخارجية ، لا يتم تنفيذ هذا العنصر ، ولكن قد يكون ذلك مفيدًا لوظائف أجهزة PCI المضمنة في مجموعة الشرائح.
  • 2) تكوين INTx # → تعيين PIRQy لكل جهاز PCI
    تجدر الإشارة إلى أنه يمكن أن يكون هناك أكثر من أربع إشارات PIRQy قياسية (PIRQA ، PIRQB ، PIRQC ، PIRQD). على سبيل المثال 8: PIRQA-PIRQH.

تنتقل إشارات PIRQy إلى خط IRQz لوحدة التحكم في المقاطعة المحددة (APIC / PIC). نظرًا لأننا نريد دعم جميع طرق التحميل الممكنة (انظر الجزء 2 ) ، فإننا نحتاج إلى ملء كلا التعيينين:

  • 3a) املأ تعيين PIRQy → IRQz1 للاتصال PIR → I / O APIC
    ولكن هذا ليس ضروريًا في العادة ، نظرًا لأن خطوط PIRQy مثبتة على خط APIC. الحل المشترك هو PIRQA → IRQ16 ، PIRQB → IRQ17 ، ... الحل الأبسط ، لأن بوضع خطوط PIRQy على خطوط التحكم ≥ 16 ، لا داعي للقلق بشأن التعارضات مع المقاطعات غير المنفصلة من أجهزة ISA.
  • 3 ب) املأ تعيين PIRQy → IRQz2 للاتصال PIR → PIC
    يجب توفير هذا في حالة استخدامنا التوجيه من خلال وحدة تحكم PIC. لا يوجد حل لا لبس فيه كما في حالة APIC ، لأنه في حالة الموافقة المسبقة عن علم ، ينبغي للمرء أن يتذكر حول احتمال وجود تعارضات مع المقاطعات لا ينفصلان من أجهزة ISA.

هناك حاجة إلى العنصر الرابع الأخير لمساعدة نظام التشغيل في تحديد توجيه المقاطعة. الجهاز نفسه عادة لا يستخدم هذه السجلات.

  • 4) املأ سجلات مقاطعة الخط / المقاطعة لكل وظيفة PCI
    بشكل عام ، يتم ملء سجل دبوس المقاطعة تلقائيًا وعادة ما يكون للقراءة فقط ، لذلك على الأرجح سيتطلب ملء فقط ملء سجل خط المقاطعة. يجب توفير ذلك في حالة استخدامنا التوجيه من خلال وحدة تحكم PIC دون تزويد نظام التشغيل بأي جدول حول مقاطعات التوجيه (انظر مرة أخرى الجزء 2 ). إذا تم توفير الجداول وكان هذا التعيين متوافقًا مع جداول التوجيه ($ PIR / ACPI) ، فغالبًا ما يتركه نظام التشغيل.

تجدر الإشارة إلى أننا لا نلمس جداول $ PIR / MPtable / ACPI حتى الآن وننظر في كيفية تكوين سجلات شرائح من حيث مقاطعات التوجيه قبل نقل التحكم إلى محمل النظام. تعد جداول المقاطعة موضوعًا لمقالة منفصلة (ربما مقالة مستقبلية).

لذلك ، يتم دراسة الأسس النظرية ، وأخيرا نبدأ في ممارسة!

الممارسة


وكمثال على المقالات في هذه السلسلة ، أستخدم لوحة مخصصة بمعالج Intel Haswell i7 ومجموعة شرائح LynxPoint-LP. في هذا المنتدى ، أطلقت لعبة coreboot بالتعاون مع SeaBIOS. يوفر Coreboot التهيئة الخاصة بالأجهزة ، وتوفر حمولة SeaBIOS واجهة BIOS لأنظمة التشغيل. في هذه المقالة ، لن أصف عملية تكوين نظام التشغيل الأساسي ، ولكن حاول فقط أن أقوم بمثال بنوع إعدادات BIOS التي يجب إجراؤها في مجموعة الشرائح لتوجيه مقاطعات IRQ من الأجهزة الخارجية.

نظرًا لتطوير مشروع coreboot بنشاط حتى يتم تحديث المقالة دائمًا ، سننظر في الكود باستخدام مثال أحدث إصدار ثابت 4.9 (الإصدار 2018-12-20).

أقرب اللوحات الأم إلى Google هي Google Beltino مع تنوع النمر. المجلد الرئيسي لهذه اللوحة هو المجلد "src \ mainboard \ google \ beltino" . تتركز جميع الإعدادات هنا والرمز المحدد لهذا المنتدى.

لذلك ، لنبدأ في فرز أماكن تكوين العناصر أعلاه:

1) حدد أي سطر من INTx # لكل وظيفة من أجهزة PCI يسحب


يتم تعريف هذه المعلومات في ملف "src / mainboard / google / beltino / romstage.c" في بنية rcba_config عبر سجلات DxxIP (Device xx Interrupt Pin Register (IP)). يشير هذا السجل إلى الرقم INTx # (A / B / C / D) الذي تقوم كل وظيفة من وظائف الجهاز بإخراج مقاطعة منه.

الخيارات الممكنة (انظر الملف "src / southbridge / intel / lynxpoint / pch.h" ):

0h = No interrupt 1h = INTA# 2h = INTB# 3h = INTC# 4h = INTD# 

من المفترض أن العديد من الوظائف تستخدم نفس دبوس.

من المفترض أن الوظائف قد لا تستخدم الرقم السري للمقاطعات (بدون مقاطعة).
كل شيء كما رأينا في الشكل في بداية المقال.

الكود الكامل مسؤول عن العنصر الذي حددناه:

 /* Device interrupt pin register (board specific) */ RCBA_SET_REG_32(D31IP, (INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP)), RCBA_SET_REG_32(D29IP, (INTA << D29IP_E1P)), RCBA_SET_REG_32(D28IP, (INTA << D28IP_P1IP) | (INTC << D28IP_P3IP) | (INTB << D28IP_P4IP)), RCBA_SET_REG_32(D27IP, (INTA << D27IP_ZIP)), RCBA_SET_REG_32(D26IP, (INTA << D26IP_E2P)), RCBA_SET_REG_32(D22IP, (NOINT << D22IP_MEI1IP)), RCBA_SET_REG_32(D20IP, (INTA << D20IP_XHCI)), 

لفهم أفضل ، فكر في بعض الأمثلة:

مثال 1:

يحتوي الجهاز 0x1d (29 في العشري) وظيفة واحدة (تحكم EHCI).

في هذه الحالة ، قم بتعيين مقاطعة إلى INTA #.

00: 1d.0 - INTA #

 RCBA_SET_REG_32(D29IP, (INTA << D29IP_E1P)), 

مثال 2:
يحتوي الجهاز 0x1f (31 في عشري) على وظائف جهاز التحكم في المستشعر الحراري (00: 1f.6) ، وحدة تحكم SATA 2 (00: 1f.2) ، وحدة تحكم SMBus (00: 1f.3) ، وحدة تحكم SATA 1 (00: 1f) .2). نريد فقط استخدام وحدة التحكم SMBus ووحدة التحكم SATA 1 ووحدة التحكم في المستشعر الحراري.

00: 1f.2 - INTA # (وحدة تحكم SATA 1)
00: 1f.3 - INTB # (وحدة تحكم SMBus)
00: 1f.2 - لا مقاطعة (لا يتم استخدام وحدة تحكم SATA 2)
00: 1f.6 - INTC # (جهاز التحكم في المستشعر الحراري)

لهذا التكوين ، يجب أن تكتب:

 RCBA_SET_REG_32(D31IP, (INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP)), 

مثال 3:

في جهاز واحد ، يكون عدد الوظائف التي نحتاج إليها أكثر من 4. في جهاز 0x1c ، تكون كل وظيفة مسؤولة عن منفذ PCI Express. لكي تعمل المنافذ من 0 إلى 5 ، ويتم توزيع المقاطعات بين السطور بالتساوي ، يمكنك تكوين هذا:

00: 1c.0 - INTA # (منفذ PCI Express 0)
00.1c.1 - INTB # (منفذ PCI Express 1)
00.1c.2 - INTC # (منفذ PCI Express 2)
00.1c.3 - INTD # (منفذ PCI Express 3)
00.1c.4 - INTA # (منفذ PCI Express 4)
00.1c.5 - INTB # (منفذ PCI Express 5)
00.1c.6 - لا يوجد مقاطعة (المنفذ غير مستخدم)
00.1c.7 - لا مقاطعة (المنفذ غير مستخدم)

 RCBA_SET_REG_32(D28IP, (INTA << D28IP_P1IP) | (INTB << D28IP_P2IP) | (INTC << D28IP_P3IP) | (INTD << D28IP_P4IP) | (INTA << D28IP_P5IP) | (INTB << D28IP_P6IP) | (NOINT << D28IP_P7IP) | (NOINT << D28IP_P8IP)), 

2) تكوين INTx # → تعيين PIRQy لكل جهاز PCI


يتم تعريف هذه المعلومات أيضًا في الملف "src \ mainboard \ google \ beltino \ romstage.c"
في هيكل rcba_config ، ولكن بالفعل من خلال سجلات DxxIR (تسجيل مسار جهاز المقاطعة xx).

تُظهر المعلومات الموجودة في هذا السجل خط PIRQx (A / B / C / D / E / F / G / H) الذي يتصل به كل خط مقاطعة INTx #.

 /* Device interrupt route registers */ RCBA_SET_REG_32(D31IR, DIR_ROUTE(PIRQG, PIRQC, PIRQB, PIRQA)),/* LPC */ RCBA_SET_REG_32(D29IR, DIR_ROUTE(PIRQD, PIRQD, PIRQD, PIRQD)),/* EHCI */ RCBA_SET_REG_32(D28IR, DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD)),/* PCIE */ RCBA_SET_REG_32(D27IR, DIR_ROUTE(PIRQG, PIRQG, PIRQG, PIRQG)),/* HDA */ RCBA_SET_REG_32(D22IR, DIR_ROUTE(PIRQA, PIRQA, PIRQA, PIRQA)),/* ME */ RCBA_SET_REG_32(D21IR, DIR_ROUTE(PIRQE, PIRQF, PIRQF, PIRQF)),/* SIO */ RCBA_SET_REG_32(D20IR, DIR_ROUTE(PIRQC, PIRQC, PIRQC, PIRQC)),/* XHCI */ RCBA_SET_REG_32(D23IR, DIR_ROUTE(PIRQH, PIRQH, PIRQH, PIRQH)),/* SDIO */ 

مثال 1:

الجهاز 0x1c (28 في النظام العشري) هو منافذ PCIe كما اكتشفنا بالفعل.

نقوم بعمل اتصال "مباشر":

  • INTA # → PIRQA
  • INTB # → PIRQB
  • INTC # → PIRQC
  • INTD # → PIRQD

 RCBA_SET_REG_32(D28IR, DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD)) 

مثال 2:

0x1d الجهاز (29 في العشري) - وظيفة واحدة (وحدة تحكم EHCI) على INTA # ، لا يتم استخدام خطوط أخرى.

قم بتوصيل خط INTA # بـ PIRQD:

 RCBA_SET_REG_32(D29IR, DIR_ROUTE(PIRQD, PIRQD, PIRQD, PIRQD)) 

في هذه الحالة ، يكون سجل PIRQD الأول فقط (لـ INTA #) منطقيًا ، والباقي ليس منطقيًا.

3a) املأ التعيين PIRQy → IRQz1 (PIR → APIC)


كما قلنا بالفعل ، غالبًا ما يتم إصلاح التعيين هنا ، وهذه الحالة ليست استثناء.

  • PIRQA → IRQ16
  • PIRQB → IRQ17
  • ...
  • PIRQH → IRQ23

3 ب) املأ التعيين PIRQy → IRQz2 (PIR → PIC)


في الأساسية ، يتم تعريف محتويات ملء هذه السجلات في ملف devicetree.cb في مجلد اللوحة الأم "src \ mainboard \ google \ beltino \".

devicetree.cb (اسم devicetree للتواصل مع مفهوم مشابه في Linux kernel ، و "cb" هو اختصار لـ coreboot) وهو ملف خاص يعكس تكوين هذه اللوحة الأم: أي معالج ، يتم استخدام مجموعة الشرائح ، وأي الأجهزة يتم تضمينها فيها ، والتي خارج الخ بالإضافة إلى ذلك ، يمكن تحديد معلومات خاصة لتكوين شرائح في هذا الملف. هذه هي الحالة التي نحتاجها فقط:

 register "pirqa_routing" = "0x8b" register "pirqb_routing" = "0x8a" register "pirqc_routing" = "0x8b" register "pirqd_routing" = "0x8b" register "pirqe_routing" = "0x80" register "pirqf_routing" = "0x80" register "pirqg_routing" = "0x80" register "pirqh_routing" = "0x80" 

تحدد هذه الخطوط تعيين PIRQy → IRQz2. في التعليمات البرمجية ، بعد تحليل ملف devicetree.cb ، يتم تحويلها إلى متغيرات "config-> pirqX_routing".

يعني المتغير "config-> pirqa_routing = 0x8b" أن PIRQA متصل بسطر المقاطعة IRIC11 (0x0b = 11) لوحدة التحكم PIC ، ومع ذلك ، فإن البت الأعلى (وهو 0x80) يعني عدم تنفيذ توجيه المقاطعة. بصراحة ، في تجربتي ، يعد هذا خطأً ، ومن الجدير افتراضيًا تشغيل توجيه الموافقة المسبقة عن علم ، سيكون نظام التشغيل نفسه قادرًا على التبديل إلى I / O APIC عن طريق تعيين هذا البت إلى 1 إذا لزم الأمر.

هذا هو ، في هذه الحالة سيكون من الأصح الكتابة:

 register "pirqa_routing" = "0x0b" register "pirqb_routing" = "0x0a" register "pirqc_routing" = "0x0b" register "pirqd_routing" = "0x0b" register "pirqe_routing" = "0x80" # not used register "pirqf_routing" = "0x80" # not used register "pirqg_routing" = "0x80" # not used register "pirqh_routing" = "0x80" # not used 

لم نقم بتمكين المقاطعات الأربعة الأخيرة ، لأن تُستخدم المقاطعة IRQ0 دائمًا في إطار مؤقت النظام وهي غير متوفرة بوضوح (انظر معلومات المقاطعة العامة المتوافقة مع IBM-PC ).

ولكن إذا ألقينا نظرة فاحصة على النقطة 2) ، فسوف نرى أن بعض أجهزة PCI تستخدم خطوط PIRQE-PIRQH ، لذلك فإن تركها دون اتصال هو الطريقة الصحيحة للأجهزة المعطلة.

لذلك من الأفضل كتابة شيء مثل هذا:
 register "pirqa_routing" = "0x03" register "pirqb_routing" = "0x04" register "pirqc_routing" = "0x05" register "pirqd_routing" = "0x06" register "pirqe_routing" = "0x0a" register "pirqf_routing" = "0x0b" register "pirqg_routing" = "0x0e" register "pirqh_routing" = "0x0f" 


يحدث التعبئة الفعلية للسجلات المقابلة في الملف src \ southbridge \ intel \ lynxpoint \ lpc.c في الوظيفة pch_pirq_init.

مقتطف الشفرة المسؤول عن تعبئة السجل:

 /* Get the chip configuration */ config_t *config = dev->chip_info; pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing); pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing); pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing); pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing); pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing); pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing); pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing); pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing); 

يتم وصف ثوابت عنوان السجل في نفس ملف pch.h

 #define PIRQA_ROUT 0x60 #define PIRQB_ROUT 0x61 #define PIRQC_ROUT 0x62 #define PIRQD_ROUT 0x63 #define PIRQE_ROUT 0x68 #define PIRQF_ROUT 0x69 #define PIRQG_ROUT 0x6A #define PIRQH_ROUT 0x6B 

يتم تعيين تعيين PIRQy → IRQz2 لمجموعة الشرائح هذه على جهاز LPC PCI (العنوان 00: 1f.0) في سجلات PIRQy_ROUT. تجدر الإشارة إلى أنه في كثير من الأحيان لا يُسمح باستخدام جميع خطوط IRQz2 الخمسة عشر في الموافقة المسبقة عن علم للاستخدام ، ولكن جزءًا فقط (على سبيل المثال ، 3،4،5،6،7،9،10،11،12،14،15). يجب أن يحتوي وصف هذه السجلات على معلومات حول IRQs المتوفرة لتعيين المقاطعات من خطوط PIRQ إليهم. لذلك ، فإن التعيين المقترح من قبلنا أعلاه ممكن فقط إذا كان تخصيص PIRQ على السطر IRQ3 ، IRQ4 ، IRQ5 ، IRQ6 ، IRQ10 ، IRQ11 ، IRQ14 ، IRQ15 متاحًا. ولكن إذا نظرنا بعناية في التعليق قبل وظيفة pch_pirq_init ، فسنرى أنه:

 /* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control * 0x00 - 0000 = Reserved * 0x01 - 0001 = Reserved * 0x02 - 0010 = Reserved * 0x03 - 0011 = IRQ3 * 0x04 - 0100 = IRQ4 * 0x05 - 0101 = IRQ5 * 0x06 - 0110 = IRQ6 * 0x07 - 0111 = IRQ7 * 0x08 - 1000 = Reserved * 0x09 - 1001 = IRQ9 * 0x0A - 1010 = IRQ10 * 0x0B - 1011 = IRQ11 * 0x0C - 1100 = IRQ12 * 0x0D - 1101 = Reserved * 0x0E - 1110 = IRQ14 * 0x0F - 1111 = IRQ15 * PIRQ[n]_ROUT[7] - PIRQ Routing Control * 0x80 - The PIRQ is not routed. */ 

4) املأ سجلات مقاطعة الخط / المقاطعة لكل وظيفة PCI


يوجد في مساحة تكوين PCI (لكل PCI وظائف وفقًا للمعايير) هناك سجلان مهمان لنا:

  • 3Ch: Interrupt Line - هنا تحتاج إلى كتابة رقم IRQz2 (رقم من 0 إلى 15) ، وهو رقم المقاطعة الذي تسحبه الوظيفة أخيرًا عند استخدام وحدة التحكم PIC
  • 3Dh: Interrupt Pin - يعرض السطر INTx # (A / B / C / D) الذي تستخدمه الوظيفة

لنبدأ مع آخر واحد. سيتم ملء سجل Interrupt Pin تلقائيًا بناءً على إعدادات الشرائح (سجلات DxxIP) التي أعدناها في الفقرة 1 وسيكون للقراءة فقط.

كل ما تبقى هو تعبئة سجل المقاطعة مع مقاطعة IRQz2 لكل وظيفة PCI.

معرفة تعيين PIRQy → IRQz2 (العنصر 3 ب) ، ورسم الخرائط INTx # → PIRQy (البند 2) ، يمكنك بسهولة ملء سجل خط المقاطعة لكل وظيفة ، ومعرفة أي مقاطعة INTx # تستخدمه (البند 1).

في نظام التشغيل الأساسية ، يتم تسجيل سجلات Interrupt Line أيضًا في ملف src \ southbridge \ intel \ lynxpoint \ lpc.c في دالة pch_pirq_init:

 /* Eric Biederman once said we should let the OS do this. * I am not so sure anymore he was right. */ for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) { u8 int_pin=0, int_line=0; if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI) continue; int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); switch (int_pin) { case 1: /* INTA# */ int_line = config->pirqa_routing; break; case 2: /* INTB# */ int_line = config->pirqb_routing; break; case 3: /* INTC# */ int_line = config->pirqc_routing; break; case 4: /* INTD# */ int_line = config->pirqd_routing; break; } if (!int_line) continue; pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); } 

لسبب ما ، يشير هذا الرمز إلى أن التعيين في أي حال INTA # → PIRQA ، INTB # → PIRQB ، INTC # → PIRQC ، INTD # → PIRQD. على الرغم من أننا في الممارسة العملية رأينا أنه قد يكون مختلفًا (انظر الفقرة 2)

عموما "إريك بيدرمان قال ذات مرة" ، وقمنا بنسخه في أي مكان:

 $ grep "Eric Biederman once said" -r src/ src/southbridge/intel/fsp_bd82x6x/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/i82801gx/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/i82801ix/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/lynxpoint/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/sch/lpc.c: /* Eric Biederman once said we should let the OS do this. 

بشكل عام ، لا يهتم coreboot حقًا بدعم المقاطعة القديم. الكثير ليفاجأ في هذا الخطأ لا يستحق كل هذا العناء. عند تحميل نظام تشغيل حديث ، لن يزعجك ذلك ، ولكن إذا كنت بحاجة فجأة إلى تحميل Linux بخيارات "acpi = off nolapic" ، فمن الصعب القيام بذلك.

الخاتمة


في الختام ، سنكرر المعلومات النموذجية التي يجب تكوينها في مجموعة الشرائح لتوجيه مقاطعات PCI:

  1. حدد أي سطر INTx تسحب كل وظيفة من وظائف PCI
  2. تكوين INTx # → تعيين PIRQy لكل جهاز PCI
  3. املأ تعيين PIRQy → IRQz1 (PIR → APIC) ورسم خرائط PIRQy → IRQz2 (PIR → PIC)
  4. املأ سجلات مقاطعة الخط / المقاطعة لمساحة تكوين PCI لكل وظيفة من وظائف PCI.

Source: https://habr.com/ru/post/ar440304/


All Articles