Merge HEAD from master.kernel.org:/pub/scm/linux/kernel/git/paulus/ppc64-2.6
[linux-2.6] / arch / ppc64 / kernel / HvLpEvent.c
1 /*
2  * Copyright 2001 Mike Corrigan IBM Corp
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version
7  * 2 of the License, or (at your option) any later version.
8  */
9 #include <linux/stddef.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <asm/system.h>
13 #include <asm/iSeries/HvLpEvent.h>
14 #include <asm/iSeries/HvCallEvent.h>
15 #include <asm/iSeries/ItLpNaca.h>
16
17 /* Array of LpEvent handler functions */
18 LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
19 unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
20
21 /* Register a handler for an LpEvent type */
22
23 int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler handler )
24 {
25         int rc = 1;
26         if ( eventType < HvLpEvent_Type_NumTypes ) {
27                 lpEventHandler[eventType] = handler;
28                 rc = 0;
29         }
30         return rc;
31         
32 }
33
34 int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType )
35 {
36         int rc = 1;
37
38         might_sleep();
39
40         if ( eventType < HvLpEvent_Type_NumTypes ) {
41                 if ( !lpEventHandlerPaths[eventType] ) {
42                         lpEventHandler[eventType] = NULL;
43                         rc = 0;
44
45                         /* We now sleep until all other CPUs have scheduled. This ensures that
46                          * the deletion is seen by all other CPUs, and that the deleted handler
47                          * isn't still running on another CPU when we return. */
48                         synchronize_rcu();
49                 }
50         }
51         return rc;
52 }
53 EXPORT_SYMBOL(HvLpEvent_registerHandler);
54 EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
55
56 /* (lpIndex is the partition index of the target partition.  
57  * needed only for VirtualIo, VirtualLan and SessionMgr.  Zero
58  * indicates to use our partition index - for the other types)
59  */
60 int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex )
61 {
62         int rc = 1;
63         if ( eventType < HvLpEvent_Type_NumTypes &&
64              lpEventHandler[eventType] ) {
65                 if ( lpIndex == 0 )
66                         lpIndex = itLpNaca.xLpIndex;
67                 HvCallEvent_openLpEventPath( lpIndex, eventType );
68                 ++lpEventHandlerPaths[eventType];
69                 rc = 0;
70         }
71         return rc;
72 }
73
74 int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex )
75 {
76         int rc = 1;
77         if ( eventType < HvLpEvent_Type_NumTypes &&
78              lpEventHandler[eventType] &&
79              lpEventHandlerPaths[eventType] ) {
80                 if ( lpIndex == 0 )
81                         lpIndex = itLpNaca.xLpIndex;
82                 HvCallEvent_closeLpEventPath( lpIndex, eventType );
83                 --lpEventHandlerPaths[eventType];
84                 rc = 0;
85         }
86         return rc;
87 }
88