Embox pada prosesor Elbrus. Atau jangan pernah melupakan kecerdasan Anda

Artikel ini adalah kesimpulan logis untuk serangkaian artikel "mendaki Elbrus" tentang memperkenalkan arsitektur prosesor Embox ke Elbrus (E2K) . Mengapa kesimpulan logis, karena sebagai hasilnya, dimungkinkan untuk menjalankan melalui telnet aplikasi yang menampilkan gambar di layar, yaitu, untuk mencapai kerja penuh Embox pada arsitektur ini. Penelitian lebih lanjut hampir tidak bisa disebut pengantar, meskipun tentu saja, masih banyak yang tidak jelas. Dan arsitekturnya sendiri memiliki banyak fitur menarik, yang saat ini juga belum dipahami. Pada artikel ini, kita akan berbicara tentang mengatur memori virtual, mari kita menyentuh PCI, berbicara sedikit tentang kartu jaringan dan menyentuh kartu video pada perangkat keras tertentu yang kita miliki.

Bagi yang terlalu malas membaca artikel, saya akan langsung memberikan video pendek dengan hasilnya.


Dan sekarang bagi mereka yang tertarik, kami akan mengungkapkan detail teknis yang kami dapat mengerti dalam proses.

Memori virtual


Kesalahan tumpukan kami


Mari kita mulai dengan memori virtual. Sebenarnya, inilah yang kami selesaikan di artikel sebelumnya dalam seri. Perlu segera diingat mengapa kami membutuhkan memori virtual, karena Embox dapat bekerja tanpanya. Sederhana: masalahnya adalah caching. Vidyaha bekerja, tetapi saya harus merekam hal yang sama dua kali dalam memori video untuk pengambilan gambar yang andal. Tentu saja, itu mungkin untuk menangani cache, tetapi contoh kami melibatkan penggunaan memori video langsung dari aplikasi pengguna, tanpa hal-hal nuklir seperti manajemen cache, jadi itu benar untuk belajar bagaimana memetakan memori sebagai non-cacheable. Hal yang sama dapat dilakukan di Linux dengan memetakan fb ( contoh ).

Perlu dicatat bahwa meskipun kami tidak menulis tentang Elbrus untuk waktu yang lama dan mungkin terlihat bahwa MMU dalam arsitektur ini adalah jenis yang sangat rumit, tetapi masalahnya berbeda. Bahkan, kami menambahkan dukungan di musim panas, kami sama sekali tidak mencapai tangan kami untuk menulis tentang hal itu. Waktu yang lama (beberapa bulan) dihabiskan karena kesalahan bodoh kami. Kesalahan ini bahkan dibuat dalam judul artikel ("Atau tidak pernah melupakan apa yang Anda dapatkan selama intelijen"). Kita berbicara tentang tumpukan dengan mana kita berurusan dengan cukup baik dan menggambarkan ini dalam artikel Climbing Elbrus - Reconnaissance. Bagian Teknis 1. Register, tumpukan dan detail teknis lainnya . " Kami menderita untuk waktu yang sangat lama, dengan bodohnya kehilangan fakta bahwa kami mengambil tumpukan awal (di mana sistem diinisialisasi) dari suatu tempat di luar, dan memetakan semuanya. apa yang kami butuhkan agar Embox berfungsi, kami tidak memetakan data ini.

Di bawah kucing, saya akan memberikan fungsi baru e2k_entry, yang dijelaskan dalam artikel kedua di artikel dalam seri .

Jika diinginkan, Anda dapat membandingkan.

__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]); } 

Saya hanya akan menjelaskan bahwa sekarang kita menggunakan fungsi context_init () dan context_switch () hanya untuk mengalihkan stack ke memori di ruang Embox. Dan kami melakukan ini untuk semua core, termasuk yang tidak digunakan.

Organisasi MMU


Sekarang saya akan berbicara sedikit tentang organisasi MMU dalam arsitektur E2k.

