• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2010 - 2013 UNISYS CORPORATION
2  * All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or (at
7  * your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12  * NON INFRINGEMENT.  See the GNU General Public License for more
13  * details.
14  */
15 
16 #include <linux/kernel.h>
17 #ifdef CONFIG_MODVERSIONS
18 #include <config/modversions.h>
19 #endif
20 #include <linux/module.h>
21 #include <linux/init.h>		/* for module_init and module_exit */
22 #include <linux/slab.h>		/* for memcpy */
23 #include <linux/types.h>
24 
25 /* Implementation of exported functions for Supervisor channels */
26 #include "channel.h"
27 
28 /*
29  * Routine Description:
30  * Tries to insert the prebuilt signal pointed to by pSignal into the nth
31  * Queue of the Channel pointed to by pChannel
32  *
33  * Parameters:
34  * pChannel: (IN) points to the IO Channel
35  * Queue: (IN) nth Queue of the IO Channel
36  * pSignal: (IN) pointer to the signal
37  *
38  * Assumptions:
39  * - pChannel, Queue and pSignal are valid.
40  * - If insertion fails due to a full queue, the caller will determine the
41  * retry policy (e.g. wait & try again, report an error, etc.).
42  *
43  * Return value:
44  * 1 if the insertion succeeds, 0 if the queue was full.
45  */
46 unsigned char
visor_signal_insert(CHANNEL_HEADER __iomem * pChannel,u32 Queue,void * pSignal)47 visor_signal_insert(CHANNEL_HEADER __iomem *pChannel, u32 Queue, void *pSignal)
48 {
49 	void __iomem *psignal;
50 	unsigned int head, tail, nof;
51 
52 	SIGNAL_QUEUE_HEADER __iomem *pqhdr =
53 	    (SIGNAL_QUEUE_HEADER __iomem *)
54 		((char __iomem *) pChannel + readq(&pChannel->oChannelSpace))
55 		+ Queue;
56 
57 	/* capture current head and tail */
58 	head = readl(&pqhdr->Head);
59 	tail = readl(&pqhdr->Tail);
60 
61 	/* queue is full if (head + 1) % n equals tail */
62 	if (((head + 1) % readl(&pqhdr->MaxSignalSlots)) == tail) {
63 		nof = readq(&pqhdr->NumOverflows) + 1;
64 		writeq(nof, &pqhdr->NumOverflows);
65 		return 0;
66 	}
67 
68 	/* increment the head index */
69 	head = (head + 1) % readl(&pqhdr->MaxSignalSlots);
70 
71 	/* copy signal to the head location from the area pointed to
72 	 * by pSignal
73 	 */
74 	psignal = (char __iomem *)pqhdr + readq(&pqhdr->oSignalBase) +
75 		(head * readl(&pqhdr->SignalSize));
76 	memcpy_toio(psignal, pSignal, readl(&pqhdr->SignalSize));
77 
78 	mb(); /* channel synch */
79 	writel(head, &pqhdr->Head);
80 
81 	writeq(readq(&pqhdr->NumSignalsSent) + 1, &pqhdr->NumSignalsSent);
82 	return 1;
83 }
84 EXPORT_SYMBOL_GPL(visor_signal_insert);
85 
86 /*
87  * Routine Description:
88  * Removes one signal from Channel pChannel's nth Queue at the
89  * time of the call and copies it into the memory pointed to by
90  * pSignal.
91  *
92  * Parameters:
93  * pChannel: (IN) points to the IO Channel
94  * Queue: (IN) nth Queue of the IO Channel
95  * pSignal: (IN) pointer to where the signals are to be copied
96  *
97  * Assumptions:
98  * - pChannel and Queue are valid.
99  * - pSignal points to a memory area large enough to hold queue's SignalSize
100  *
101  * Return value:
102  * 1 if the removal succeeds, 0 if the queue was empty.
103  */
104 unsigned char
visor_signal_remove(CHANNEL_HEADER __iomem * pChannel,u32 Queue,void * pSignal)105 visor_signal_remove(CHANNEL_HEADER __iomem *pChannel, u32 Queue, void *pSignal)
106 {
107 	void __iomem *psource;
108 	unsigned int head, tail;
109 	SIGNAL_QUEUE_HEADER __iomem *pqhdr =
110 	    (SIGNAL_QUEUE_HEADER __iomem *) ((char __iomem *) pChannel +
111 				    readq(&pChannel->oChannelSpace)) + Queue;
112 
113 	/* capture current head and tail */
114 	head = readl(&pqhdr->Head);
115 	tail = readl(&pqhdr->Tail);
116 
117 	/* queue is empty if the head index equals the tail index */
118 	if (head == tail) {
119 		writeq(readq(&pqhdr->NumEmptyCnt) + 1, &pqhdr->NumEmptyCnt);
120 		return 0;
121 	}
122 
123 	/* advance past the 'empty' front slot */
124 	tail = (tail + 1) % readl(&pqhdr->MaxSignalSlots);
125 
126 	/* copy signal from tail location to the area pointed to by pSignal */
127 	psource = (char __iomem *) pqhdr + readq(&pqhdr->oSignalBase) +
128 		(tail * readl(&pqhdr->SignalSize));
129 	memcpy_fromio(pSignal, psource, readl(&pqhdr->SignalSize));
130 
131 	mb(); /* channel synch */
132 	writel(tail, &pqhdr->Tail);
133 
134 	writeq(readq(&pqhdr->NumSignalsReceived) + 1,
135 	       &pqhdr->NumSignalsReceived);
136 	return 1;
137 }
138 EXPORT_SYMBOL_GPL(visor_signal_remove);
139 
140 /*
141  * Routine Description:
142  * Removes all signals present in Channel pChannel's nth Queue at the
143  * time of the call and copies them into the memory pointed to by
144  * pSignal.  Returns the # of signals copied as the value of the routine.
145  *
146  * Parameters:
147  * pChannel: (IN) points to the IO Channel
148  * Queue: (IN) nth Queue of the IO Channel
149  * pSignal: (IN) pointer to where the signals are to be copied
150  *
151  * Assumptions:
152  * - pChannel and Queue are valid.
153  * - pSignal points to a memory area large enough to hold Queue's MaxSignals
154  * # of signals, each of which is Queue's SignalSize.
155  *
156  * Return value:
157  * # of signals copied.
158  */
159 unsigned int
SignalRemoveAll(pCHANNEL_HEADER pChannel,u32 Queue,void * pSignal)160 SignalRemoveAll(pCHANNEL_HEADER pChannel, u32 Queue, void *pSignal)
161 {
162 	void *psource;
163 	unsigned int head, tail, signalCount = 0;
164 	pSIGNAL_QUEUE_HEADER pqhdr =
165 	    (pSIGNAL_QUEUE_HEADER) ((char *) pChannel +
166 				    pChannel->oChannelSpace) + Queue;
167 
168 	/* capture current head and tail */
169 	head = pqhdr->Head;
170 	tail = pqhdr->Tail;
171 
172 	/* queue is empty if the head index equals the tail index */
173 	if (head == tail)
174 		return 0;
175 
176 	while (head != tail) {
177 		/* advance past the 'empty' front slot */
178 		tail = (tail + 1) % pqhdr->MaxSignalSlots;
179 
180 		/* copy signal from tail location to the area pointed
181 		 * to by pSignal
182 		 */
183 		psource =
184 		    (char *) pqhdr + pqhdr->oSignalBase +
185 		    (tail * pqhdr->SignalSize);
186 		memcpy((char *) pSignal + (pqhdr->SignalSize * signalCount),
187 		       psource, pqhdr->SignalSize);
188 
189 		mb(); /* channel synch */
190 		pqhdr->Tail = tail;
191 
192 		signalCount++;
193 		pqhdr->NumSignalsReceived++;
194 	}
195 
196 	return signalCount;
197 }
198 
199 /*
200  * Routine Description:
201  * Determine whether a signal queue is empty.
202  *
203  * Parameters:
204  * pChannel: (IN) points to the IO Channel
205  * Queue: (IN) nth Queue of the IO Channel
206  *
207  * Return value:
208  * 1 if the signal queue is empty, 0 otherwise.
209  */
210 unsigned char
visor_signalqueue_empty(CHANNEL_HEADER __iomem * pChannel,u32 Queue)211 visor_signalqueue_empty(CHANNEL_HEADER __iomem *pChannel, u32 Queue)
212 {
213 	SIGNAL_QUEUE_HEADER __iomem *pqhdr =
214 	    (SIGNAL_QUEUE_HEADER __iomem *) ((char __iomem *) pChannel +
215 				    readq(&pChannel->oChannelSpace)) + Queue;
216 	return readl(&pqhdr->Head) == readl(&pqhdr->Tail);
217 }
218 EXPORT_SYMBOL_GPL(visor_signalqueue_empty);
219 
220