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

intr.c (7504B)


      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  * Interrupt controller task.
      8  * This task emulates an interrupt handler and callout mechanism.
      9  */
     10 
     11 #ifdef LINUX_PLI_COMBO_BDE
     12 /* Avoid name clash when using two BDEs */
     13 #define intr_int_context pli_intr_int_context
     14 #endif
     15 
     16 #include <shared/bsl.h>
     17 
     18 #include <sys/types.h>
     19 #include <stdlib.h>
     20 #include <unistd.h>
     21 #include <string.h>
     22 #include <errno.h>
     23 #include <netinet/in.h>
     24 #include <sys/socket.h>
     25 #include <stdio.h>
     26 
     27 #ifdef VXWORKS
     28 #include <vxWorks.h>
     29 #include <sockLib.h>
     30 #endif
     31 
     32 #include <sal/appl/sal.h>
     33 #include <sal/appl/io.h>
     34 #include <sal/core/thread.h>
     35 #include <sal/core/sync.h>
     36 #include <sal/core/spl.h>
     37 #include <soc/debug.h>	
     38 
     39 #include "verinet.h"
     40 
     41 int
     42 intr_int_context(void)
     43 {
     44     int i;
     45 
     46     for (i = 0; i < N_VERINET_DEVICES; i++) {
     47 	if (sal_thread_self() == verinet[i].intrDispatchThread) {
     48 	    return 1;
     49 	}
     50     }
     51 
     52     return 0;
     53 }
     54 
     55 static void
     56 intr_dispatch(void *v_void)
     57 {
     58     verinet_t *v = (verinet_t *)v_void;
     59     int s;
     60 
     61     LOG_INFO(BSL_LS_SYS_VERINET,
     62              (BSL_META("running, sema=%p\n"),
     63               v->intrDispatchSema));
     64 
     65     while (!v->intrFinished) {
     66 	if (sal_sem_take(v->intrDispatchSema, sal_sem_FOREVER)) {
     67 	    cli_out("intr_dispatch: sal_sem_take failed\n");
     68 	    continue;
     69 	}
     70 
     71 	/*
     72 	 * In real hardware, interrupts aren't taken while at splhi.  We
     73 	 * simulate this in our thread-based simulation simply by taking
     74 	 * the semaphore for the duration of the call to the interrupt
     75 	 * vector.  To be correct, sal_splhi() would actually have to
     76 	 * suspend all other threads and spl() resume them.
     77 	 */
     78 
     79         LOG_INFO(BSL_LS_SYS_VERINET,
     80                  (BSL_META("ISR=%p ISR_data=%p\n"),
     81                   v->ISR, v->ISR_data));
     82 
     83 	if (v->ISR) {
     84 	    s = sal_splhi();
     85 	    (*v->ISR)(v->ISR_data);
     86 	    sal_spl(s);
     87 	}
     88     }
     89 
     90     LOG_INFO(BSL_LS_SYS_VERINET,
     91              (BSL_META("thread exiting ....\n")));
     92     sal_sem_destroy(v->intrDispatchSema);
     93     v->intrDispatchThread = 0;
     94     sal_thread_exit(0);
     95 }
     96 
     97 /*
     98  * Process an interrupt request dispatched on the socket.
     99  */
    100 
    101 void
    102 intr_handler(void *v_void)
    103 {
    104     verinet_t *v = (verinet_t *)v_void;
    105     uint32 cause;
    106     rpc_cmd_t cmd;
    107     int sockfd = v->intrFd;
    108 
    109     v->intrFinished = 0;
    110 
    111     /* Start off dispatch thread */
    112 
    113     v->intrDispatchSema =
    114 	sal_sem_create("Interrupt-dispatch", sal_sem_BINARY, 0);
    115 
    116     if (!v->intrDispatchSema) {
    117 	cli_out("intr_handler: failed to create dispatch sem\n");
    118 	v->intrFinished = 1;
    119     } else {
    120 	v->intrDispatchThread = sal_thread_create("Interrupt-dispatch",
    121 						  SAL_THREAD_STKSZ, 100,
    122 						  intr_dispatch, v);
    123 	if (SAL_THREAD_ERROR == v->intrDispatchThread) {
    124 	    cli_out("intr_handler: failed to create dispatch thread\n");
    125 	    sal_sem_destroy(v->intrDispatchSema);
    126 	    v->intrDispatchSema = 0;
    127 	    v->intrFinished = 1;
    128 	}
    129     }
    130 
    131     while (!v->intrFinished) {
    132         LOG_INFO(BSL_LS_SYS_VERINET,
    133                  (BSL_META("wait...\n")));
    134 
    135 	if (wait_command(sockfd, &cmd) < 0) {
    136 	    break;	/* Error message already printed */
    137 	}
    138 
    139         LOG_INFO(BSL_LS_SYS_VERINET,
    140                  (BSL_META("request opcode 0x%x\n"),
    141                   cmd.opcode));
    142 
    143 	switch(cmd.opcode) {
    144 
    145 	case RPC_SEND_INTR:
    146 	    /* Read cause */
    147 	    cause = cmd.args[0];
    148 	    make_rpc_intr_resp(&cmd,cause);
    149 	    write_command(sockfd, &cmd);
    150 
    151 	    if (v->intrSkipTest) {
    152                 LOG_INFO(BSL_LS_SYS_VERINET,
    153                          (BSL_META("Test interrupt received (ignoring)\n")));
    154 		v->intrSkipTest = 0;
    155 		break;
    156 	    }
    157 
    158 	    /* Wake up dispatch thread */
    159 
    160             LOG_INFO(BSL_LS_SYS_VERINET,
    161                      (BSL_META("Wake dispatch\n")));
    162 
    163 	    sal_sem_give(v->intrDispatchSema);
    164 	    break;
    165 
    166 	case RPC_DISCONNECT:
    167 	    v->intrFinished = 1;
    168 	    v->intrWorkerExit++;
    169             v->ISR = NULL;
    170             LOG_INFO(BSL_LS_SYS_VERINET,
    171                      (BSL_META("received disconnect\n")));
    172 	    sal_sem_give(v->intrDispatchSema);
    173 	    break;
    174 
    175 	default:
    176 	    /* Unknown opcode */
    177 	    break;
    178 	}
    179     }
    180     LOG_INFO(BSL_LS_SYS_VERINET,
    181              (BSL_META("shutting down...\n")));
    182     close(sockfd);
    183 
    184     /* If dispatch thread around - wait for him to exit */
    185 
    186     if (v->intrDispatchSema) {
    187 	sal_sem_give(v->intrDispatchSema);
    188     }
    189 
    190     sal_thread_exit(0);
    191 }
    192 
    193 void
    194 intr_set_vector(verinet_t *v, pli_isr_t isr, void *isr_data)
    195 {
    196     /*
    197      * Set interrupt vector
    198      */
    199 
    200     LOG_INFO(BSL_LS_SYS_VERINET,
    201              (BSL_META("intr_set_vector: dev=%d isr=%p isr_data=%p\n"),
    202               (int)(v - verinet), isr, isr_data));
    203 
    204     v->ISR = isr;
    205     v->ISR_data = isr_data;
    206 }
    207 
    208 /*
    209  * start_isr_service: Sets up the socket and handles client requests
    210  * with a child thread per socket.
    211  */
    212 void
    213 intr_listener(void *v_void)
    214 {
    215     verinet_t *v = (verinet_t *)v_void;
    216     int sockfd, newsockfd, one = 1;
    217     socklen_t clilen;
    218     struct sockaddr_in cli_addr, serv_addr;
    219 
    220     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    221 	perror("server: can't open stream socket");
    222 	exit(1);
    223     }
    224 
    225     if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
    226 		   (char *)&one, sizeof (one)) < 0) {
    227 	perror("setsockopt");
    228     }
    229 
    230     /*
    231      * Setup server address...
    232      */
    233     memset((void *) &serv_addr, 0, sizeof(serv_addr));
    234     serv_addr.sin_family = AF_INET;
    235     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    236     serv_addr.sin_port = htons(0);	/* Pick any port */
    237 
    238     /*
    239      * Bind our local address
    240      */
    241     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
    242 	perror("dmac: unable to bind address");
    243 	sal_thread_exit(0);
    244     }
    245 
    246     v->intPort = getsockport(sockfd);	/* Get port that was picked */
    247 
    248     /* listen for inbound homies ...*/
    249     listen(sockfd, 5);
    250 
    251     /* Notify intr_init that socket is listening */
    252     sal_sem_give(v->intrListening);
    253 
    254     cli_out("ISR dispatcher listening on port[%d]\n", v->intPort);
    255 
    256     while (!v->intrWorkerExit) {
    257 	clilen = sizeof(cli_addr);
    258 
    259 	newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    260 	if (newsockfd < 0 && errno == EINTR) {
    261 	    continue;
    262 	}
    263 
    264 	if (newsockfd < 0) {
    265 	    perror("server: accept error");
    266 	} else {
    267 	    v->intrSkipTest = 1;
    268 
    269 	    v->intrFd = newsockfd;
    270 
    271 	    v->intrHandlerThread = sal_thread_create("Interrupt-handler",
    272 						     SAL_THREAD_STKSZ, 100,
    273 						     intr_handler, v);
    274 
    275 	    if (SAL_THREAD_ERROR == v->intrHandlerThread) {
    276 		cli_out("start_isr_service: thread creation error\n");
    277 	    } else{
    278                 LOG_INFO(BSL_LS_SYS_VERINET,
    279                          (BSL_META("Interrupt request thread dispatched.\n")));
    280 	    }
    281 	}
    282     }
    283 
    284     LOG_INFO(BSL_LS_SYS_VERINET,
    285              (BSL_META("INTC listener shutdown.\n")));
    286     close(sockfd);
    287     sal_thread_exit(0);
    288 }
    289 
    290 int
    291 intr_init(verinet_t *v)
    292 {
    293     if (v->intrInited) {
    294 	return 0;
    295     }
    296 
    297     v->intrListening = sal_sem_create("intr listener", sal_sem_BINARY, 0);
    298 
    299     /*
    300      * Create Interrupt task
    301      */
    302     cli_out("Starting Interrupt service...\n");
    303 
    304     v->intrThread = sal_thread_create("Interrupt-listener",
    305 				      SAL_THREAD_STKSZ, 100,
    306 				      intr_listener, v);
    307 
    308     if (SAL_THREAD_ERROR == v->intrThread) {
    309 	cli_out("ERROR: could not create interrupt listener task!\n");
    310 	return -2;
    311     }
    312 
    313     sal_sem_take(v->intrListening, sal_sem_FOREVER);   /* Wait for listen() */
    314     sal_sem_destroy(v->intrListening);
    315 
    316     v->intrInited = 1;
    317 
    318     return 0;
    319 }