Elbrus प्रोसेसर पर Embox। या जो आपको बुद्धिमत्ता में मिला है उसे कभी न भूलें

यह लेख एमब्रो टू एलब्रस प्रोसेसर आर्किटेक्चर (ई 2 डी) को पेश करने पर " एलब्रस पर चढ़ाई" लेखों की एक श्रृंखला के लिए तार्किक निष्कर्ष है। एक तार्किक निष्कर्ष क्यों, क्योंकि परिणामस्वरूप, टेलनेट के माध्यम से एक एप्लिकेशन चलाना संभव था जो स्क्रीन पर छवि प्रदर्शित करता है, अर्थात, इस वास्तुकला पर एमबॉक्स का पूरा संचालन प्राप्त करने के लिए। आगे के शोध को शायद ही एक परिचय कहा जा सकता है, हालांकि, बहुत अस्पष्ट है। और वास्तुकला में स्वयं कई दिलचस्प विशेषताएं हैं, जो वर्तमान में भी समझ में नहीं आती हैं। इस लेख में, हम वर्चुअल मेमोरी के संगठन पर ध्यान केंद्रित करेंगे, हम पीसीआई पर टच करेंगे, नेटवर्क कार्ड के बारे में थोड़ी बात करेंगे और एक विशिष्ट हार्डवेयर पर एक वीडियो कार्ड पर स्पर्श करेंगे।

उन लोगों के लिए जो लेख पढ़ने के लिए बहुत आलसी हैं, मैं तुरंत परिणामों के साथ एक छोटा वीडियो दूंगा।


और अब जो लोग रुचि रखते हैं, हम उन तकनीकी विवरणों को प्रकट करेंगे जिन्हें हम प्रक्रिया में समझने में सक्षम थे।

आभासी स्मृति


हमारी स्टैक त्रुटि


आभासी स्मृति से शुरू करते हैं। दरअसल, यह वही है जो हमने श्रृंखला के पिछले लेख में तय किया था। यह तुरंत याद रखने योग्य है कि हमें आभासी मेमोरी की आवश्यकता क्यों है, क्योंकि Embox इसके बिना काम कर सकता है। यह आसान है: बात कैशिंग है। विद्या ने काम किया, लेकिन मुझे विश्वसनीय स्मृति पुनर्प्राप्ति के लिए वीडियो मेमोरी में एक ही चीज़ को दो बार रिकॉर्ड करना पड़ा। बेशक, कैश से निपटना संभव था, लेकिन हमारे उदाहरणों में कैश एप्लिकेशन जैसे किसी भी परमाणु सामान के बिना, एक उपयोगकर्ता एप्लिकेशन से सीधे वीडियो मेमोरी का उपयोग करना शामिल है, इसलिए यह सीखना सही था कि मेमोरी को नॉन-कैचेबल के रूप में कैसे मैप किया जाए। लिनक्स पर fb ( उदाहरण ) को मैप करके भी यही काम किया जा सकता है।

यह ध्यान देने योग्य है कि यद्यपि हमने लंबे समय तक एल्ब्रस के बारे में नहीं लिखा था और ऐसा लग सकता है कि इस वास्तुकला में एमएमयू किसी प्रकार का सुपर जटिल है, लेकिन बात अलग है। वास्तव में, हमने गर्मियों में समर्थन जोड़ा, हम बस इसके बारे में लिखने के लिए अपने हाथों तक नहीं पहुंचे। हमारी मूर्खतापूर्ण गलती के कारण एक लंबा समय (कई महीने) व्यतीत हुआ। यह गलती भी लेख के शीर्षक में की गई थी ("खुफिया जानकारी के दौरान आपको जो मिला है उसे कभी न भूलें")। हम उन ढेरियों के बारे में बात कर रहे हैं जिनके साथ हमने बहुत अच्छी तरह से निपटा और इस लेख का वर्णन किया है क्लिम्बिंग एल्ब्रस - रिकोनाइसेंस। तकनीकी भाग 1. रजिस्टर, ढेर और अन्य तकनीकी विवरण" हमने बहुत लंबे समय तक सामना किया, इस तथ्य के बारे में मूर्खतापूर्ण दृष्टि से खो दिया कि हम प्रारंभिक स्टैक (जिस पर सिस्टम को इनिशियलाइज़ किया गया है) को कहीं बाहर से ले जाते हैं, और सब कुछ मैप करते हैं। हमें काम करने के लिए Embox की क्या आवश्यकता है, हमने इस डेटा को मैप नहीं किया।

बिल्ली के नीचे, मैं एक नया फ़ंक्शन e2k_entry देता हूं, जिसे श्रृंखला में लेख के दूसरे लेख में वर्णित किया गया है।

यदि वांछित है, तो आप तुलना कर सकते हैं।

