xref: /OK3568_Linux_fs/kernel/drivers/visorbus/visorchannel.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2010 - 2015 UNISYS CORPORATION
4*4882a593Smuzhiyun  * All rights reserved.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /*
8*4882a593Smuzhiyun  *  This provides s-Par channel communication primitives, which are
9*4882a593Smuzhiyun  *  independent of the mechanism used to access the channel data.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/uuid.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/visorbus.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "visorbus_private.h"
18*4882a593Smuzhiyun #include "controlvmchannel.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define VISOR_DRV_NAME "visorchannel"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define VISOR_CONSOLEVIDEO_CHANNEL_GUID \
23*4882a593Smuzhiyun 	GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \
24*4882a593Smuzhiyun 		  0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun struct visorchannel {
29*4882a593Smuzhiyun 	u64 physaddr;
30*4882a593Smuzhiyun 	ulong nbytes;
31*4882a593Smuzhiyun 	void *mapped;
32*4882a593Smuzhiyun 	bool requested;
33*4882a593Smuzhiyun 	struct channel_header chan_hdr;
34*4882a593Smuzhiyun 	guid_t guid;
35*4882a593Smuzhiyun 	/*
36*4882a593Smuzhiyun 	 * channel creator knows if more than one thread will be inserting or
37*4882a593Smuzhiyun 	 * removing
38*4882a593Smuzhiyun 	 */
39*4882a593Smuzhiyun 	bool needs_lock;
40*4882a593Smuzhiyun 	/* protect head writes in chan_hdr */
41*4882a593Smuzhiyun 	spinlock_t insert_lock;
42*4882a593Smuzhiyun 	/* protect tail writes in chan_hdr */
43*4882a593Smuzhiyun 	spinlock_t remove_lock;
44*4882a593Smuzhiyun 	guid_t type;
45*4882a593Smuzhiyun 	guid_t inst;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
visorchannel_destroy(struct visorchannel * channel)48*4882a593Smuzhiyun void visorchannel_destroy(struct visorchannel *channel)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	if (!channel)
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (channel->mapped) {
54*4882a593Smuzhiyun 		memunmap(channel->mapped);
55*4882a593Smuzhiyun 		if (channel->requested)
56*4882a593Smuzhiyun 			release_mem_region(channel->physaddr, channel->nbytes);
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 	kfree(channel);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
visorchannel_get_physaddr(struct visorchannel * channel)61*4882a593Smuzhiyun u64 visorchannel_get_physaddr(struct visorchannel *channel)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	return channel->physaddr;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
visorchannel_get_nbytes(struct visorchannel * channel)66*4882a593Smuzhiyun ulong visorchannel_get_nbytes(struct visorchannel *channel)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	return channel->nbytes;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
visorchannel_guid_id(const guid_t * guid,char * s)71*4882a593Smuzhiyun char *visorchannel_guid_id(const guid_t *guid, char *s)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	sprintf(s, "%pUL", guid);
74*4882a593Smuzhiyun 	return s;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
visorchannel_id(struct visorchannel * channel,char * s)77*4882a593Smuzhiyun char *visorchannel_id(struct visorchannel *channel, char *s)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	return visorchannel_guid_id(&channel->guid, s);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
visorchannel_zoneid(struct visorchannel * channel,char * s)82*4882a593Smuzhiyun char *visorchannel_zoneid(struct visorchannel *channel, char *s)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
visorchannel_get_clientpartition(struct visorchannel * channel)87*4882a593Smuzhiyun u64 visorchannel_get_clientpartition(struct visorchannel *channel)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	return channel->chan_hdr.partition_handle;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
visorchannel_set_clientpartition(struct visorchannel * channel,u64 partition_handle)92*4882a593Smuzhiyun int visorchannel_set_clientpartition(struct visorchannel *channel,
93*4882a593Smuzhiyun 				     u64 partition_handle)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	channel->chan_hdr.partition_handle = partition_handle;
96*4882a593Smuzhiyun 	return 0;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /**
100*4882a593Smuzhiyun  * visorchannel_get_guid() - queries the GUID of the designated channel
101*4882a593Smuzhiyun  * @channel: the channel to query
102*4882a593Smuzhiyun  *
103*4882a593Smuzhiyun  * Return: the GUID of the provided channel
104*4882a593Smuzhiyun  */
visorchannel_get_guid(struct visorchannel * channel)105*4882a593Smuzhiyun const guid_t *visorchannel_get_guid(struct visorchannel *channel)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	return &channel->guid;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(visorchannel_get_guid);
110*4882a593Smuzhiyun 
visorchannel_read(struct visorchannel * channel,ulong offset,void * dest,ulong nbytes)111*4882a593Smuzhiyun int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest,
112*4882a593Smuzhiyun 		      ulong nbytes)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	if (offset + nbytes > channel->nbytes)
115*4882a593Smuzhiyun 		return -EIO;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	memcpy(dest, channel->mapped + offset, nbytes);
118*4882a593Smuzhiyun 	return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
visorchannel_write(struct visorchannel * channel,ulong offset,void * dest,ulong nbytes)121*4882a593Smuzhiyun int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest,
122*4882a593Smuzhiyun 		       ulong nbytes)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	size_t chdr_size = sizeof(struct channel_header);
125*4882a593Smuzhiyun 	size_t copy_size;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	if (offset + nbytes > channel->nbytes)
128*4882a593Smuzhiyun 		return -EIO;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (offset < chdr_size) {
131*4882a593Smuzhiyun 		copy_size = min(chdr_size - offset, nbytes);
132*4882a593Smuzhiyun 		memcpy(((char *)(&channel->chan_hdr)) + offset,
133*4882a593Smuzhiyun 		       dest, copy_size);
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 	memcpy(channel->mapped + offset, dest, nbytes);
136*4882a593Smuzhiyun 	return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
visorchannel_get_header(struct visorchannel * channel)139*4882a593Smuzhiyun void *visorchannel_get_header(struct visorchannel *channel)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	return &channel->chan_hdr;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun  * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
146*4882a593Smuzhiyun  * channel header
147*4882a593Smuzhiyun  */
sig_queue_offset(struct channel_header * chan_hdr,int q)148*4882a593Smuzhiyun static int sig_queue_offset(struct channel_header *chan_hdr, int q)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	return ((chan_hdr)->ch_space_offset +
151*4882a593Smuzhiyun 	       ((q) * sizeof(struct signal_queue_header)));
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun /*
155*4882a593Smuzhiyun  * Return offset of a specific queue entry (data) from the beginning of a
156*4882a593Smuzhiyun  * channel header
157*4882a593Smuzhiyun  */
sig_data_offset(struct channel_header * chan_hdr,int q,struct signal_queue_header * sig_hdr,int slot)158*4882a593Smuzhiyun static int sig_data_offset(struct channel_header *chan_hdr, int q,
159*4882a593Smuzhiyun 			   struct signal_queue_header *sig_hdr, int slot)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	return (sig_queue_offset(chan_hdr, q) + sig_hdr->sig_base_offset +
162*4882a593Smuzhiyun 	       (slot * sig_hdr->signal_size));
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /*
166*4882a593Smuzhiyun  * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back into
167*4882a593Smuzhiyun  * host memory
168*4882a593Smuzhiyun  */
169*4882a593Smuzhiyun #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
170*4882a593Smuzhiyun 	visorchannel_write(channel, \
171*4882a593Smuzhiyun 			   sig_queue_offset(&channel->chan_hdr, queue) + \
172*4882a593Smuzhiyun 			   offsetof(struct signal_queue_header, FIELD), \
173*4882a593Smuzhiyun 			   &((sig_hdr)->FIELD), \
174*4882a593Smuzhiyun 			   sizeof((sig_hdr)->FIELD))
175*4882a593Smuzhiyun 
sig_read_header(struct visorchannel * channel,u32 queue,struct signal_queue_header * sig_hdr)176*4882a593Smuzhiyun static int sig_read_header(struct visorchannel *channel, u32 queue,
177*4882a593Smuzhiyun 			   struct signal_queue_header *sig_hdr)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
180*4882a593Smuzhiyun 		return -EINVAL;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	/* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
183*4882a593Smuzhiyun 	return visorchannel_read(channel,
184*4882a593Smuzhiyun 				 sig_queue_offset(&channel->chan_hdr, queue),
185*4882a593Smuzhiyun 				 sig_hdr, sizeof(struct signal_queue_header));
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
sig_read_data(struct visorchannel * channel,u32 queue,struct signal_queue_header * sig_hdr,u32 slot,void * data)188*4882a593Smuzhiyun static int sig_read_data(struct visorchannel *channel, u32 queue,
189*4882a593Smuzhiyun 			 struct signal_queue_header *sig_hdr, u32 slot,
190*4882a593Smuzhiyun 			 void *data)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
193*4882a593Smuzhiyun 						 sig_hdr, slot);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return visorchannel_read(channel, signal_data_offset,
196*4882a593Smuzhiyun 				 data, sig_hdr->signal_size);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
sig_write_data(struct visorchannel * channel,u32 queue,struct signal_queue_header * sig_hdr,u32 slot,void * data)199*4882a593Smuzhiyun static int sig_write_data(struct visorchannel *channel, u32 queue,
200*4882a593Smuzhiyun 			  struct signal_queue_header *sig_hdr, u32 slot,
201*4882a593Smuzhiyun 			  void *data)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
204*4882a593Smuzhiyun 						 sig_hdr, slot);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return visorchannel_write(channel, signal_data_offset,
207*4882a593Smuzhiyun 				  data, sig_hdr->signal_size);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
signalremove_inner(struct visorchannel * channel,u32 queue,void * msg)210*4882a593Smuzhiyun static int signalremove_inner(struct visorchannel *channel, u32 queue,
211*4882a593Smuzhiyun 			      void *msg)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct signal_queue_header sig_hdr;
214*4882a593Smuzhiyun 	int error;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	error = sig_read_header(channel, queue, &sig_hdr);
217*4882a593Smuzhiyun 	if (error)
218*4882a593Smuzhiyun 		return error;
219*4882a593Smuzhiyun 	/* No signals to remove; have caller try again. */
220*4882a593Smuzhiyun 	if (sig_hdr.head == sig_hdr.tail)
221*4882a593Smuzhiyun 		return -EAGAIN;
222*4882a593Smuzhiyun 	sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
223*4882a593Smuzhiyun 	error = sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg);
224*4882a593Smuzhiyun 	if (error)
225*4882a593Smuzhiyun 		return error;
226*4882a593Smuzhiyun 	sig_hdr.num_received++;
227*4882a593Smuzhiyun 	/*
228*4882a593Smuzhiyun 	 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
229*4882a593Smuzhiyun 	 * host memory. Required for channel sync.
230*4882a593Smuzhiyun 	 */
231*4882a593Smuzhiyun 	mb();
232*4882a593Smuzhiyun 	error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail);
233*4882a593Smuzhiyun 	if (error)
234*4882a593Smuzhiyun 		return error;
235*4882a593Smuzhiyun 	error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received);
236*4882a593Smuzhiyun 	if (error)
237*4882a593Smuzhiyun 		return error;
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun /**
242*4882a593Smuzhiyun  * visorchannel_signalremove() - removes a message from the designated
243*4882a593Smuzhiyun  *                               channel/queue
244*4882a593Smuzhiyun  * @channel: the channel the message will be removed from
245*4882a593Smuzhiyun  * @queue:   the queue the message will be removed from
246*4882a593Smuzhiyun  * @msg:     the message to remove
247*4882a593Smuzhiyun  *
248*4882a593Smuzhiyun  * Return: integer error code indicating the status of the removal
249*4882a593Smuzhiyun  */
visorchannel_signalremove(struct visorchannel * channel,u32 queue,void * msg)250*4882a593Smuzhiyun int visorchannel_signalremove(struct visorchannel *channel, u32 queue,
251*4882a593Smuzhiyun 			      void *msg)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	int rc;
254*4882a593Smuzhiyun 	unsigned long flags;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (channel->needs_lock) {
257*4882a593Smuzhiyun 		spin_lock_irqsave(&channel->remove_lock, flags);
258*4882a593Smuzhiyun 		rc = signalremove_inner(channel, queue, msg);
259*4882a593Smuzhiyun 		spin_unlock_irqrestore(&channel->remove_lock, flags);
260*4882a593Smuzhiyun 	} else {
261*4882a593Smuzhiyun 		rc = signalremove_inner(channel, queue, msg);
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	return rc;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(visorchannel_signalremove);
267*4882a593Smuzhiyun 
queue_empty(struct visorchannel * channel,u32 queue)268*4882a593Smuzhiyun static bool queue_empty(struct visorchannel *channel, u32 queue)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	struct signal_queue_header sig_hdr;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (sig_read_header(channel, queue, &sig_hdr))
273*4882a593Smuzhiyun 		return true;
274*4882a593Smuzhiyun 	return (sig_hdr.head == sig_hdr.tail);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun /**
278*4882a593Smuzhiyun  * visorchannel_signalempty() - checks if the designated channel/queue contains
279*4882a593Smuzhiyun  *				any messages
280*4882a593Smuzhiyun  * @channel: the channel to query
281*4882a593Smuzhiyun  * @queue:   the queue in the channel to query
282*4882a593Smuzhiyun  *
283*4882a593Smuzhiyun  * Return: boolean indicating whether any messages in the designated
284*4882a593Smuzhiyun  *         channel/queue are present
285*4882a593Smuzhiyun  */
visorchannel_signalempty(struct visorchannel * channel,u32 queue)286*4882a593Smuzhiyun bool visorchannel_signalempty(struct visorchannel *channel, u32 queue)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	bool rc;
289*4882a593Smuzhiyun 	unsigned long flags;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	if (!channel->needs_lock)
292*4882a593Smuzhiyun 		return queue_empty(channel, queue);
293*4882a593Smuzhiyun 	spin_lock_irqsave(&channel->remove_lock, flags);
294*4882a593Smuzhiyun 	rc = queue_empty(channel, queue);
295*4882a593Smuzhiyun 	spin_unlock_irqrestore(&channel->remove_lock, flags);
296*4882a593Smuzhiyun 	return rc;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(visorchannel_signalempty);
299*4882a593Smuzhiyun 
signalinsert_inner(struct visorchannel * channel,u32 queue,void * msg)300*4882a593Smuzhiyun static int signalinsert_inner(struct visorchannel *channel, u32 queue,
301*4882a593Smuzhiyun 			      void *msg)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct signal_queue_header sig_hdr;
304*4882a593Smuzhiyun 	int err;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	err = sig_read_header(channel, queue, &sig_hdr);
307*4882a593Smuzhiyun 	if (err)
308*4882a593Smuzhiyun 		return err;
309*4882a593Smuzhiyun 	sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots;
310*4882a593Smuzhiyun 	if (sig_hdr.head == sig_hdr.tail) {
311*4882a593Smuzhiyun 		sig_hdr.num_overflows++;
312*4882a593Smuzhiyun 		err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows);
313*4882a593Smuzhiyun 		if (err)
314*4882a593Smuzhiyun 			return err;
315*4882a593Smuzhiyun 		return -EIO;
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 	err = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg);
318*4882a593Smuzhiyun 	if (err)
319*4882a593Smuzhiyun 		return err;
320*4882a593Smuzhiyun 	sig_hdr.num_sent++;
321*4882a593Smuzhiyun 	/*
322*4882a593Smuzhiyun 	 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
323*4882a593Smuzhiyun 	 * host memory. Required for channel sync.
324*4882a593Smuzhiyun 	 */
325*4882a593Smuzhiyun 	mb();
326*4882a593Smuzhiyun 	err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, head);
327*4882a593Smuzhiyun 	if (err)
328*4882a593Smuzhiyun 		return err;
329*4882a593Smuzhiyun 	err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent);
330*4882a593Smuzhiyun 	if (err)
331*4882a593Smuzhiyun 		return err;
332*4882a593Smuzhiyun 	return 0;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun /*
336*4882a593Smuzhiyun  * visorchannel_create() - creates the struct visorchannel abstraction for a
337*4882a593Smuzhiyun  *                         data area in memory, but does NOT modify this data
338*4882a593Smuzhiyun  *                         area
339*4882a593Smuzhiyun  * @physaddr:      physical address of start of channel
340*4882a593Smuzhiyun  * @gfp:           gfp_t to use when allocating memory for the data struct
341*4882a593Smuzhiyun  * @guid:          GUID that identifies channel type;
342*4882a593Smuzhiyun  * @needs_lock:    must specify true if you have multiple threads of execution
343*4882a593Smuzhiyun  *                 that will be calling visorchannel methods of this
344*4882a593Smuzhiyun  *                 visorchannel at the same time
345*4882a593Smuzhiyun  *
346*4882a593Smuzhiyun  * Return: pointer to visorchannel that was created if successful,
347*4882a593Smuzhiyun  *         otherwise NULL
348*4882a593Smuzhiyun  */
visorchannel_create(u64 physaddr,gfp_t gfp,const guid_t * guid,bool needs_lock)349*4882a593Smuzhiyun struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp,
350*4882a593Smuzhiyun 					 const guid_t *guid, bool needs_lock)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	struct visorchannel *channel;
353*4882a593Smuzhiyun 	int err;
354*4882a593Smuzhiyun 	size_t size = sizeof(struct channel_header);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (physaddr == 0)
357*4882a593Smuzhiyun 		return NULL;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	channel = kzalloc(sizeof(*channel), gfp);
360*4882a593Smuzhiyun 	if (!channel)
361*4882a593Smuzhiyun 		return NULL;
362*4882a593Smuzhiyun 	channel->needs_lock = needs_lock;
363*4882a593Smuzhiyun 	spin_lock_init(&channel->insert_lock);
364*4882a593Smuzhiyun 	spin_lock_init(&channel->remove_lock);
365*4882a593Smuzhiyun 	/*
366*4882a593Smuzhiyun 	 * Video driver constains the efi framebuffer so it will get a conflict
367*4882a593Smuzhiyun 	 * resource when requesting its full mem region. Since we are only
368*4882a593Smuzhiyun 	 * using the efi framebuffer for video we can ignore this. Remember that
369*4882a593Smuzhiyun 	 * we haven't requested it so we don't try to release later on.
370*4882a593Smuzhiyun 	 */
371*4882a593Smuzhiyun 	channel->requested = request_mem_region(physaddr, size, VISOR_DRV_NAME);
372*4882a593Smuzhiyun 	if (!channel->requested && !guid_equal(guid, &visor_video_guid))
373*4882a593Smuzhiyun 		/* we only care about errors if this is not the video channel */
374*4882a593Smuzhiyun 		goto err_destroy_channel;
375*4882a593Smuzhiyun 	channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
376*4882a593Smuzhiyun 	if (!channel->mapped) {
377*4882a593Smuzhiyun 		release_mem_region(physaddr, size);
378*4882a593Smuzhiyun 		goto err_destroy_channel;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 	channel->physaddr = physaddr;
381*4882a593Smuzhiyun 	channel->nbytes = size;
382*4882a593Smuzhiyun 	err = visorchannel_read(channel, 0, &channel->chan_hdr, size);
383*4882a593Smuzhiyun 	if (err)
384*4882a593Smuzhiyun 		goto err_destroy_channel;
385*4882a593Smuzhiyun 	size = (ulong)channel->chan_hdr.size;
386*4882a593Smuzhiyun 	memunmap(channel->mapped);
387*4882a593Smuzhiyun 	if (channel->requested)
388*4882a593Smuzhiyun 		release_mem_region(channel->physaddr, channel->nbytes);
389*4882a593Smuzhiyun 	channel->mapped = NULL;
390*4882a593Smuzhiyun 	channel->requested = request_mem_region(channel->physaddr, size,
391*4882a593Smuzhiyun 						VISOR_DRV_NAME);
392*4882a593Smuzhiyun 	if (!channel->requested && !guid_equal(guid, &visor_video_guid))
393*4882a593Smuzhiyun 		/* we only care about errors if this is not the video channel */
394*4882a593Smuzhiyun 		goto err_destroy_channel;
395*4882a593Smuzhiyun 	channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB);
396*4882a593Smuzhiyun 	if (!channel->mapped) {
397*4882a593Smuzhiyun 		release_mem_region(channel->physaddr, size);
398*4882a593Smuzhiyun 		goto err_destroy_channel;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 	channel->nbytes = size;
401*4882a593Smuzhiyun 	guid_copy(&channel->guid, guid);
402*4882a593Smuzhiyun 	return channel;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun err_destroy_channel:
405*4882a593Smuzhiyun 	visorchannel_destroy(channel);
406*4882a593Smuzhiyun 	return NULL;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /**
410*4882a593Smuzhiyun  * visorchannel_signalinsert() - inserts a message into the designated
411*4882a593Smuzhiyun  *                               channel/queue
412*4882a593Smuzhiyun  * @channel: the channel the message will be added to
413*4882a593Smuzhiyun  * @queue:   the queue the message will be added to
414*4882a593Smuzhiyun  * @msg:     the message to insert
415*4882a593Smuzhiyun  *
416*4882a593Smuzhiyun  * Return: integer error code indicating the status of the insertion
417*4882a593Smuzhiyun  */
visorchannel_signalinsert(struct visorchannel * channel,u32 queue,void * msg)418*4882a593Smuzhiyun int visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
419*4882a593Smuzhiyun 			      void *msg)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	int rc;
422*4882a593Smuzhiyun 	unsigned long flags;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	if (channel->needs_lock) {
425*4882a593Smuzhiyun 		spin_lock_irqsave(&channel->insert_lock, flags);
426*4882a593Smuzhiyun 		rc = signalinsert_inner(channel, queue, msg);
427*4882a593Smuzhiyun 		spin_unlock_irqrestore(&channel->insert_lock, flags);
428*4882a593Smuzhiyun 	} else {
429*4882a593Smuzhiyun 		rc = signalinsert_inner(channel, queue, msg);
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	return rc;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
435