Linux Audio

Check our new training course

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