__attribute__ ((__section__(".e2k_entry"))) void e2k_entry(struct pt_regs *regs) { /* Since we enable exceptions only when all CPUs except the main one * reached the idle state (cpu_idle), we can rely that order and can * guarantee exceptions happen strictly after all CPUS entries. */ if (entries_count >= CPU_COUNT) { /* Entering here because of exception or interrupt */ e2k_trap_handler(regs); RESTORE_COMMON_REGS(regs); E2K_DONE; } /* It wasn't exception, so we decide this usual program execution, * that is, Embox started on CPU0 or CPU1 */ e2k_wait_all(); entries_count = __e2k_atomic32_add(1, &entries_count); if (entries_count > 1) { /* XXX currently we support only single core */ /* Run cpu_idle on 2nd CPU */ /* it's just needed if log_debug enabled in e2k_context module * else output will be wrong because 2 cpu printing at the same time */ while(!sync_count); context_init(&cpu_ctx[0], CONTEXT_PRIVELEGED | CONTEXT_IRQDISABLE, cpu_idle, idle_stack, sizeof(idle_stack)); context_switch(&cpu_ctx_prev[0], &cpu_ctx[0]); } /* Run e2k_kernel_start on 1st CPU */ context_init(&cpu_ctx[1], CONTEXT_PRIVELEGED | CONTEXT_IRQDISABLE, e2k_kernel_start, &_stack_top, KERNEL_STACK_SZ); sync_count = __e2k_atomic32_add(1, &sync_count); context_switch(&cpu_ctx_prev[1], &cpu_ctx[1]); } 

मैं सिर्फ यह समझाऊंगा कि अब हम Embox स्पेस में मेमोरी में स्टैक को स्विच करने के लिए केवल reference_init () और reference_switch () फंक्शन्स का उपयोग करते हैं। और हम सभी कोर के लिए ऐसा करते हैं, जिनमें उन का उपयोग नहीं किया जाता है।

MMU संगठन


अब मैं E2k आर्किटेक्चर में MMU के संगठन के बारे में थोड़ी बात करूँगा।

सामान्य तौर पर, MMU वास्तुकला काफी सामान्य है और इसमें चार-स्तरीय तालिकाओं (या 4MB पेज का उपयोग करते समय तीन) हैं।

E2k वास्तुकला में कई सेवा रजिस्टर हैं, वे वैकल्पिक स्थानों तक पहुंच आदेशों का उपयोग करते हुए पहुंचते हैं, साथ ही I / O अंतरिक्ष में संक्षेप में लेख में वर्णित "Embox Elbrus चढ़ाई शुरू करता है"

हमें ऐसे रजिस्टरों की आवश्यकता होगी:

 #define MMU_REG_CR 0x00 /* Control register */ #define MMU_REG_CONT 0x10 /* Context register */ #define MMU_REG_CR3_RG 0x20 /* CR3 register for INTEL only */ #define MMU_REG_ELB_PTB 0x30 /* ELBRUS page table virtual base */ #define MMU_REG_ROOT_PTB 0x40 /* Root Page Table Base register *// 

दरअसल, यह एक कंट्रोल रजिस्टर, एक संदर्भ संख्या रजिस्टर, टेबल का एक रूट रजिस्टर और थोड़ा अस्पष्ट MMU_REG_ELB_PTB है। चलो इसके साथ शुरू करते हैं, इस रजिस्टर को कुछ मूल्य पर सेट किया जाना चाहिए, अगले 512GB का उपयोग प्रोसेसर द्वारा उपकरणों की जरूरतों के लिए किया जाएगा, और ये पते प्रोग्रामर के लिए उपलब्ध नहीं होंगे। मैं आईसीएसटी विशेषज्ञ के पत्र से स्पष्टीकरण प्रदान करूंगा, मैं शायद ही बेहतर समझा सकता हूं:

लिनक्स पर, हम MMU_ELB_PTB को 0xff1 << 39 और फिर सेट करते हैं
वर्चुअल मेमोरी का ऊपरी क्षेत्र (0xff8000000000 - 0xffffffffff)
उपकरण की जरूरतों के लिए आरक्षित, टीएलबी। प्रत्येक पृष्ठ
पृष्ठ तालिका (TS) को इस क्षेत्र में अपना विशिष्ट पता प्राप्त होता है,
इसके अलावा, ये पते आसानी से उस पते से प्राप्त किए जाते हैं जिस पर कार्यक्रम
स्मृति से अपील की। और कब से टीएलबी वर्चुअल एड्रेस मैपिंग को स्टोर करता है
भौतिक, यह आपको उसी TLB बफर में कैश करने की अनुमति देता है
न केवल उपयोगकर्ता पते के लिए, बल्कि वाहन के लिए भी प्रसारण करता है।

उन प्रोसेसर / आर्किटेक्चर में जहां अलग-अलग के लिए अलग-अलग टीएलबी बनाए जाते हैं
पृष्ठ तालिका स्तर, ऐसी चाल अनावश्यक हो जाती है।

