Merge 3.18-rc3 into staging-next
[cascardo/linux.git] / drivers / staging / unisys / uislib / uisqueue.c
1 /* uisqueue.c
2  *
3  * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  */
17
18 /* @ALL_INSPECTED */
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21
22 #include "uisutils.h"
23
24 #include "chanstub.h"
25
26 /* this is shorter than using __FILE__ (full path name) in
27  * debug/info/error messages */
28 #define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
29 #define __MYFILE__ "uisqueue.c"
30
31 #define CHECK_CACHE_ALIGN 0
32
33 /*****************************************************/
34 /* Exported functions                                */
35 /*****************************************************/
36 unsigned long long
37 uisqueue_interlocked_or(unsigned long long __iomem *tgt,
38                        unsigned long long set)
39 {
40         unsigned long long i;
41         unsigned long long j;
42
43         j = readq(tgt);
44         do {
45                 i = j;
46                 j = cmpxchg((__force unsigned long long *)tgt, i, i | set);
47
48         } while (i != j);
49
50         return j;
51 }
52 EXPORT_SYMBOL_GPL(uisqueue_interlocked_or);
53
54 unsigned long long
55 uisqueue_interlocked_and(unsigned long long __iomem *tgt,
56                         unsigned long long set)
57 {
58         unsigned long long i;
59         unsigned long long j;
60
61         j = readq(tgt);
62         do {
63                 i = j;
64                 j = cmpxchg((__force unsigned long long *)tgt, i, i & set);
65
66         } while (i != j);
67
68         return j;
69 }
70 EXPORT_SYMBOL_GPL(uisqueue_interlocked_and);
71
72 static u8
73 do_locked_client_insert(struct uisqueue_info *queueinfo,
74                         unsigned int whichqueue,
75                         void *pSignal,
76                         spinlock_t *lock,
77                         unsigned char issueInterruptIfEmpty,
78                         u64 interruptHandle, u8 *channelId)
79 {
80         unsigned long flags;
81         u8 rc = 0;
82
83         spin_lock_irqsave(lock, flags);
84         if (!spar_channel_client_acquire_os(queueinfo->chan, channelId))
85                 goto unlock;
86         if (spar_signal_insert(queueinfo->chan, whichqueue, pSignal)) {
87                 queueinfo->packets_sent++;
88                 rc = 1;
89         }
90         spar_channel_client_release_os(queueinfo->chan, channelId);
91 unlock:
92         spin_unlock_irqrestore((spinlock_t *)lock, flags);
93         return rc;
94 }
95
96 int
97 uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
98                                      struct uiscmdrsp *cmdrsp,
99                                      unsigned int whichqueue,
100                                      void *insertlock,
101                                      unsigned char issue_irq_if_empty,
102                                      u64 irq_handle,
103                                      char oktowait, u8 *channel_id)
104 {
105         while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
106                                         (spinlock_t *) insertlock,
107                                         issue_irq_if_empty,
108                                         irq_handle, channel_id)) {
109                 if (oktowait != OK_TO_WAIT) {
110                         LOGERR("****FAILED visor_signal_insert failed; cannot wait; insert aborted\n");
111                         return 0;       /* failed to queue */
112                 }
113                 /* try again */
114                 LOGERR("****FAILED visor_signal_insert failed; waiting to try again\n");
115                 set_current_state(TASK_INTERRUPTIBLE);
116                 schedule_timeout(msecs_to_jiffies(10));
117         }
118         return 1;
119 }
120 EXPORT_SYMBOL_GPL(uisqueue_put_cmdrsp_with_lock_client);
121
122 /* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
123  * returns NULL if queue is empty */
124 int
125 uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo,
126                     void *cmdrsp, unsigned int whichqueue)
127 {
128         if (!spar_signal_remove(queueinfo->chan, whichqueue, cmdrsp))
129                 return 0;
130
131         queueinfo->packets_received++;
132
133         return 1;               /* Success */
134 }
135 EXPORT_SYMBOL_GPL(uisqueue_get_cmdrsp);