2 * Copyright 2009 Novell. All Rights Reserved.
4 * See include/linux/shm_signal.h for documentation
7 * Gregory Haskins <ghaskins@novell.com>
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <linux/module.h>
24 #include <linux/interrupt.h>
25 #include <linux/shm_signal.h>
27 int shm_signal_enable(struct shm_signal
*s
, int flags
)
29 struct shm_signal_irq
*irq
= &s
->desc
->irq
[s
->locale
];
32 spin_lock_irqsave(&s
->lock
, iflags
);
37 if ((irq
->dirty
|| irq
->pending
)
38 && !test_bit(shm_signal_in_wakeup
, &s
->flags
)) {
40 tasklet_schedule(&s
->deferred_notify
);
43 spin_unlock_irqrestore(&s
->lock
, iflags
);
47 EXPORT_SYMBOL_GPL(shm_signal_enable
);
49 int shm_signal_disable(struct shm_signal
*s
, int flags
)
51 struct shm_signal_irq
*irq
= &s
->desc
->irq
[s
->locale
];
58 EXPORT_SYMBOL_GPL(shm_signal_disable
);
63 * each side of the shm_signal has an "irq" structure with the following
66 * - enabled: controlled by shm_signal_enable/disable() to mask/unmask
67 * the notification locally
68 * - dirty: indicates if the shared-memory is dirty or clean. This
69 * is updated regardless of the enabled/pending state so that
70 * the state is always accurately tracked.
71 * - pending: indicates if a signal is pending to the remote locale.
72 * This allows us to determine if a remote-notification is
73 * already in flight to optimize spurious notifications away.
75 int shm_signal_inject(struct shm_signal
*s
, int flags
)
77 /* Load the irq structure from the other locale */
78 struct shm_signal_irq
*irq
= &s
->desc
->irq
[!s
->locale
];
81 * We always mark the remote side as dirty regardless of whether
82 * they need to be notified.
85 wmb(); /* dirty must be visible before we test the pending state */
87 if (irq
->enabled
&& !irq
->pending
) {
91 * If the remote side has enabled notifications, and we do
92 * not see a notification pending, we must inject a new one.
95 wmb(); /* make it visible before we do the injection */
102 EXPORT_SYMBOL_GPL(shm_signal_inject
);
104 void _shm_signal_wakeup(struct shm_signal
*s
)
106 struct shm_signal_irq
*irq
= &s
->desc
->irq
[s
->locale
];
110 spin_lock_irqsave(&s
->lock
, flags
);
112 __set_bit(shm_signal_in_wakeup
, &s
->flags
);
115 * The outer loop protects against race conditions between
116 * irq->dirty and irq->pending updates
118 while (irq
->enabled
&& (irq
->dirty
|| irq
->pending
)) {
121 * Run until we completely exhaust irq->dirty (it may
122 * be re-dirtied by the remote side while we are in the
123 * callback). We let "pending" remain untouched until we have
124 * processed them all so that the remote side knows we do not
125 * need a new notification (yet).
129 /* the unlock is an implicit wmb() for dirty = 0 */
130 spin_unlock_irqrestore(&s
->lock
, flags
);
133 s
->notifier
->signal(s
->notifier
);
135 spin_lock_irqsave(&s
->lock
, flags
);
139 } while (irq
->enabled
&& dirty
);
144 * We can finally acknowledge the notification by clearing
145 * "pending" after all of the dirty memory has been processed
146 * Races against this clearing are handled by the outer loop.
147 * Subsequent iterations of this loop will execute with
148 * pending=0 potentially leading to future spurious
149 * notifications, but this is an acceptable tradeoff as this
150 * will be rare and harmless.
157 __clear_bit(shm_signal_in_wakeup
, &s
->flags
);
158 spin_unlock_irqrestore(&s
->lock
, flags
);
161 EXPORT_SYMBOL_GPL(_shm_signal_wakeup
);
163 void _shm_signal_release(struct kref
*kref
)
165 struct shm_signal
*s
= container_of(kref
, struct shm_signal
, kref
);
169 EXPORT_SYMBOL_GPL(_shm_signal_release
);
172 deferred_notify(unsigned long data
)
174 struct shm_signal
*s
= (struct shm_signal
*)data
;
176 _shm_signal_wakeup(s
);
179 void shm_signal_init(struct shm_signal
*s
, enum shm_signal_locality locale
,
180 struct shm_signal_ops
*ops
, struct shm_signal_desc
*desc
)
182 memset(s
, 0, sizeof(*s
));
184 spin_lock_init(&s
->lock
);
185 tasklet_init(&s
->deferred_notify
,
192 EXPORT_SYMBOL_GPL(shm_signal_init
);