इस प्रकार, जब आप टीएलबी को याद करते हैं, तो खोज शुरू नहीं करना संभव हो जाता है
शून्य स्तर (pgd *) से, और तुरंत वाहन के अंतिम स्तर (pte *) की जांच करें।
इस क्षेत्र में, Wirth को मैप करने के लिए कोई हार्डवेयर की आवश्यकता नहीं है से पता
यह केवल TLB खोज के लिए अनुक्रमित के रूप में आवश्यक है। हालाँकि, कोर में
पृष्ठ तालिका के शून्य स्तर के अंतिम pgd को भौतिक द्वारा लिखा गया है इसका पता
सबसे शून्य स्तर। नतीजतन, केवल
क्षेत्र के अंतिम 4 KB ff80'0000'0000 - ffff'ffff'ffff - अर्थात्। बस सही है
शून्य वाहन स्तर। इससे pgd * को सामान्य द्वारा एक्सेस किया जा सकता है
वर्चुअल पते पर काम करने वाले निर्देशों को पढ़ें / लिखें।

नतीजतन, यह केवल इस रजिस्टर में एक महान मूल्य रखने का फैसला किया गया था, जो हमें परेशान नहीं करेगा। आखिरकार, प्रस्तावित समाधान हमें पृष्ठों की खोज का अनुकूलन करने की अनुमति देता है, लेकिन हम अभी तक अनुकूलन में लगे नहीं हैं। लिनक्स में के रूप में ही वितरित।

अब कंट्रोल रजिस्टर। आपको इसके माध्यम से MMU को सक्षम करने की आवश्यकता है। ज्ञात बिट्स इस तरह दिखते हैं:

 #define _MMU_CR_TLB_EN 0x0000000000000001 /* translation enable */ #define _MMU_CR_CD_MASK 0x0000000000000006 /* cache disable bits */ #define _MMU_CR_SET1 0x0000000000000008 /* set #1 enable for 4 MB pages */ #define _MMU_CR_SET2 0x0000000000000010 /* set #2 enable for 4 MB pages */ #define _MMU_CR_SET3 0x0000000000000020 /* set #3 enable for 4 MB pages */ /* paging enable for second space INTEL */ #define _MMU_CR_CR0_PG 0x0000000000000040 /* page size 4Mb enable for second space INTEL */ #define _MMU_CR_CR4_PSE 0x0000000000000080 /* cache disable for secondary space INTEL */ #define _MMU_CR_CR0_CD 0x0000000000000100 /* TLU enable for secondary space INTEL */ #define _MMU_CR_TLU2_EN 0x0000000000000200 /* memory protection table enable for LD from secondary space INTEL */ #define _MMU_CR_LD_MPT 0x0000000000000400 #define _MMU_CR_IPD_MASK 0x0000000000000800 /* Instruction Prefetch Depth */ #define _MMU_CR_UPT_EN 0x0000000000001000 /* enable UPT */ 

हम पहले बिट में रुचि रखते हैं, जिसमें पतों का अनुवाद शामिल है।

हम _MMU_CR_SET3 भी सेट करते हैं, लेकिन हमें यह पता नहीं चला है कि किन विशेष मामलों में ऐसा किया जाना चाहिए।

प्रतियोगिता रजिस्टर ठीक है, अगर सरल है, तो यह प्रक्रिया या पते की जगह का पीआईडी ​​है। अधिक तकनीकी रूप से, यह 11-बिट एड्रेस एक्सटेंशन है। हमारे मामले में, हमने सभी पृष्ठों को परमाणु बना दिया है, हमारे सभी पृष्ठों में वैश्विकता की थोड़ी सी भी सेटिंग करके, हम एक ही पते की जगह का उपयोग करते हैं और इसलिए हम इस रजिस्टर में शून्य का उपयोग कर सकते हैं।

रूट टेबल के रजिस्टर में अनुवाद तालिका की शुरुआत के भौतिक पते के लिए एक संकेतक है। आप केवल MMU_REG_ELB_PTB रजिस्टर में निर्दिष्ट पते पर तालिका को मैप करके एक धोखाधड़ी कर सकते हैं, लेकिन जैसा कि मैंने कहा, हम अनुकूलन पर ध्यान केंद्रित नहीं कर रहे थे।