Secara umum, arsitektur MMU cukup biasa dan memiliki tabel empat tingkat (atau tiga saat menggunakan halaman 4MB).

Ada beberapa register layanan dalam arsitektur E2k, mereka diakses menggunakan perintah akses ke ruang alternatif, serta ke ruang I / O yang dijelaskan secara singkat dalam artikel "Embox mulai mendaki Elbrus" .

Kami akan membutuhkan register tersebut:

 #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 *// 

Sebenarnya, ini adalah register kontrol, register nomor konteks, daftar root tabel, dan MMU_REG_ELB_PTB sedikit tidak jelas. Mari kita mulai dengan itu, register ini harus diatur ke beberapa nilai, 512GB berikutnya akan digunakan oleh prosesor untuk kebutuhan peralatan, dan alamat ini tidak akan tersedia untuk programmer. Saya akan memberikan penjelasan dari surat spesialis ICST, saya hampir tidak bisa menjelaskan lebih baik:

Di Linux, kami mengatur MMU_ELB_PTB ke 0xff1 << 39, lalu
memori virtual bagian atas (0xff8000000000 - 0xffffffffffff)
dicadangkan untuk kebutuhan peralatan, yaitu, TLB. Setiap halaman
tabel halaman (TS) mendapatkan alamat uniknya di area ini,
selain itu, alamat-alamat ini mudah diperoleh dari alamat di mana program tersebut
menarik ke memori. Dan sejak itu TLB menyimpan pemetaan alamat virtual
fisik, ini memungkinkan Anda untuk cache di buffer TLB yang sama
siaran tidak hanya untuk alamat pengguna, tetapi juga untuk kendaraan itu sendiri.

Dalam prosesor / arsitektur di mana TLB terpisah dibuat untuk berbeda
tingkat tabel halaman, trik seperti itu menjadi tidak perlu.

Jadi, ketika Anda melewatkan TLB, menjadi mungkin untuk tidak memulai pencarian
dari level nol (pgd *), dan segera periksa level terakhir kendaraan (pte *).
Tidak ada persyaratan perangkat keras untuk memetakan area ini sendiri, Wirth. alamat dari
itu diperlukan hanya sebagai indeks untuk pencarian TLB. Namun, pada intinya
pgd terakhir di level nol dari tabel halaman ditulis nat. alamat ini
tingkat paling nol. Akibatnya, hanya
4 KB terakhir dari area ff80'0000'0000 - ffff'ffff'ffff - i.e. tepat
tingkat kendaraan nol. Ini memungkinkan pgd * diakses secara biasa
baca / tulis instruksi yang bekerja di alamat virtual.

Alhasil, diputuskan untuk sekadar memasukkan nilai yang besar di register ini, yang tidak akan mengganggu kami. Bagaimanapun, solusi yang diusulkan memungkinkan kami untuk mengoptimalkan pencarian halaman, tetapi kami belum terlibat dalam optimasi. Disampaikan sama seperti di Linux.

Sekarang register kontrol. Anda perlu mengaktifkan MMU melalui itu. Bit yang dikenal terlihat seperti ini:

 #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 */ 

Kami tertarik pada bit pertama, yang mencakup terjemahan alamat.

Kami juga menetapkan _MMU_CR_SET3, tetapi kami belum menemukan kasus tertentu yang harus dilakukan.

Daftar Kontes Nah, jika sederhana, maka ini adalah PID dari proses atau ruang alamat. Lebih teknis, ini adalah ekstensi alamat 11-bit. Dalam kasus kami, kami membuat semua halaman menjadi nuklir, dengan menetapkan sedikit globalitas di semua halaman kami, kami menggunakan ruang alamat yang sama dan oleh karena itu kami dapat menggunakan nol dalam register ini.

Dalam register tabel root adalah pointer ke alamat fisik dari awal tabel terjemahan. Anda bisa saja melakukan penipuan dengan memetakan tabel juga ke alamat yang ditentukan dalam register MMU_REG_ELB_PTB, tetapi seperti yang saya katakan, kami tidak fokus pada optimasi.

