]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/octeon-sdk/cvmx-app-hotplug.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / octeon-sdk / cvmx-app-hotplug.c
1 /***********************license start***************
2  * Copyright (c) 2003-2010  Cavium Networks (support@cavium.com). All rights
3  * reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *   * Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  *
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17
18  *   * Neither the name of Cavium Networks nor the names of
19  *     its contributors may be used to endorse or promote products
20  *     derived from this software without specific prior written
21  *     permission.
22
23  * This Software, including technical data, may be subject to U.S. export  control
24  * laws, including the U.S. Export Administration Act and its  associated
25  * regulations, and may be subject to export or import  regulations in other
26  * countries.
27
28  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29  * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
30  * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31  * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32  * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33  * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34  * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35  * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36  * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37  * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38  ***********************license end**************************************/
39
40 /**
41  * @file
42  *
43  * Provides APIs for applications to register for hotplug. It also provides 
44  * APIs for requesting shutdown of a running target application. 
45  *
46  * <hr>$Revision: $<hr>
47  */
48
49 #include "cvmx-app-hotplug.h"
50 #include "cvmx-spinlock.h"
51
52 //#define DEBUG 1
53
54 #ifndef CVMX_BUILD_FOR_LINUX_USER
55
56 static CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_sync_lock = { CVMX_SPINLOCK_UNLOCKED_VAL };
57 static CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_lock = { CVMX_SPINLOCK_UNLOCKED_VAL };
58 static CVMX_SHARED cvmx_app_hotplug_info_t *cvmx_app_hotplug_info_ptr = NULL;
59
60 static void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], void *user_arg);
61 static void __cvmx_app_hotplug_sync(void);
62 static void __cvmx_app_hotplug_reset(void);
63
64 /**
65  * This routine registers an application for hotplug. It installs a handler for
66  * any incoming shutdown request. It also registers a callback routine from the
67  * application. This callback is invoked when the application receives a 
68  * shutdown notification. 
69  *
70  * This routine only needs to be called once per application. 
71  *
72  * @param fn      Callback routine from the application. 
73  * @param arg     Argument to the application callback routine. 
74  * @return        Return 0 on success, -1 on failure
75  *
76  */
77 int cvmx_app_hotplug_register(void(*fn)(void*), void* arg)
78 {
79     /* Find the list of applications launched by bootoct utility. */
80
81     if (!(cvmx_app_hotplug_info_ptr = cvmx_app_hotplug_get_info(cvmx_sysinfo_get()->core_mask)))
82     {
83         /* Application not launched by bootoct? */
84         printf("ERROR: cmvx_app_hotplug_register() failed\n");
85         return -1;
86     }
87
88     /* Register the callback */
89     cvmx_app_hotplug_info_ptr->data = CAST64(arg);
90     cvmx_app_hotplug_info_ptr->shutdown_callback = CAST64(fn);
91
92 #ifdef DEBUG
93     cvmx_dprintf("cvmx_app_hotplug_register(): coremask 0x%x valid %d\n", 
94                   cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid);
95 #endif
96
97     cvmx_interrupt_register(CVMX_IRQ_MBOX0, __cvmx_app_hotplug_shutdown, NULL);
98
99     return 0;
100 }
101
102 /**
103  * Activate the current application core for receiving hotplug shutdown requests. 
104  *
105  * This routine makes sure that each core belonging to the application is enabled 
106  * to receive the shutdown notification and also provides a barrier sync to make
107  * sure that all cores are ready. 
108  */
109 int cvmx_app_hotplug_activate(void)
110 {
111     /* Make sure all application cores are activating */
112     __cvmx_app_hotplug_sync();
113
114     cvmx_spinlock_lock(&cvmx_app_hotplug_lock);
115
116     if (!cvmx_app_hotplug_info_ptr)
117     {
118         cvmx_spinlock_unlock(&cvmx_app_hotplug_lock);
119         printf("ERROR: This application is not registered for hotplug\n");
120         return -1;
121     }
122
123     /* Enable the interrupt before we mark the core as activated */
124     cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0);
125
126     cvmx_app_hotplug_info_ptr->hotplug_activated_coremask |= (1<<cvmx_get_core_num());
127
128 #ifdef DEBUG
129     cvmx_dprintf("cvmx_app_hotplug_activate(): coremask 0x%x valid %d sizeof %d\n", 
130                  cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid, 
131                  sizeof(*cvmx_app_hotplug_info_ptr));
132 #endif
133
134     cvmx_spinlock_unlock(&cvmx_app_hotplug_lock);
135
136     return 0;
137 }
138
139 /**
140  * This routine is only required if cvmx_app_hotplug_shutdown_request() was called
141  * with wait=0. This routine waits for the application shutdown to complete. 
142  *
143  * @param coremask     Coremask the application is running on. 
144  * @return             0 on success, -1 on error
145  *
146  */
147 int cvmx_app_hotplug_shutdown_complete(uint32_t coremask)
148 {
149     cvmx_app_hotplug_info_t *hotplug_info_ptr;
150
151     if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask)))
152     {
153         printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask);
154         return -1;
155     }
156
157     while(!hotplug_info_ptr->shutdown_done);
158
159     /* Clean up the hotplug info region for this app */
160     bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr));
161
162     return 0;
163 }
164
165 /**
166  * Disable recognition of any incoming shutdown request. 
167  */
168
169 void cvmx_app_hotplug_shutdown_disable(void)
170 {
171     cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0);
172 }
173
174 /**
175  * Re-enable recognition of incoming shutdown requests.
176  */
177
178 void cvmx_app_hotplug_shutdown_enable(void)
179 {
180     cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0);
181 }
182
183 /*
184  * ISR for the incoming shutdown request interrupt. 
185  */
186 static void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], void *user_arg)
187 {
188     cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
189     uint32_t flags;
190
191     cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0);
192
193     /* Clear the interrupt */
194     cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 1);
195
196     /* Make sure the write above completes */
197     cvmx_read_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()));
198
199     if (!cvmx_app_hotplug_info_ptr)
200     {
201         printf("ERROR: Application is not registered for hotplug!\n");
202         return;
203     }
204
205     if (cvmx_app_hotplug_info_ptr->hotplug_activated_coremask != sys_info_ptr->core_mask)
206     {
207         printf("ERROR: Shutdown requested when not all app cores have activated hotplug\n"
208                "Application coremask: 0x%x Hotplug coremask: 0x%x\n", (unsigned int)sys_info_ptr->core_mask, 
209                (unsigned int)cvmx_app_hotplug_info_ptr->hotplug_activated_coremask);
210         return;
211     }
212
213     /* Call the application's own callback function */
214     ((void(*)(void*))(long)cvmx_app_hotplug_info_ptr->shutdown_callback)(CASTPTR(void *, cvmx_app_hotplug_info_ptr->data));
215
216     __cvmx_app_hotplug_sync();
217
218     if (cvmx_coremask_first_core(sys_info_ptr->core_mask))
219     {
220         bzero(cvmx_app_hotplug_info_ptr, sizeof(*cvmx_app_hotplug_info_ptr));
221 #ifdef DEBUG
222         cvmx_dprintf("__cvmx_app_hotplug_shutdown(): setting shutdown done! \n");
223 #endif
224         cvmx_app_hotplug_info_ptr->shutdown_done = 1;
225     }
226
227     flags = cvmx_interrupt_disable_save();
228
229     __cvmx_app_hotplug_sync();
230
231     /* Reset the core */
232     __cvmx_app_hotplug_reset();
233 }
234
235 /*
236  * Reset the core. We just jump back to the reset vector for now. 
237  */
238 void __cvmx_app_hotplug_reset(void)
239 {
240     /* Code from SecondaryCoreLoop from bootloader, sleep until we recieve
241        a NMI. */
242     __asm__ volatile (
243         ".set noreorder      \n"
244         "\tsync               \n"
245         "\tnop               \n"
246         "1:\twait            \n"
247         "\tb 1b              \n"
248         "\tnop               \n"             
249         ".set reorder        \n"
250         :: 
251     );
252 }
253
254 /* 
255  * We need a separate sync operation from cvmx_coremask_barrier_sync() to
256  * avoid a deadlock on state.lock, since the application itself maybe doing a
257  * cvmx_coremask_barrier_sync(). 
258  */
259 static void __cvmx_app_hotplug_sync(void)
260 {
261     static CVMX_SHARED volatile uint32_t sync_coremask = 0;
262     cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
263
264     cvmx_spinlock_lock(&cvmx_app_hotplug_sync_lock);
265     
266     sync_coremask |= cvmx_coremask_core(cvmx_get_core_num());
267
268     cvmx_spinlock_unlock(&cvmx_app_hotplug_sync_lock);
269
270     while (sync_coremask != sys_info_ptr->core_mask);
271 }
272
273 #endif /* CVMX_BUILD_FOR_LINUX_USER */
274
275 /**
276  * Return the hotplug info structure (cvmx_app_hotplug_info_t) pointer for the 
277  * application running on the given coremask. 
278  *
279  * @param coremask     Coremask of application. 
280  * @return             Returns hotplug info struct on success, NULL on failure
281  *
282  */
283 cvmx_app_hotplug_info_t* cvmx_app_hotplug_get_info(uint32_t coremask)
284 {
285     const struct cvmx_bootmem_named_block_desc *block_desc;
286     cvmx_app_hotplug_info_t *hip;
287     cvmx_app_hotplug_global_t *hgp;
288     int i;
289
290     block_desc = cvmx_bootmem_find_named_block(CVMX_APP_HOTPLUG_INFO_REGION_NAME);
291
292     if (!block_desc)
293     {
294         printf("ERROR: Hotplug info region is not setup\n");
295         return NULL;
296     }
297     else
298
299 #ifdef CVMX_BUILD_FOR_LINUX_USER
300     {
301         size_t pg_sz = sysconf(_SC_PAGESIZE), size;
302         off_t offset;
303         char *vaddr;
304         int fd;
305
306         if ((fd = open("/dev/mem", O_RDWR)) == -1) {
307             perror("open");
308             return NULL;
309         }
310
311         /*
312          * We need to mmap() this memory, since this was allocated from the 
313          * kernel bootup code and does not reside in the RESERVE32 region.
314          */
315         size = CVMX_APP_HOTPLUG_INFO_REGION_SIZE + pg_sz-1;
316         offset = block_desc->base_addr & ~(pg_sz-1);
317         if ((vaddr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) 
318         {
319             perror("mmap");
320             return NULL;
321         }
322
323         hgp = (cvmx_app_hotplug_global_t *)(vaddr + ( block_desc->base_addr & (pg_sz-1)));
324     }
325 #else
326     hgp = cvmx_phys_to_ptr(block_desc->base_addr);
327 #endif
328
329     hip = hgp->hotplug_info_array;
330
331 #ifdef DEBUG
332     cvmx_dprintf("cvmx_app_hotplug_get_info(): hotplug_info phy addr 0x%llx ptr %p\n", 
333                   block_desc->base_addr, hgp);
334 #endif
335
336     /* Look for the current app's info */
337
338     for (i=0; i<CVMX_APP_HOTPLUG_MAX_APPS; i++)
339     {
340         if (hip[i].coremask == coremask)
341         {
342 #ifdef DEBUG
343             cvmx_dprintf("cvmx_app_hotplug_get_info(): coremask match %d -- coremask 0x%x valid %d\n", 
344                          i, hip[i].coremask, hip[i].valid);
345 #endif
346
347             return &hip[i];
348         }
349     }
350
351     return NULL;
352 }
353
354 /**
355  * This routine sends a shutdown request to a running target application. 
356  *
357  * @param coremask     Coremask the application is running on. 
358  * @param wait         1 - Wait for shutdown completion
359  *                     0 - Do not wait
360  * @return             0 on success, -1 on error
361  *
362  */
363
364 int cvmx_app_hotplug_shutdown_request(uint32_t coremask, int wait) 
365 {
366     int i;
367     cvmx_app_hotplug_info_t *hotplug_info_ptr;
368
369     if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask)))
370     {
371         printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask);
372         return -1;
373     }
374
375     if (!hotplug_info_ptr->shutdown_callback)
376     {
377         printf("\nERROR: Target application has not registered for hotplug!\n");
378         return -1;
379     }
380
381     if (hotplug_info_ptr->hotplug_activated_coremask != coremask)
382     {
383         printf("\nERROR: Not all application cores have activated hotplug\n");
384         return -1;
385     }
386
387     /* Send IPIs to all application cores to request shutdown */
388     for (i=0; i<CVMX_MAX_CORES; i++) {
389         if (coremask & (1<<i))
390                 cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 1);
391     }
392
393     if (wait)
394     {
395         while (!hotplug_info_ptr->shutdown_done);    
396
397         /* Clean up the hotplug info region for this application */
398         bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr));
399     }
400
401     return 0;
402 }