मैं और क्या कह सकता हूं, तालिकाओं की संरचना काफी सामान्य है, झंडे इस प्रकार हैं:

 #define E2K_MMU_PAGE_P 0x0000000000000001ULL /* Page Present bit */ #define E2K_MMU_PAGE_W 0x0000000000000002ULL /* Writable (0 - only read) */ #define E2K_MMU_PAGE_UU2 0x0000000000000004ULL /* unused bit # 2 */ #define E2K_MMU_PAGE_PWT 0x0000000000000008ULL /* Write Through */ #define E2K_MMU_PAGE_CD1 0x0000000000000010ULL /* Cache disable (right bit) */ #define E2K_MMU_PAGE_A 0x0000000000000020ULL /* Accessed Page */ #define E2K_MMU_PAGE_D 0x0000000000000040ULL /* Page Dirty */ #define E2K_MMU_PAGE_HUGE 0x0000000000000080ULL /* Page Size */ #define E2K_MMU_PAGE_G 0x0000000000000100ULL /* Global Page */ #define E2K_MMU_PAGE_CD2 0x0000000000000200ULL /* Cache disable (left bit) */ #define E2K_MMU_PAGE_NWA 0x0000000000000400ULL /* Prohibit address writing */ #define E2K_MMU_PAGE_AVAIL 0x0000000000000800ULL /* Available page */ #define E2K_MMU_PAGE_PFN 0x000000fffffff000ULL /* Physical Page Number */ #define E2K_MMU_PAGE_VALID 0x0000010000000000ULL /* Valid Page */ #define E2K_MMU_PAGE_PV 0x0000020000000000ULL /* PriVileged Page */ #define E2K_MMU_PAGE_INT_PR 0x0000040000000000ULL /* Integer address access Protection */ #define E2K_MMU_PAGE_NON_EX 0x0000080000000000ULL /* Non Executable Page */ #define E2K_MMU_PAGE_RES 0x0000f00000000000ULL /* Reserved bits */ #define E2K_MMU_PAGE_C_UNIT 0xffff000000000000ULL /* Compilation Unit */ 

4-स्तरीय तालिका के लिए, पता शिफ्ट इस प्रकार हैं:

 #define __MMU_PGD_SHIFT (PAGE_SHIFT + 3 * (PAGE_SHIFT-3)) /* 39 */ #define __MMU_PUD_SHIFT (PAGE_SHIFT + 2 * (PAGE_SHIFT-3)) /* 30 */ #define __MMU_PMD_SHIFT (PAGE_SHIFT + 1 * (PAGE_SHIFT-3)) /* 21 */ 

PCI के बारे में थोड़ा सा


वैकल्पिक पते के स्थानों के माध्यम से संचार


Vidyaha और नेटवर्क कार्ड पर जाने से पहले, आइए संक्षेप में PCI में वापस चलते हैं। हमने पहले ही इसके बारे में थोड़ी बात की थी "Embox माउंट एलब्रस पर चढ़ना शुरू करता है" इसने वैकल्पिक पता स्थानों के साथ संचार करने के लिए मैक्रोज़ दिखाया:

 #define _E2K_READ_MAS(addr, mas, type, size_letter, chan_letter) \ ({ \ register type res; \ asm volatile ("ld" #size_letter "," #chan_letter " \t0x0, [%1] %2, %0" \ : "=r" (res) \ : "r" ((__e2k_ptr_t) (addr)), \ "i" (mas)); \ res; \ }) #define _E2K_WRITE_MAS(addr, val, mas, type, size_letter, chan_letter) \ ({ \ asm volatile ("st" #size_letter "," #chan_letter " \t0x0, [%0] %2, %1" \ : \ : "r" ((__e2k_ptr_t) (addr)), \ "r" ((type) (val)), \ "i" (mas) \ : "memory"); \ }) 

और पता रिक्त स्थान के सिद्धांत का संदर्भ था। अलग-अलग एड्रेस स्पेस को MAS (मेमोरी एड्रेस स्पेसियर) का उपयोग करके परिभाषित किया गया है। और उदाहरण के लिए, आईओ तक पहुंचने के लिए, जिसके माध्यम से पीसीआई एक्सेस किया जाता है, आपको 6 और एमएमयू 7 का उपयोग करने की आवश्यकता है।

लेकिन मैक्रो के अधिक गहन अध्ययन के साथ, आप किसी प्रकार के चान_लेटर को नोटिस कर सकते हैं। और अगर आप e2k कमांड के विवरण को देखें, तो हम पाते हैं
LDD डबल वर्ड रीडिंग
ldd [पता] मास, डीएसटी

यही है, पहली नज़र में, कोई चैनल नहीं हैं। लेकिन यदि आप लिंक का अनुसरण करते हैं, तो यह पता चलता है कि दिए गए ऑपरेशन ldd के लिए कोड 67 है। लेकिन 67 केवल चैनल AL0 / AL3 और AL2 / AL5 के लिए ldd के लिए कोड है, और चैनल AL1 / AL4 के लिए यह कोड POPCNTd के संचालन से मेल खाता है।

इसलिए, यह पूरी तरह से समझना संभव नहीं था कि एल्ब्रस की शब्दावली में कौन से चैनल हैं। मैं यह सुझाव देने के लिए उद्यम करूंगा कि यह पहले से ही vliw सिद्धांत के साथ जुड़ा हुआ है, जब आप यह निर्दिष्ट कर सकते हैं कि किस अलू का उपयोग किया जाता है, क्योंकि इस प्रकार की वास्तुकला में एक विशेषता कई स्वतंत्र कंप्यूटिंग उपकरणों की उपस्थिति है। मैं निश्चित रूप से गलत हो सकता हूं, लेकिन तथ्य यह है कि पीसीआई या एमएमयू तक पहुंचने के लिए आपको दूसरे या पांचवें चैनल का उपयोग करने की आवश्यकता है। इस प्रकार, कमांड कुछ इस तरह दिखाई देगी:
ldd, 2 0x0, [addr_in_mas] mas_id,% reg

