openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 }