Apa lagi yang bisa saya katakan, struktur tabelnya cukup biasa, benderanya adalah sebagai berikut:

 #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 */ 

Untuk tabel 4 tingkat, shift alamat adalah sebagai berikut:

 #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 */ 

Sedikit tentang PCI


Komunikasi melalui ruang alamat alternatif


Sebelum beralih ke vidyaha dan kartu jaringan, mari kita kembali ke PCI. Kami sudah berbicara sedikit tentang ini di bagian pertama "Embox mulai mendaki Gunung Elbrus . " Itu menunjukkan makro untuk berkomunikasi dengan ruang alamat alternatif:

 #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"); \ }) 

Dan ada referensi pada prinsip ruang alamat. Ruang alamat yang berbeda didefinisikan menggunakan MAS (penentu alamat memori). Dan misalnya, untuk mengakses IO, melalui mana PCI diakses, Anda harus menggunakan 6, dan untuk MMU 7.

Tetapi dengan studi makro yang lebih menyeluruh, Anda dapat melihat beberapa jenis chan_letter. Dan jika Anda melihat deskripsi perintah e2k, kami menemukan
LDD ddd membaca kata ganda
ldd [address] mas, dst

Artinya, pada pandangan pertama, tidak ada saluran. Tetapi jika Anda mengikuti tautan, ternyata kode untuk ldd operasi yang diberikan adalah 67. Namun 67 adalah kode untuk ldd hanya untuk saluran AL0 / AL3 dan AL2 / AL5, dan untuk saluran AL1 / AL4 kode ini sesuai dengan operasi POPCNTd.

Jadi, tidak mungkin untuk sepenuhnya memahami saluran apa yang ada dalam terminologi Elbrus. Saya berani menyarankan bahwa ini sudah terhubung dengan prinsip vliw, ketika Anda dapat menentukan alu mana yang digunakan, karena dalam jenis arsitektur ini salah satu fitur adalah kehadiran beberapa perangkat komputasi independen. Saya bisa, tentu saja, salah, tetapi kenyataannya adalah bahwa untuk mengakses PCI atau MMU Anda perlu menggunakan saluran kedua atau kelima. Dengan demikian, perintahnya akan terlihat seperti ini:
ldd, 2 0x0, [addr_in_mas] mas_id,% reg

lspci


Sekarang saya akan memberikan hasil dari output perintah lspci pada perangkat yang kita miliki:
root @ embox: (null) #lspci
00: 0,0 (PCI dev E3E3: ABCD) [6 4]
Jembatan PCI-ke-PCI: (null) Jembatan Elbrus PCIe (rev 01)
00: 1.0 (PCI dev 8086: E3E3) [6 4]
Jembatan PCI-ke-PCI: Jembatan Intel Intel Elbrus Virt PCI (rev 01)
01: 0.0 (PCI dev 1FFF: 8000) [6 4]
Jembatan PCI-ke-PCI: (null) Jembatan PCI Elbrus (rev 05)
01: 1.0 (PCI dev 8086: 4D45) [2 0]
Pengontrol Ethernet: Intel Corporation MCST ETH1000 Gigabit Ethernet (rev 01)
01: 2.0 (PCI dev 8086: 4D49) [1 1]
Pengontrol IDE: Intel Corporation MCST IDE (rev 128)
01: 2.1 (PCI dev 8086: 0002) [7 2]
Comm sederhana. controller: Intel Corporation (null) (rev 05)
01: 2.2 (PCI dev 8086: 8000) [7 128]
Comm sederhana. controller: Intel Corporation Elbrus PCI bridge (rev 00)
01: 2.3 (PCI dev 1013: 6005) [4 1]
Perangkat multimedia: Cirrus Logic Crystal CS4281 PCI Audio (rev 01)
01: 3.0 (PCI dev 8086: 4748) [1 6]
Pengontrol penyimpanan massal: Intel Corporation MCST SATA (rev 00)
01: 4.0 (PCI dev 8086: 554F) [12 3]
Perangkat USB: Intel Corporation OHCI untuk Elbrus (rev 00)
01: 4.1 (PCI dev 8086: 5545) [12 3]
Perangkat USB: Intel Corporation EHCI untuk Elbrus (rev 00)
02: 1.0 (PCI dev 126F: 0718) [3 0]
Pengontrol yang kompatibel dengan VGA: Silicon Motion, Inc. SM718 LynxSE + (rev 160)
root @ embox: (null) #