lspci


अब मैं उस डिवाइस पर lspci कमांड के आउटपुट का परिणाम दूंगा जो हमारे पास है:
root @ embox: (null) #lspci
00: 0.0 (PCI देव E3E3: ABCD) [6 4]
पीसीआई-टू-पीसीआई पुल: (अशक्त) एल्ब्रस पीसीआई पुल (रेव 01)
00: 1.0 (पीसीआई देव 8086: ई 3 ई 3) [6 4]
PCI-to-PCI ब्रिज: Intel Corporation Elbrus Virt PCI ब्रिज (रेव 01)
01: 0.0 (PCI देव 1FFF: 8000) [6 4]
पीसीआई-टू-पीसीआई पुल: (अशक्त) एल्ब्रस पीसीआई पुल (पुन: 05)
01: 1.0 (PCI देव 8086: 4D45) [2 0]
ईथरनेट कंट्रोलर: इंटेल कॉर्पोरेशन MCST ETH1000 गिगाबिट ईथरनेट (Rev 01)
01: 2.0 (PCI देव 8086: 4D49) [1 1]
IDE कंट्रोलर: Intel Corporation MCST IDE (Rev 128)
01: 2.1 (पीसीआई देव 8086: 0002) [7 2]
सिंपल कॉम। नियंत्रक: इंटेल कॉरपोरेशन (शून्य) (संशोधित ०५)
01: 2.2 (पीसीआई देव 8086: 8000) [7 128]
सिंपल कॉम। नियंत्रक: इंटेल कॉर्पोरेशन एल्ब्रस पीसीआई पुल (रेव 00)
01: 2.3 (पीसीआई देव 1013: 6005) [4 1]
मल्टीमीडिया डिवाइस: सिरस लॉजिक क्रिस्टल CS4281 पीसीआई ऑडियो (रेव 01)
01: 3.0 (पीसीआई देव 8086: 4748) [1 6]
मास स्टोरेज कंट्रोलर: Intel Corporation MCST SATA (Rev 00)
01: 4.0 (PCI देव 8086: 554F) [12 3]
USB डिवाइस: Elbrus के लिए Intel Corporation OHCI (Rev 00)
01: 4.1 (पीसीआई देव 8086: 5545) [12 3]
USB डिवाइस: Elbrus के लिए Intel Corporation EHCI (Rev 00)
02: 1.0 (पीसीआई देव 126F: 0718) [3 0]
वीजीए-संगत नियंत्रक: सिलिकॉन मोशन, इंक। SM718 लिंक्स + (रेव 160)
रूट @ embox: (अशक्त) #

टिप्पणी
01: 2.2 (पीसीआई देव 8086: 8000) [7 128]
सिंपल कॉम। नियंत्रक: इंटेल कॉर्पोरेशन एल्ब्रस पीसीआई पुल (रेव 00)

वास्तव में, यह MC85 से am85c30 के समान एक सीरियल पोर्ट है, कम से कम इस डिवाइस के माध्यम से हम मिनिकॉम के माध्यम से संवाद करते हैं।

नेटवर्क कार्ड


सामान्य संरचना


अब नेटवर्क कार्ड पर आते हैं।

अगर मैं सही ढंग से समझूं, तो यह मूल नेटवर्क कार्ड है, ऑपरेशन में ई -1000 से थोड़ा सा समान है, लेकिन केवल ऑपरेशन में (जैसे कि प्राप्तकर्ताओं में मौजूद विवरण और प्रेषित कतारें)।

अब हमारे सामने आए महत्वपूर्ण बिंदुओं के बारे में अधिक।

नेटवर्क कार्ड PCI वीआईडी: पीआईडी ​​0x8086: 0x4D45। आश्चर्यचकित न हों कि VID इंटेल से मेल खाती है, MCST अक्सर इस विशेष VID का उपयोग करता है, कम से कम ऊपर उल्लिखित सीरियल पोर्ट डिवाइस को देखें।

BAR0 में एक रजिस्टर आधार होता है। रजिस्टर इस प्रकार हैं:

 #define L_E1000_E_CSR 0x00 /* Ethernet Control/Status Register */ #define L_E1000_MGIO_CSR 0x04 /* MGIO Control/Status Register */ #define L_E1000_MGIO_DATA 0x08 /* MGIO Data Register */ #define L_E1000_E_BASE_ADDR 0x0c /* EthernetBase Address Register */ #define L_E1000_DMA_BASE_ADDR 0x10 /* DMA Base Address Register */ #define L_E1000_PSF_CSR 0x14 /* Pause Frame Control/Status Register */ #define L_E1000_PSF_DATA 0x18 /* Pause Frame Data Register */ #define L_E1000_INT_DELAY 0x1c /* Interrupt Delay Register */ 

