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 }