Catatan
01: 2.2 (PCI dev 8086: 8000) [7 128]
Comm sederhana. controller: Intel Corporation Elbrus PCI bridge (rev 00)

Bahkan, itu adalah port serial dari MCST mirip dengan am85c30, setidaknya melalui perangkat ini kami berkomunikasi melalui minicom.

Kartu jaringan


Struktur umum


Sekarang mari kita ke kartu jaringan.

Jika saya mengerti dengan benar, maka ini adalah kartu jaringan asli, sedikit mirip dalam operasi dengan e1000, tetapi hanya dalam operasi (seperti keberadaan deskriptor dalam antrian terima dan kirim).

Sekarang lebih lanjut tentang poin penting yang kami temui.

Kartu Jaringan PCI VID: PID 0x8086: 0x4D45. Jangan kaget bahwa VID sama dengan Intel, MCST sering menggunakan VID khusus ini, lihat setidaknya pada perangkat port serial yang disebutkan di atas.

BAR0 berisi basis register. Register adalah sebagai berikut:

 #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 */ 

Tiga yang terakhir (L_E1000_PSF_CSR, L_E1000_PSF_DATA, L_E1000_INT_DELAY) tidak kami gunakan, jadi kami tidak akan membicarakannya. Mari kita mulai dengan MGIO, semuanya sederhana: baca-tulis menggunakan protokol MII, yaitu komunikasi dengan chip PHY. Secara khusus, kami memiliki chip DP83865.

Prosedurnya tidak terlalu luar biasa, saya hanya akan daftar mereka.

Membaca:

 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; } 

Rekam:

 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; } 

Sekarang L_E1000_DMA_BASE_ADDR dan L_E1000_E_BASE_ADDR, sebenarnya mereka menggambarkan satu parameter, alamat blok deskripsi kartu jaringan. Yaitu, alamat di Elbrus adalah 64-bit, dan registernya 32-bit.

Sebenarnya kode:

  /* 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); /************************************************************************/ 

Dari mana dapat dilihat bahwa L_E1000_DMA_BASE_ADDR adalah bagian atas, dan L_E1000_DMA_BASE_ADDR adalah bagian bawah dari alamat blok inisialisasi tertentu (sebenarnya blok deskripsi peta).

Struktur deskripsi adalah sebagai berikut:

 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)); 

C laddrf - tidak mengerti, untuk beberapa alasan itu dimasukkan ke nol, kami melakukan hal yang sama.

paddr - seperti yang Anda duga, mac adalah alamat kartu jaringan.

rdra dan tdra berisi alamat cincin deskriptor memori, 4 bit lebih rendah dialokasikan ke ukuran cincin, dan ini adalah logaritma ukuran. Artinya, jika ada 8, maka jumlah deskriptor di atas ring adalah 2 ^ 8 (1 << 8 == 256).

mode adalah mode operasi kartu, bit adalah sebagai berikut:

 #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 */ 

Artinya, ketika semuanya sudah dikonfigurasi, Anda perlu mengatur bit 10. Jika Anda ingin mode promiscuous, maka juga 15.

Deskriptor paket


Sekarang tentang format deskriptor paket.

Di resepsi:

 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)); 

