dmac.c (8194B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * A simple DMA controller "server". This code responds to a DMA 8 * request to read or write a word of data into shared memory. 9 * 10 * The DMA controller is a simple task (Solaris Thread) which handles 11 * two types of requests: 12 * 13 * RPC_DMAC_READ: read data from memory 14 * RPC_DMAC_WRITE: write data to memory address 15 */ 16 17 #include <shared/bsl.h> 18 19 #include <sys/types.h> 20 #include <stdlib.h> 21 #include <unistd.h> 22 #include <string.h> 23 #include <signal.h> 24 #include <errno.h> 25 #include <netinet/in.h> 26 #include <sys/socket.h> 27 #include <stdio.h> 28 29 #ifdef VXWORKS 30 #include <vxWorks.h> 31 #include <sockLib.h> 32 #endif 33 34 #include <sal/appl/io.h> 35 #include <sal/core/thread.h> 36 #include <sal/core/sync.h> 37 #include <sal/appl/pci.h> 38 #include <soc/debug.h> 39 40 #include "verinet.h" 41 42 /* 43 * DMA memory routines. 44 * The routines below operate on memory which the CMIC onboard the 45 * Orion will read and write. Under the PLI simulator, these routines 46 * read and write shared memory. 47 */ 48 49 #define MAX_DMA_MEMORY (64*1024) 50 static uint32 kluge_dma_memory[MAX_DMA_MEMORY/sizeof(uint32)]; 51 52 static int 53 _dma_putw(uint32 addr, uint32 data) 54 { 55 sal_vaddr_t dma_addr = addr; 56 57 if (addr < MAX_DMA_MEMORY) { 58 dma_addr += PTR_TO_UINTPTR(kluge_dma_memory); 59 } 60 61 *((uint32 *)dma_addr) = data; 62 63 return(0); 64 } 65 66 static int 67 _dma_putb(uint32 addr, uint8 data) 68 { 69 sal_vaddr_t dma_addr = addr; 70 71 if (addr < MAX_DMA_MEMORY) { 72 dma_addr += PTR_TO_UINTPTR(kluge_dma_memory); 73 } 74 75 *((uint8 *)dma_addr) = data; 76 77 return(0); 78 } 79 80 static int 81 _dma_getw(uint32 addr) 82 { 83 sal_vaddr_t dma_addr = addr; 84 85 if (addr < MAX_DMA_MEMORY) { 86 dma_addr += PTR_TO_UINTPTR(kluge_dma_memory); 87 } 88 89 return *((uint32 *)dma_addr); 90 91 } 92 93 static int 94 _dma_getb(uint32 addr) 95 { 96 sal_vaddr_t dma_addr = addr; 97 98 if (addr < MAX_DMA_MEMORY) { 99 dma_addr += PTR_TO_UINTPTR(kluge_dma_memory); 100 } 101 102 return *((uint8 *)dma_addr); 103 } 104 105 /* 106 * Main thread of control. This worker thread will service requests 107 * on a socket, read or writing to memory based on the command 108 * dispatched from the main execution thread. 109 */ 110 void 111 dmac_handler(void *v_void) 112 { 113 verinet_t *v = (verinet_t *)v_void; 114 volatile int finished = 0; 115 volatile uint32 dmaAddr, dmaData; 116 rpc_cmd_t cmd; 117 int sockfd = v->dmacFd; 118 uint8 *byte_ptr; 119 uint32 i; 120 121 while (!finished){ 122 LOG_INFO(BSL_LS_SYS_VERINET, 123 (BSL_META("dmac_handler: wait...\n"))); 124 125 if (wait_command(sockfd, &cmd) < 0) { 126 break; /* Error message already printed */ 127 } 128 129 LOG_INFO(BSL_LS_SYS_VERINET, 130 (BSL_META("request opcode 0x%x\n"), 131 cmd.opcode)); 132 133 switch(cmd.opcode){ 134 case RPC_DMAC_READ_REQ: 135 /* Read DMA memory ... */ 136 dmaAddr = cmd.args[0]; 137 /* Read data from shared memory at Addr */ 138 dmaData = _dma_getw(dmaAddr); 139 LOG_INFO(BSL_LS_SYS_VERINET, 140 (BSL_META("**DMA_RD: 0x%x = 0x%x\n"), 141 dmaAddr, dmaData)); 142 /* Send back a response */ 143 make_rpc_getmem_resp(&cmd, dmaData); 144 write_command(sockfd, &cmd); 145 break; 146 147 case RPC_DMAC_WRITE_REQ: 148 /* Write DMA memory ... */ 149 dmaAddr = cmd.args[0]; /* Address */ 150 dmaData = cmd.args[1]; /* Data */ 151 /* Write the data to shared memory */ 152 _dma_putw(dmaAddr, dmaData); 153 LOG_INFO(BSL_LS_SYS_VERINET, 154 (BSL_META("**DMA_WR: 0x%x = 0x%x\n"), 155 dmaAddr, dmaData)); 156 /* Send back a response */ 157 make_rpc_setmem_resp(&cmd,dmaData); 158 write_command(sockfd, &cmd); 159 break; 160 161 case RPC_DMAC_READ_BYTES_REQ: 162 /* Read DMA memory as a string. Would be nice to use memcpy */ 163 dmaAddr = cmd.args[0]; 164 byte_ptr = (uint8 *)&cmd.args[1]; 165 LOG_INFO(BSL_LS_SYS_VERINET, 166 (BSL_META("**DMA_RD_B: 0x%x, %d bytes\n"), 167 dmaAddr, cmd.argcount)); 168 /* coverity[tainted_data] */ 169 for (i = 0; i < cmd.argcount; i++) { 170 byte_ptr[i] = _dma_getb(dmaAddr++); 171 } 172 /* Send back a response */ 173 cmd.status = RPC_OK; 174 cmd.opcode = RPC_DMAC_READ_BYTES_RESP; 175 write_command(sockfd, &cmd); 176 break; 177 178 case RPC_DMAC_WRITE_BYTES_REQ: 179 /* Write DMA memory as a string. Would be nice to use memcpy */ 180 dmaAddr = cmd.args[0]; /* Address */ 181 byte_ptr = (uint8 *)&cmd.args[1]; /* Data */ 182 /* Write the data to shared memory */ 183 LOG_INFO(BSL_LS_SYS_VERINET, 184 (BSL_META("**DMA_WR_B: 0x%x, %d bytes\n"), 185 dmaAddr, cmd.argcount)); 186 for (i = 0; i < cmd.argcount; i++) { 187 _dma_putb(dmaAddr++, byte_ptr[i]); 188 } 189 /* Send back a response */ 190 cmd.status = RPC_OK; 191 cmd.opcode = RPC_DMAC_WRITE_BYTES_RESP; 192 write_command(sockfd, &cmd); 193 break; 194 195 case RPC_DISCONNECT: 196 finished = 1; 197 v->dmacWorkerExit++; 198 LOG_INFO(BSL_LS_SYS_VERINET, 199 (BSL_META("received disconnect\n"))); 200 break; 201 202 default: 203 /* Unknown opcode */ 204 break; 205 } 206 } 207 LOG_INFO(BSL_LS_SYS_VERINET, 208 (BSL_META("shutdown and tread existing\n"))); 209 close(sockfd); 210 sal_thread_exit(0); 211 } 212 213 214 /* 215 * main: Sets up the socket and handles client requests with a child 216 * process per socket. 217 */ 218 void 219 dmac_listener(void *v_void) 220 { 221 verinet_t *v = (verinet_t *)v_void; 222 int sockfd, newsockfd, one = 1; 223 socklen_t clilen; 224 struct sockaddr_in cli_addr, serv_addr; 225 226 /* Initialize socket ... */ 227 228 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 229 perror("server: can't open stream socket"); 230 exit(1); 231 } 232 233 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 234 (char *) &one, sizeof (one)) < 0) { 235 perror("setsockopt"); 236 } 237 238 /* 239 * Setup server address... 240 */ 241 memset((void *) &serv_addr,0x0, sizeof(serv_addr)); 242 serv_addr.sin_family = AF_INET; 243 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 244 serv_addr.sin_port = htons(0); /* Pick any port */ 245 246 /* 247 * Bind our local address 248 */ 249 if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { 250 perror("dmac: unable to bind address"); 251 sal_thread_exit(0); 252 } 253 254 v->dmaPort = getsockport(sockfd); /* Get port that was picked */ 255 256 /* listen for inbound connections ... */ 257 listen(sockfd, 5); 258 259 /* Notify dmac_init that socket is listening */ 260 sal_sem_give(v->dmacListening); 261 262 cli_out("DMA Controller listening on port[%d]\n", v->dmaPort); 263 264 while (!v->dmacWorkerExit) { 265 clilen = sizeof(cli_addr); 266 267 newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); 268 if (newsockfd < 0 && errno == EINTR) { 269 continue; 270 } 271 272 if (newsockfd < 0) { 273 perror("server: accept error"); 274 } else { 275 v->dmacFd = newsockfd; 276 v->dmacHandler = sal_thread_create("DMA-controller", 277 SAL_THREAD_STKSZ, 100, 278 dmac_handler, v); 279 280 if (SAL_THREAD_ERROR == v->dmacHandler) { 281 cli_out("Thread creation error!\n"); 282 } else { 283 LOG_INFO(BSL_LS_SYS_VERINET, 284 (BSL_META("DMAC request thread dispatched.\n"))); 285 } 286 } 287 } 288 LOG_INFO(BSL_LS_SYS_VERINET, 289 (BSL_META("DMA listener shutdown.\n"))); 290 close(sockfd); 291 sal_thread_exit(0); 292 } 293 294 int 295 dmac_init(verinet_t *v) 296 { 297 if (v->dmacInited) { 298 return 0; 299 } 300 301 v->dmacListening = 302 sal_sem_create("dmac listener", sal_sem_BINARY, 0); 303 304 cli_out("Starting DMA service...\n"); 305 306 v->dmacListener = sal_thread_create("DMA-listener", 307 SAL_THREAD_STKSZ, 100, 308 dmac_listener, v); 309 if (SAL_THREAD_ERROR == v->dmacListener) { 310 cli_out("ERROR: could not create DMAC task: %s!\n", strerror(errno)); 311 return -2; 312 } 313 314 sal_sem_take(v->dmacListening, sal_sem_FOREVER); /* Wait for listen() */ 315 sal_sem_destroy(v->dmacListening); 316 317 v->dmacInited = 1; 318 319 return 0; 320 }