1/* 2 *Copyright (c) 2007-2011, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <barrelfish/barrelfish.h> 15 16#include "sfn5122f.h" 17#include "mcdi_rpc.h" 18#include "sfn5122f_debug.h" 19 20static uint32_t seqno = 0; 21 22static struct thread_mutex mcdi; 23 24void init_mcdi_mutex(void) 25{ 26 thread_mutex_init(&mcdi); 27} 28 29 30/* Function to issue MCDI calls 31 ***************************************************************** 32 * Each MCDI request starts with an MCDI_HEADER, which is a 32byte 33 * structure, filled in by the client. 34 * 35 * 0 7 8 16 20 22 23 24 31 36 * | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS | 37 * | | | 38 * | | \--- Response 39 * | \------- Error 40 * \------------------------------ Resync (always set) 41*/ 42 43errval_t mcdi_rpc(unsigned cmd, const uint8_t *in, uint32_t inlen, 44 uint8_t *out, uint32_t outlen, uint32_t *outlen_actual, 45 bool port, sfn5122f_t *d) 46{ 47 uint32_t rlen = 0; 48 uint32_t hdr = 0; 49 uint32_t reg = 0; 50 uint32_t offset = MCDI_PDU(port); 51 uint32_t offset2 = MCDI_DORBELL(port); 52 unsigned error; 53 uint32_t* pointer = (uint32_t*) in; 54 55 thread_mutex_lock(&mcdi); 56 57 seqno++; 58 59 // Code 60 hdr |= cmd; 61 // Resync 62 hdr |= 1 << 7; 63 // Len 64 hdr |= inlen << 8; 65 // SEQ 66 hdr |= seqno << 16; 67 68 // write command 69 sfn5122f_mc_treg_smem_wr(d,offset,hdr); 70 // write arguments 71 for (int i = 0; i < inlen/4; i++) { 72 sfn5122f_mc_treg_smem_wr(d, offset+1+i, (uint32_t) pointer[i]); 73 __sync_synchronize(); 74 } 75 76 // from driver 77 // ring dorbell with distinct value 78 offset2 = MCDI_DORBELL(port); 79 sfn5122f_mc_treg_smem_wr(d, offset2, 0x45789abc); 80 // Poll for completion 81 while(1){ 82 // TODO add backoff ? 83 reg = sfn5122f_mc_treg_smem_rd(d, offset); 84 // If the reg is 0xffffffff the memory resets 85 if (reg != 0xffffffff && ((reg >> 23) & 0x001)) 86 break; 87 } 88 89 error = (reg >> 22) & 0x001; 90 rlen = (reg >> 8) & 0x0FF; 91 92 if (cmd == CMD_REBOOT && error && !rlen) { 93 DEBUG("CARD REBOOTED \n"); 94 } else if(error && !(cmd == CMD_REBOOT)){ 95 // TODO ERROR HANDLING 96 reg = sfn5122f_mc_treg_smem_rd(d,offset+1); 97 DEBUG("AN ERROR OCCURRED: CMD %d, ERROR %d \n",cmd , reg); 98 switch(reg){ 99 case 4: 100 return NIC_ERR_INTR; 101 case 5: 102 return NIC_ERR_IO; 103 case 37: 104 return NIC_ERR_NOSYS; 105 default: 106 return NIC_ERR_UNKNOWN; 107 } 108 } 109 // read result 110 // outlen computation from driver 111 outlen = (outlen < rlen+3) ? outlen : rlen+3; 112 outlen = outlen & ~0x3; 113 114 if (outlen_actual != NULL) { 115 *outlen_actual = rlen; 116 } 117 118 memset(&out, outlen, 0); 119 120 for (int i = 0; i < outlen; i+=4 ){ 121 reg = sfn5122f_mc_treg_smem_rd(d, offset+1+i/4); 122 memcpy(out+i, ®, 4); 123 } 124 125 __sync_synchronize(); 126 thread_mutex_unlock(&mcdi); 127 return SYS_ERR_OK; 128} 129 130 131 132 133 134 135