base - mungkin mengerti bahwa ini adalah alamat buffer untuk paket
buf_length - ukuran buffer
msg_length - setelah menerima, berisi panjang paket yang diterima
status - status deskriptor. Ketika paket disiapkan dan diberikan ke DMA (kartu), Anda perlu mengatur bit 15 (RD_OWN). Jika semuanya baik-baik saja, maka setelah menerima paket dalam deskriptor ini, bit ini akan direset dan 9 (RD_STP) dan 8 (RD_ENP) akan ditetapkan.

Semua bit status adalah sebagai berikut:

 /* 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) 

Saat transfer:

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

Hampir sama dengan menerima, bit status adalah sebagai berikut:

 /* 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) 

Ketika sebuah paket dikirim, perlu untuk mengatur 15 (TD_OWN), 9 (TD_STP) dan 8 (TD_ENP) sesuai. Bit 8 berarti bahwa ini adalah paket terakhir yang akan diproses, oleh karena itu, jika suatu paket dikirimkan, maka Anda hanya perlu menginstal yang terakhir.

Saya juga lupa fitur penting, panjang buffer dalam deskriptor ditulis dengan tanda minus, mungkin dalam kode tambahan. Bahkan dalam little-endian, tetapi karena Elbrus memiliki urutan byte yang sama, ini mungkin tidak penting.

Daftar manajemen


Sekarang kami jelaskan daftar L_E1000_E_CSR yang belum dirangkai terakhir:

 /* 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 */ 

Inisialisasi


Ada urutan inisialisasi yang agak tidak biasa:
STOP-> INIT-> IDON-> STRT

Dalam hal ini, bit RXON & TXON naik secara independen.
Rincian lebih lanjut dapat ditemukan di driver kami.

Kartu video


Seperti yang telah disebutkan, perangkat kami menggunakan vidyah Silicon Motion yang disebut SM718 LynxSE +. Oleh karena itu, semuanya sederhana, ada sumber driver di Linux dan tidak ada yang bisa dijelaskan sebenarnya.

Yah, kecuali bahwa video menunjukkan bahwa ternyata fps sangat rendah, rasanya seperti akses lambat ke memori. Tapi ini tanpa optimasi kompiler, dan secara umum, mungkin ini adalah masalah kita yang terkait dengan penggunaan arsitektur e2k yang salah.

Nah, apa lagi yang harus dikatakan tentang Sakhalin Elbrus?


Pada prinsipnya, cuacanya normal :)

Rupanya, Elbrus ada, bekerja. Secara pribadi, saya melihat masalah utama pengembangan arsitektur yang menarik ini sebagai kedekatannya. Sulit dipercaya bahwa perusahaan yang relatif kecil dapat membuat prosesor, kompiler, memberikan dukungan, dan yang lainnya. Ya, pengembang perangkat lunak pihak ketiga mulai muncul, Basalt-SPO yang sama mendukung Alt-Linux, yang dapat diinstal pada Elbrus .

Ya, ada laporan bahwa pengembang pihak ketiga membuat perangkat keras berdasarkan prosesor Elbrus, misalnya Fastwel . Tetapi semua ini hanyalah kemajuan kecil menuju keterbukaan. Contoh yang sangat sederhana, untuk mereproduksi apa yang telah kami katakan dan perlihatkan di sini, kami memerlukan kompiler, dan hanya MCST yang memilikinya , informasi yang diberikan dalam artikel adalah tambahan untuk informasi yang diterima dari, sekali lagi, MCST , dan saya masih belum mengatakan bahwa sepotong besi tidak mungkin ditemukan bahkan di MCST. Cukup lama, dan ICST menawarkan model yang lebih baru.

PS Secara alami, Anda dapat melihat semua yang ada di repositori Embox .

PPS Datang ke saluran telegram Rusia melalui Embox ( https://t.me/embox_chat ).

PPS Embox telah memperbarui komponen kedua dalam versi, sekarang 0.4.0 saat ini

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


All Articles