अंतिम तीन (L_E1000_PSF_CSR, L_E1000_PSF_DATA, L_E1000_INT_DELAY) हमने उपयोग नहीं किए, इसलिए हम उनके बारे में बात नहीं करेंगे। चलो एमजीआईओ के साथ शुरू करते हैं, सब कुछ सरल है: एमआईआई प्रोटोकॉल का उपयोग करते हुए पढ़ा-लिखें, अर्थात, पीएचवाई चिप के साथ संचार। विशेष रूप से, हमारे पास एक चिप DP83865 है।

प्रक्रियाएं विशेष रूप से उल्लेखनीय नहीं हैं, मैं बस उन्हें सूचीबद्ध करूंगा।

पढ़ने:

 static int e1000_mii_readreg(struct net_device *dev, int phy_id, int reg_num) { struct l_e1000_priv *ep = netdev_priv(dev); uint32_t rd; uint16_t val_out = 0; int i = 0; rd = 0; rd |= 0x2 << MGIO_CS_OFF; rd |= 0x1 << MGIO_ST_OF_F_OFF; rd |= 0x2 << MGIO_OP_CODE_OFF; /* Read */ rd |= (phy_id & 0x1f) << MGIO_PHY_AD_OFF; rd |= (reg_num & 0x1f) << MGIO_REG_AD_OFF; e1000_write_mgio_data(ep, rd); rd = 0; for (i = 0; i != 1000; i++) { if (e1000_read_mgio_csr(ep) & MGIO_CSR_RRDY) { rd = (uint16_t)e1000_read_mgio_data(ep); val_out = rd & 0xffff; log_debug("reg 0x%x >>> 0x%x", reg_num, val_out); return val_out; } usleep(100); } log_error("mdio_read: Unable to read from MGIO_DATA reg\n"); return val_out; } 

रिकॉर्ड:

 static void e1000_mii_writereg(struct net_device *dev, int phy_id, int reg_num, int val) { struct l_e1000_priv *ep = netdev_priv(dev); uint32_t wr; int i = 0; wr = 0; wr |= 0x2 << MGIO_CS_OFF; wr |= 0x1 << MGIO_ST_OF_F_OFF; wr |= 0x1 << MGIO_OP_CODE_OFF; /* Write */ wr |= (phy_id & 0x1f) << MGIO_PHY_AD_OFF; wr |= (reg_num & 0x1f) << MGIO_REG_AD_OFF; wr |= val & 0xffff; log_debug("reg 0x%x <<< 0x%x", reg_num, val); e1000_write_mgio_data(ep, wr); for (i = 0; i != 1000; i++) { if (e1000_read_mgio_csr(ep) & MGIO_CSR_RRDY) { return; } usleep(100); } log_error("Unable to write MGIO_DATA reg: val = 0x%x", wr); return; } 

अब L_E1000_DMA_BASE_ADDR और L_E1000_E_BASE_ADDR, वास्तव में वे एक पैरामीटर, नेटवर्क कार्ड विवरण ब्लॉक का पता बताते हैं। यही है, एल्ब्रस में पता 64-बिट है, और रजिस्टर 32-बिट हैं।

वास्तव में कोड:

  /* low 32 bits */ init_block_addr_part = (uint32_t)((uintptr_t)ep->init_block & 0xffffffff); e1000_write_e_base_addr(ep, init_block_addr_part); log_debug("Init Block Low DMA addr: 0x%x", init_block_addr_part); /* high 32 bits */ init_block_addr_part = (uint32_t)(((uintptr_t)(ep->init_block) >> 32) & 0xffffffff); e1000_write_dma_base_addr(ep, init_block_addr_part); log_debug("Init Block High DMA addr: 0x%x", init_block_addr_part); /************************************************************************/ 

जिससे यह देखा जा सकता है कि L_E1000_DMA_BASE_ADDR ऊपरी भाग है, और L_E1000_DMA_BASE_ADDR एक निश्चित आरंभीकरण खंड (वास्तव में एक मानचित्र विवरण ब्लॉक) के पते का निचला भाग है।

विवरण संरचना इस प्रकार है:

 struct l_e1000_init_block { uint16_t mode; uint8_t paddr[6]; uint64_t laddrf; /* 31:4 = addr of rx desc ring (16 bytes align) + * 3:0 = number of descriptors (the power of two) * 0x09 is max value (desc number = 512 if [3:0] >= 0x09) */ uint32_t rdra; /* 31:4 = addr of tx desc ring (16 bytes align) + * 3:0 = number of descriptors (the power of two) * 0x09 is max value (desc number = 512 if [3:0] >= 0x09) */ uint32_t tdra; } __attribute__((packed)); 

सी लड्डू - समझ में नहीं आया, किसी कारण से इसे शून्य पर रखा जाता है, हमने ऐसा ही किया।

पैड्र - जैसा कि आप अनुमान लगा सकते हैं, मैक नेटवर्क कार्ड का पता है।

