/* * Copyright 2010 Stefan Lankes, Chair for Operating Systems, * RWTH Aachen University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR COND */ #include #include #include #include #include #include #include #ifdef CONFIG_ROCKCREEK #include #include #include #include #include #define IRQ_STATUS 0xD000 #define IRQ_MASK 0xD200 #define IRQ_RESET 0xD400 #define IRQ_REQUEST 0xD600 #define IRQ_CONFIG 0xD800 #include bootinfo_t* bootinfo = (bootinfo_t*) SCC_BOOTINFO; static int num_ues, my_ue; /* PSE bit for Pentium+ equals MPE (message buffer enable) flag in RCK! So, use it to create _PAGE_MPB symbol... */ #define _CR4_MPE 0x00000800 /* maximal number of SCC's cores */ #define MAX_SCC_CORES (NUM_ROWS*NUM_COLS*NUM_CORES) /* * This is the modified MPB program, which is part of the RCCE distribution (src/mpb.c). * * This function clears the local MPB and resets the test&set register. */ static int scc_clear(void) { int tmp, x, y, z, offset; // Initialize API InitAPI(0); // Find out who I am... tmp=ReadConfigReg(CRB_OWN+MYTILEID); x=(tmp>>3) & 0x0f; // bits 06:03 y=(tmp>>7) & 0x0f; // bits 10:07 z=(tmp ) & 0x07; // bits 02:00 // Allocate Message Passing Buffer t_vcharp MPB; MPBalloc(&MPB, x, y, z, 1); if (!MPB) { kprintf("Unable to allocate MPB for core %d of Tile x=%d, y= %d! Exiting.\n", z, x, y); return 255; } // zap own MPB for (offset=0; offset < 0x2000; offset+=8) *(volatile unsigned long long int*)(MPB+offset) = 0; // Clear test&set register write. Next read-access will read "1" (lock granted). SetConfigReg(CRB_ADDR(x,y)+((z)?LOCK1:LOCK0), 1); // frees Message Passing Buffer MPBunalloc(&MPB); return 0; } static void intr_handler(struct state *s) { // reset appropriate bit in the core configuration register int tmp, z; #ifdef CONFIG_LWIP mmnif_irqhandler(); #endif z = Z_PID(RC_COREID[my_ue]); tmp=ReadConfigReg(CRB_OWN + (z==0 ? GLCFG0 : GLCFG1)); tmp &= ~2; SetConfigReg(CRB_OWN + (z==0 ? GLCFG0 : GLCFG1), tmp); } int icc_init(void) { int i, z, tmp; uint64_t start, end, ticks, freq = 533; uint32_t cr4; kputs("Initialize Rock Creek!\n"); /* Enable Messagepassing in CR4 */ cr4 = read_cr4(); cr4 = cr4 | _CR4_MPE; write_cr4(cr4); kprintf("address of the initrd: 0x%x\n", bootinfo->addr); kprintf("size of the initrd: %d\n", bootinfo->size); kprintf("rcce argc = %d\n", bootinfo->argc); for(i=0; iargc; i++) kprintf("rcce argv[%d] = %s\n", i, bootinfo->argv[i]); if (bootinfo->argc >= 3) freq = atoi(bootinfo->argv[2]); kputs("Reset SCC!\n"); scc_clear(); kputs("Wait some time...\n"); mb(); start = rdtsc(); do { mb(); end = rdtsc(); ticks = end > start ? end - start : start - end; } while(ticks*TIMER_FREQ < 300ULL*freq*1000000ULL); if (RCCE_init(&bootinfo->argc, &bootinfo->argv) != RCCE_SUCCESS) return -ENODEV; if (iRCCE_init() != iRCCE_SUCCESS) return -ENODEV; // enable additional outputs RCCE_debug_set(RCCE_DEBUG_ALL); my_ue = RCCE_ue(); num_ues = RCCE_num_ues(); kprintf("Got rank %d of %d ranks\n", my_ue, num_ues); RCCE_barrier(&RCCE_COMM_WORLD); #if 0 kputs("RCCE test...\t"); if (my_ue == 0) msg = 0x4711; if (RCCE_bcast((char*) &msg, sizeof(msg), 0, RCCE_COMM_WORLD) == RCCE_SUCCESS) kprintf("successfull! (0x%x)\n", msg); else kprintf("failed! (0x%x)\n", msg); #endif #if 0 char* str = RCCE_shmalloc(128); if (my_ue == 1) { memset(str, 0x00, 128); strcpy(str, "Hello RCCE_shmalloc\n"); } RCCE_barrier(&RCCE_COMM_WORLD); kprintf("RCCE_shmalloc test: %s\n", str); RCCE_shfree(str); #endif // reset INTR/LINT0 flag z = Z_PID(RC_COREID[my_ue]); tmp=ReadConfigReg(CRB_OWN + (z==0 ? GLCFG0 : GLCFG1)); tmp &= ~2; SetConfigReg(CRB_OWN + (z==0 ? GLCFG0 : GLCFG1), tmp); // set interrupt handler (INTR/LINT0) irq_install_handler(124, intr_handler); // unmask interrupts volatile uint64_t* irq_mask = (volatile uint64_t*)(FPGA_BASE + IRQ_MASK + my_ue*8); *irq_mask &= 0; // reset interrupt reg volatile uint64_t* irq_reset = (volatile uint64_t*)(FPGA_BASE + IRQ_RESET + my_ue*8); *irq_reset = ~(0); // set remote interrupts to LINT 0 volatile int* irq_config = (volatile int*)(FPGA_BASE + IRQ_CONFIG + my_ue*4); *irq_config = 0; volatile int* irq_status = (volatile int*)(FPGA_BASE + IRQ_STATUS + my_ue*8); kprintf( "irq_mask = %x\n", *irq_mask ); kprintf( "irq_config = %x\n", *irq_config ); kprintf( "status_reg = %x\n", *irq_status ); kputs("Now, the SCC is initialized!\n"); return 0; } int icc_send_irq(int ue) { int tmp, x, y, z, addr; z = Z_PID(RC_COREID[ue]); x = X_PID(RC_COREID[ue]); y = Y_PID(RC_COREID[ue]); addr = CRB_ADDR(x,y) + (z==0 ? GLCFG0 : GLCFG1); // send interrupt to ue do { NOP1; tmp=ReadConfigReg(addr); } while(tmp & 2); tmp |= 2; SetConfigReg(addr, tmp); return 0; } int icc_halt(void) { icc_mail_check(0); NOP1; //HALT; return 0; } #define ROUNDS 1000 #define CORE_A 0 // sender #define CORE_B 1 // receiver int icc_send_gic_irq(int core_num) { volatile uint64_t* irq_request = (volatile uint64_t*)(FPGA_BASE+IRQ_REQUEST+my_ue*8); uint64_t bit_pos; // determine bit position and set according bit bit_pos = (1 << core_num); *irq_request = bit_pos; return 0; } int icc_irq_ping() { if( my_ue == 2 ) return -1 ; icc_send_gic_irq(2); kprintf( "my_ue = %d\n", my_ue ); kprintf( "sending irq to 1!\n"); return 0; } static inline void icc_mail_check_tag(iRCCE_MAIL_HEADER* mail) { char* recv_buffer; switch( mail->tag ) { case iRCCE_ANYLENGTH: recv_buffer = (char*)kmalloc( mail->size ); iRCCE_irecv(recv_buffer, mail->size, mail->source, NULL ); break; case PING_REQ: kprintf( "icc_mail_check_tag: ping_req\n" ); iRCCE_mail_send(0, PING_RESP, 0, NULL, mail->source); break; default: kprintf( "icc_mail_check_tag: uknown tag id %d\n", mail->tag ); break; } } int icc_mail_ping( void ) { uint32_t flags; uint64_t timer = 0; int i; int res; iRCCE_MAIL_HEADER* recv_header = NULL; /* leave function if not participating in pingpong */ if( (my_ue != CORE_A) && (my_ue != CORE_B) ) return -1; kprintf( "my_ue = %d\n", my_ue ); kprintf( "Hello from mail_ping ... \n" ); kprintf( "rounds = %d\n", ROUNDS ); // disable interrupts flags = irq_nested_disable(); for( i=0; isource == CORE_B ) break; iRCCE_mail_release(&recv_header); } } while( 1 ); /* release mail */ iRCCE_mail_release(&recv_header); } /* receivers part */ else { /* wait for request */ do { res = iRCCE_mail_recv(&recv_header); if( res == iRCCE_SUCCESS ) { if( recv_header->tag == PING_REQ ) break; iRCCE_mail_release(&recv_header); } } while( 1 ); /* send response */ iRCCE_mail_send(0, PING_RESP, 0, NULL, recv_header->source); /* release mail */ iRCCE_mail_release(&recv_header); } /* start timer in first round */ if( i == 0 ) timer = rdtsc(); } /* stop timer */ timer = rdtsc() - timer; if( my_ue == CORE_A ) { kprintf( "timer = %ld\n", timer ); kprintf( "mail_pingpong needs in average %d msec (%d ticks)!\n", timer/(2*ROUNDS*533), timer/(2*ROUNDS) ); } irq_nested_enable(flags); return 0; } int icc_mail_ping_irq( void ) { /* return if not core A */ if( my_ue != CORE_A ) return 0; uint32_t flags; uint64_t timer = 0; int rem_rank = CORE_B; int i; int res; iRCCE_MAIL_HEADER* recv_header = NULL; kprintf( "Hello from mail_ping_irq ... \n" ); kprintf( "my_rank = %d\n", my_ue ); kprintf( "rem_rank = %d\n", rem_rank ); kprintf( "rounds = %d\n", ROUNDS ); // disable interrupts flags = irq_nested_disable(); for( i=0; isource != rem_rank) && (recv_header->tag == PING_RESP) ); iRCCE_mail_release(&recv_header); /* start timer in first round */ if( i == 0 ) timer = rdtsc(); } /* stop timer */ timer = rdtsc() - timer; kprintf( "timer = %ld\n", timer ); kprintf( "mail_pingpong needs in average %d msec (%d ticks)!\n", timer/(2*ROUNDS*533), timer/(2*ROUNDS) ); irq_nested_enable(flags); return 0; } int icc_mail_noise() { int j, res; int num_ranks = RCCE_num_ues(); iRCCE_MAIL_HEADER* recv_mail = NULL; // leave function if not participating if( (my_ue == CORE_A) /*|| (my_ue == CORE_B)*/ ) { return -1; } kprintf( "Hello from icc_mail_noise: my_ue = %d\n", my_ue ); for( ;; ) { /* send a mail to each UE */ for( j=0; j>= 6; // shift emac bits for( source = 0; irq_status != 0; irq_status >>= 1, ++source ) { if( (irq_status & 0x1) != 0 ) { res = iRCCE_mail_check(source); } } /* reset status register */ irq_reset_reg = (volatile uint64_t*)(FPGA_BASE + IRQ_RESET + my_ue*8); *irq_reset_reg = ~(0); } else { iRCCE_mail_check(iRCCE_MAILBOX_ALL); } /* empty mail queue */ while( (res = iRCCE_mail_recv(&header)) == iRCCE_SUCCESS ) { icc_mail_check_tag(header); iRCCE_mail_release( &header ); } /* enable interrupts */ irq_nested_enable(flags); } #endif