|
@@ -37,8 +37,28 @@
|
|
|
* architectures that don't have NMI-safe cmpxchg implementation, the
|
|
|
* list can NOT be used in NMI handler. So code uses the list in NMI
|
|
|
* handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
|
|
|
+ *
|
|
|
+ * Copyright 2010,2011 Intel Corp.
|
|
|
+ * Author: Huang Ying <ying.huang@intel.com>
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or
|
|
|
+ * modify it under the terms of the GNU General Public License version
|
|
|
+ * 2 as published by the Free Software Foundation;
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ * GNU General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program; if not, write to the Free Software
|
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
*/
|
|
|
|
|
|
+#include <linux/kernel.h>
|
|
|
+#include <asm/system.h>
|
|
|
+#include <asm/processor.h>
|
|
|
+
|
|
|
struct llist_head {
|
|
|
struct llist_node *first;
|
|
|
};
|
|
@@ -113,14 +133,46 @@ static inline void init_llist_head(struct llist_head *list)
|
|
|
* test whether the list is empty without deleting something from the
|
|
|
* list.
|
|
|
*/
|
|
|
-static inline int llist_empty(const struct llist_head *head)
|
|
|
+static inline bool llist_empty(const struct llist_head *head)
|
|
|
{
|
|
|
return ACCESS_ONCE(head->first) == NULL;
|
|
|
}
|
|
|
|
|
|
-void llist_add(struct llist_node *new, struct llist_head *head);
|
|
|
-void llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
|
|
|
- struct llist_head *head);
|
|
|
-struct llist_node *llist_del_first(struct llist_head *head);
|
|
|
-struct llist_node *llist_del_all(struct llist_head *head);
|
|
|
+/**
|
|
|
+ * llist_add - add a new entry
|
|
|
+ * @new: new entry to be added
|
|
|
+ * @head: the head for your lock-less list
|
|
|
+ */
|
|
|
+static inline void llist_add(struct llist_node *new, struct llist_head *head)
|
|
|
+{
|
|
|
+ struct llist_node *entry, *old_entry;
|
|
|
+
|
|
|
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
|
|
|
+ BUG_ON(in_nmi());
|
|
|
+#endif
|
|
|
+
|
|
|
+ entry = head->first;
|
|
|
+ do {
|
|
|
+ old_entry = entry;
|
|
|
+ new->next = entry;
|
|
|
+ cpu_relax();
|
|
|
+ } while ((entry = cmpxchg(&head->first, old_entry, new)) != old_entry);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * llist_del_all - delete all entries from lock-less list
|
|
|
+ * @head: the head of lock-less list to delete all entries
|
|
|
+ *
|
|
|
+ * If list is empty, return NULL, otherwise, delete all entries and
|
|
|
+ * return the pointer to the first entry. The order of entries
|
|
|
+ * deleted is from the newest to the oldest added one.
|
|
|
+ */
|
|
|
+static inline struct llist_node *llist_del_all(struct llist_head *head)
|
|
|
+{
|
|
|
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
|
|
|
+ BUG_ON(in_nmi());
|
|
|
+#endif
|
|
|
+
|
|
|
+ return xchg(&head->first, NULL);
|
|
|
+}
|
|
|
#endif /* LLIST_H */
|