rdra और tdra में मेमोरी डिस्क्रिप्टर के छल्ले के पते होते हैं, निचले 4 बिट्स को रिंग के आकार में आवंटित किया जाता है, और यह आकार का लघुगणक होता है। यही है, अगर 8 है, तो रिंग में वर्णनकर्ताओं की संख्या 2 ^ 8 (1 << 8 == 256) होगी।

मोड कार्ड के संचालन का तरीका है, बिट्स इस प्रकार हैं:

 #define DRX (1 << 0) /* Receiver disable */ #define DTX (1 << 1) /* Transmitter disable */ #define LOOP (1 << 2) /* loopback */ #define DTCR (1 << 3) /* disable transmit crc */ #define COLL (1 << 4) /* force collision */ #define DRTY (1 << 5) /* disable retry */ #define INTL (1 << 6) /* Internal loopback */ #define EMBA (1 << 7) /* enable modified back-off algorithm */ #define EJMF (1 << 8) /* enable jambo frame */ #define EPSF (1 << 9) /* enable pause frame */ #define FULL (1 << 10) /* full packet mode */ #define PROM (1 << 15) /* promiscuous mode */ 

यही है, जब सब कुछ कॉन्फ़िगर किया गया है, तो आपको बिट 10 सेट करने की आवश्यकता है। यदि आप एक उचित मोड चाहते हैं, तो 15 भी।

पैकेट विवरणक


अब पैकेट विवरणकों के प्रारूप के बारे में।

स्वागत समारोह में:

 struct l_e1000_rx_desc { uint32_t base; int16_t buf_length; int16_t status; int16_t msg_length; uint16_t reserved1; uint32_t etmr; } __attribute__((packed)); 

आधार - शायद समझते हैं कि यह पैकेट के लिए बफर का पता है
buf_length - बफर आकार
msg_length - प्राप्त करने के बाद, प्राप्त पैकेट की लंबाई होती है
स्टेटस - डिस्क्रिप्टर स्टेटस। जब पैकेट तैयार किया जाता है और डीएमए (कार्ड) को दिया जाता है, तो आपको बिट 15 (RD_OWN) सेट करना होगा। यदि सब कुछ ठीक है, तो इस डिस्क्रिप्टर में पैकेट प्राप्त करने के बाद, यह बिट रीसेट हो जाएगा और 9 (RD_STP) और 8 (RD_ENP) सेट हो जाएगा।

सभी स्थिति बिट्स इस प्रकार हैं:

 /* RX Descriptor status bits */ #define RD_OWN (1 << 15) #define RD_ERR (1 << 14) #define RD_FRAM (1 << 13) #define RD_OFLO (1 << 12) #define RD_CRC (1 << 11) #define RD_BUFF (1 << 10) #define RD_STP (1 << 9) #define RD_ENP (1 << 8) #define RD_PAM (1 << 6) #define RD_LAFM (1 << 4) #define RD_BAM (1 << 3) 

स्थानांतरण पर:

 struct l_e1000_tx_desc { uint32_t base; int16_t buf_length; int16_t status; uint32_t misc; uint32_t etmr; } __attribute__((packed)); 

प्राप्त करने के लगभग समान ही, स्थिति बिट्स इस प्रकार हैं:

 /* TX Descriptor status bits */ #define TD_OWN (1 << 15) #define TD_ERR (1 << 14) #define TD_AFCS (1 << 13) #define TD_NOINTR (1 << 13) #define TD_MORE (1 << 12) #define TD_ONE (1 << 11) #define TD_DEF (1 << 10) #define TD_STP (1 << 9) #define TD_ENP (1 << 8) 

जब एक पैकेट भेजा जाता है, तो उसके अनुसार 15 (TD_OWN), 9 (TD_STP) और 8 (TD_ENP) सेट करना आवश्यक है। बिट 8 का अर्थ है कि यह संसाधित होने वाला अंतिम पैकेट है, इसलिए, यदि कोई पैकेट भेजा जाता है, तो आपको केवल पिछले एक में स्थापित करने की आवश्यकता है।

मैं एक महत्वपूर्ण विशेषता भी भूल गया, विवरणों में बफर की लंबाई माइनस साइन के साथ लिखी गई है, शायद अतिरिक्त कोड में। यहां तक ​​कि छोटे-एंडियन में भी, लेकिन चूंकि एल्ब्रस के पास एक ही बाइट क्रम है, इसलिए यह संभवतः महत्वपूर्ण नहीं है।

प्रबंधन रजिस्टर


अब हम अंतिम बिना पंजीकृत रजिस्टर L_E1000_E_CSR का वर्णन करते हैं:

 /* E_CSR register bits */ /* 31:21 unused, readed as 0 */ #define E_CSR_ATME (1 << 24) /* RW, Add Timer Enable */ #define E_CSR_TMCE (1 << 23) /* RW, Timer Clear Enable */ #define E_CSR_DRIN (1 << 22) /* RW, Disable RX Interrupt */ #define E_CSR_DTIN (1 << 21) /* RW, Disable TX Interrupt */ #define E_CSR_ESLE (1 << 20) /* RW, Enable Slave Error */ #define E_CSR_SLVE (1 << 19) /* RW1c, Slave Error */ #define E_CSR_PSFI (1 << 18) /* RW1c, Pause Frame Interrupt */ /* 17 unused, read as 0 */ #define E_CSR_SINT (1 << 16) /* R, Status Interrupt */ #define E_CSR_ERR (1 << 15) /* R, Error */ #define E_CSR_BABL (1 << 14) /* RW1c, Babble */ #define E_CSR_CERR (1 << 13) /* RW1c, Collision Error */ #define E_CSR_MISS (1 << 12) /* RW1c, Missed Packet */ #define E_CSR_MERR (1 << 11) /* RW1c, Memory Error */ #define E_CSR_RINT (1 << 10) /* RW1c, Receiver Interrupt */ #define E_CSR_TINT (1 << 9) /* RW1c, Transmiter Interrupt */ #define E_CSR_IDON (1 << 8) /* RW1c, Initialization Done */ #define E_CSR_INTR (1 << 7) /* R, Interrupt Flag */ #define E_CSR_INEA (1 << 6) /* RW, Interrupt Enable */ #define E_CSR_RXON (1 << 5) /* R, Receiver On */ #define E_CSR_TXON (1 << 4) /* R, Transmiter On */ #define E_CSR_TDMD (1 << 3) /* RW1, Transmit Demand */ #define E_CSR_STOP (1 << 2) /* RW1, Stop */ #define E_CSR_STRT (1 << 1) /* RW1, Start */ #define E_CSR_INIT (1 << 0) /* RW1, Initialize */ 

प्रारंभ


कुछ हद तक असामान्य प्रारंभिक अनुक्रम है:
STOP-> INIT-> IDON-> STRT

इस मामले में, RXON और TXON बिट स्वतंत्र रूप से उठते हैं।
अधिक जानकारी हमारे ड्राइवर में पाई जा सकती है।

वीडियो कार्ड


जैसा कि पहले ही उल्लेख किया गया है, हमारा डिवाइस सिलिकॉन मोशन विदाह का उपयोग करता है जिसे SM718 लिंक्स + कहा जाता है। इसलिए, सब कुछ सरल है, लिनक्स में ड्राइवर स्रोत हैं और वास्तव में वर्णन करने के लिए कुछ भी नहीं है।

खैर, सिवाय इसके कि वीडियो से पता चलता है कि यह बहुत कम एफपीएस निकला, यह स्मृति की धीमी पहुंच जैसा लगता है। लेकिन यह संकलक अनुकूलन के बिना है, और सामान्य तौर पर, शायद यह हमारी समस्या है जो ई 2 के आर्किटेक्चर के गलत उपयोग से जुड़ी है।

वैसे, सखालिन एल्ब्रस के बारे में और क्या कहना है?


सिद्धांत रूप में, मौसम सामान्य है :)

जाहिर है, एल्ब्रस मौजूद हैं, काम करते हैं। व्यक्तिगत रूप से, मैं इस दिलचस्प वास्तुकला के विकास की मुख्य समस्या को इसकी निकटता के रूप में देखता हूं। यह विश्वास करना कठिन है कि एक अपेक्षाकृत छोटी कंपनी एक प्रोसेसर, एक कंपाइलर, समर्थन और बाकी सब कुछ प्रदान कर सकती है। हां, थर्ड-पार्टी सॉफ्टवेयर डेवलपर्स दिखाई देने लगे, वही बेसाल्ट-एसपीओ एल्ट-लिनक्स का समर्थन करता है , जिसे एल्ब्रस पर स्थापित किया जा सकता है

हां, ऐसी रिपोर्टें थीं कि थर्ड-पार्टी डेवलपर्स Elbrus प्रोसेसर पर आधारित हार्डवेयर बना रहे हैं, उदाहरण के लिए Fastwel । लेकिन ये सब खुलेपन की दिशा में केवल छोटे-छोटे अग्रिम हैं। एक बहुत ही सरल उदाहरण, जो हमने कहा है और यहां दिखाया गया है, उसे पुन: प्रस्तुत करने के लिए, हमें एक कंपाइलर की आवश्यकता है, और केवल एमसीटीएस के पास है , लेख में दी गई जानकारी, फिर से, एमसीएसटी से प्राप्त जानकारी के अतिरिक्त है, और मैं अभी भी नहीं कहूंगा एमसीटी पर भी लोहे का एक टुकड़ा मिलने की संभावना नहीं है। यह काफी पुराना है, और ICST नए मॉडल पेश करता है।

PS स्वाभाविक रूप से, आप Embox रिपॉजिटरी में सब कुछ देख सकते हैं।

PPS रूसी टेलीग्राम चैनल पर Embox ( https://t.me/embox_chat ) के माध्यम से आएं।

PPS Embox ने संस्करण में दूसरा घटक अपडेट किया है, जो वर्तमान 0.4.0 है

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


All Articles