blob: bd890e0f456b9de3b3ed4d016cbe00fcbf6fd5e2 [file] [log] [blame]
Greg Kroah-Hartmanb79c0f42017-11-07 14:58:47 +01001// SPDX-License-Identifier: GPL-2.0
David Binderfa96c882017-08-22 13:27:27 -04002/*
Benjamin Romer6f14cc12015-07-16 12:40:48 -04003 * Copyright (C) 2010 - 2015 UNISYS CORPORATION
Ken Coxe4238122014-03-04 07:58:06 -06004 * All rights reserved.
Ken Coxe4238122014-03-04 07:58:06 -06005 */
6
7/*
David Bindere19674c2016-06-10 21:48:17 -04008 * This provides s-Par channel communication primitives, which are
Jes Sorensen434cbf22015-05-05 18:37:00 -04009 * independent of the mechanism used to access the channel data.
Ken Coxe4238122014-03-04 07:58:06 -060010 */
11
David Kershner99c805f2015-06-15 23:31:56 -040012#include <linux/uuid.h>
Dan Williams3103dc02015-08-10 23:07:06 -040013#include <linux/io.h>
David Kershnereb6eb1e2017-09-27 13:14:29 -040014#include <linux/slab.h>
David Kershner93d3ad92017-12-07 12:11:07 -050015#include <linux/visorbus.h>
David Kershner99c805f2015-06-15 23:31:56 -040016
Laurent Navetae719092016-10-15 11:50:11 +020017#include "visorbus_private.h"
Don Zickus1fb30162015-05-13 13:22:18 -040018#include "controlvmchannel.h"
Ken Coxe4238122014-03-04 07:58:06 -060019
David Binderb35fae72017-06-30 15:43:17 -040020#define VISOR_DRV_NAME "visorchannel"
Ken Coxe4238122014-03-04 07:58:06 -060021
Sameer Wadgaonkar2b8ec7d2017-05-19 16:17:46 -040022#define VISOR_CONSOLEVIDEO_CHANNEL_GUID \
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040023 GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \
24 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)
David Binderc2a60102017-03-17 11:27:17 -040025
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040026static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID;
David Kershner99c805f2015-06-15 23:31:56 -040027
Bryan Thompson383df642014-12-05 17:09:25 -050028struct visorchannel {
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -040029 u64 physaddr;
Jes Sorensen434cbf22015-05-05 18:37:00 -040030 ulong nbytes;
Dan Williams3103dc02015-08-10 23:07:06 -040031 void *mapped;
David Kershner99c805f2015-06-15 23:31:56 -040032 bool requested;
Benjamin Romer9fd1b952014-10-23 14:29:55 -040033 struct channel_header chan_hdr;
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040034 guid_t guid;
Sameer Wadgaonkar0496bed2017-06-30 15:43:07 -040035 /*
David Kershnercbe7e022017-09-27 13:14:09 -040036 * channel creator knows if more than one thread will be inserting or
37 * removing
Sameer Wadgaonkar0496bed2017-06-30 15:43:07 -040038 */
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;
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040044 guid_t type;
45 guid_t inst;
Ken Coxe4238122014-03-04 07:58:06 -060046};
47
Charles Danielsf230ba62017-07-17 16:17:18 -040048void visorchannel_destroy(struct visorchannel *channel)
Ken Coxe4238122014-03-04 07:58:06 -060049{
Benjamin Romerfc11a552015-03-16 13:57:44 -040050 if (!channel)
Ken Coxe4238122014-03-04 07:58:06 -060051 return;
David Kershnera3b726c2017-09-27 13:14:25 -040052
Jes Sorensen434cbf22015-05-05 18:37:00 -040053 if (channel->mapped) {
Dan Williams3103dc02015-08-10 23:07:06 -040054 memunmap(channel->mapped);
David Kershner99c805f2015-06-15 23:31:56 -040055 if (channel->requested)
56 release_mem_region(channel->physaddr, channel->nbytes);
Jes Sorensen0dbb3fb2015-05-05 18:36:50 -040057 }
Ken Coxe4238122014-03-04 07:58:06 -060058 kfree(channel);
59}
Ken Coxe4238122014-03-04 07:58:06 -060060
Charles Danielsf230ba62017-07-17 16:17:18 -040061u64 visorchannel_get_physaddr(struct visorchannel *channel)
Ken Coxe4238122014-03-04 07:58:06 -060062{
Jes Sorensen434cbf22015-05-05 18:37:00 -040063 return channel->physaddr;
Ken Coxe4238122014-03-04 07:58:06 -060064}
Ken Coxe4238122014-03-04 07:58:06 -060065
Charles Danielsf230ba62017-07-17 16:17:18 -040066ulong visorchannel_get_nbytes(struct visorchannel *channel)
Ken Coxe4238122014-03-04 07:58:06 -060067{
David Binder2b9bcf82016-04-04 23:31:32 -040068 return channel->nbytes;
Ken Coxe4238122014-03-04 07:58:06 -060069}
Ken Coxe4238122014-03-04 07:58:06 -060070
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040071char *visorchannel_guid_id(const guid_t *guid, char *s)
Ken Coxe4238122014-03-04 07:58:06 -060072{
Benjamin Romer90addb02014-05-06 09:58:23 -040073 sprintf(s, "%pUL", guid);
74 return s;
Ken Coxe4238122014-03-04 07:58:06 -060075}
Ken Coxe4238122014-03-04 07:58:06 -060076
Charles Danielsf230ba62017-07-17 16:17:18 -040077char *visorchannel_id(struct visorchannel *channel, char *s)
Ken Coxe4238122014-03-04 07:58:06 -060078{
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040079 return visorchannel_guid_id(&channel->guid, s);
Ken Coxe4238122014-03-04 07:58:06 -060080}
Ken Coxe4238122014-03-04 07:58:06 -060081
Charles Danielsf230ba62017-07-17 16:17:18 -040082char *visorchannel_zoneid(struct visorchannel *channel, char *s)
Ken Coxe4238122014-03-04 07:58:06 -060083{
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -040084 return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s);
Ken Coxe4238122014-03-04 07:58:06 -060085}
Ken Coxe4238122014-03-04 07:58:06 -060086
Charles Danielsf230ba62017-07-17 16:17:18 -040087u64 visorchannel_get_clientpartition(struct visorchannel *channel)
Ken Coxe4238122014-03-04 07:58:06 -060088{
Benjamin Romera8a31f62014-10-23 14:29:56 -040089 return channel->chan_hdr.partition_handle;
Ken Coxe4238122014-03-04 07:58:06 -060090}
Ken Coxe4238122014-03-04 07:58:06 -060091
Charles Danielsf230ba62017-07-17 16:17:18 -040092int visorchannel_set_clientpartition(struct visorchannel *channel,
93 u64 partition_handle)
Don Zickus4f6d8a92015-05-13 13:22:20 -040094{
95 channel->chan_hdr.partition_handle = partition_handle;
96 return 0;
97}
Don Zickus4f6d8a92015-05-13 13:22:20 -040098
David Bindere19674c2016-06-10 21:48:17 -040099/**
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400100 * visorchannel_get_guid() - queries the GUID of the designated channel
David Bindere19674c2016-06-10 21:48:17 -0400101 * @channel: the channel to query
102 *
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400103 * Return: the GUID of the provided channel
David Bindere19674c2016-06-10 21:48:17 -0400104 */
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400105const guid_t *visorchannel_get_guid(struct visorchannel *channel)
Ken Coxe4238122014-03-04 07:58:06 -0600106{
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400107 return &channel->guid;
Ken Coxe4238122014-03-04 07:58:06 -0600108}
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400109EXPORT_SYMBOL_GPL(visorchannel_get_guid);
Ken Coxe4238122014-03-04 07:58:06 -0600110
Charles Danielsf230ba62017-07-17 16:17:18 -0400111int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest,
112 ulong nbytes)
Ken Coxe4238122014-03-04 07:58:06 -0600113{
Jes Sorensen434cbf22015-05-05 18:37:00 -0400114 if (offset + nbytes > channel->nbytes)
Jes Sorensen36203e72015-05-05 18:36:55 -0400115 return -EIO;
Prarit Bhargava69141bb2015-05-05 18:36:18 -0400116
Erik Arfvidson8c3c1e42016-11-21 12:15:42 -0500117 memcpy(dest, channel->mapped + offset, nbytes);
Jes Sorensen36203e72015-05-05 18:36:55 -0400118 return 0;
Ken Coxe4238122014-03-04 07:58:06 -0600119}
Ken Coxe4238122014-03-04 07:58:06 -0600120
Charles Danielsf230ba62017-07-17 16:17:18 -0400121int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest,
122 ulong nbytes)
Ken Coxe4238122014-03-04 07:58:06 -0600123{
Jes Sorensen0abb60c2015-05-05 18:36:56 -0400124 size_t chdr_size = sizeof(struct channel_header);
125 size_t copy_size;
Prarit Bhargava69141bb2015-05-05 18:36:18 -0400126
Jes Sorensen434cbf22015-05-05 18:37:00 -0400127 if (offset + nbytes > channel->nbytes)
Jes Sorensenad440882015-05-05 18:36:54 -0400128 return -EIO;
129
Jes Sorensen0abb60c2015-05-05 18:36:56 -0400130 if (offset < chdr_size) {
Jes Sorensen56df9002015-06-16 09:13:33 -0400131 copy_size = min(chdr_size - offset, nbytes);
Tim Selld2530582015-07-13 14:51:24 -0400132 memcpy(((char *)(&channel->chan_hdr)) + offset,
Erik Arfvidson8c3c1e42016-11-21 12:15:42 -0500133 dest, copy_size);
Jes Sorensen0abb60c2015-05-05 18:36:56 -0400134 }
Erik Arfvidson8c3c1e42016-11-21 12:15:42 -0500135 memcpy(channel->mapped + offset, dest, nbytes);
Jes Sorensenad440882015-05-05 18:36:54 -0400136 return 0;
Ken Coxe4238122014-03-04 07:58:06 -0600137}
Ken Coxe4238122014-03-04 07:58:06 -0600138
Charles Danielsf230ba62017-07-17 16:17:18 -0400139void *visorchannel_get_header(struct visorchannel *channel)
Ken Coxe4238122014-03-04 07:58:06 -0600140{
David Binder5da77f32017-03-17 11:27:11 -0400141 return &channel->chan_hdr;
Ken Coxe4238122014-03-04 07:58:06 -0600142}
Ken Coxe4238122014-03-04 07:58:06 -0600143
David Bindere19674c2016-06-10 21:48:17 -0400144/*
145 * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
146 * channel header
Ken Coxe4238122014-03-04 07:58:06 -0600147 */
Colin Ian Kingbc05a9c2017-09-01 11:08:10 +0100148static int sig_queue_offset(struct channel_header *chan_hdr, int q)
David Kershnerc0616452017-08-30 13:36:15 -0400149{
150 return ((chan_hdr)->ch_space_offset +
151 ((q) * sizeof(struct signal_queue_header)));
152}
Ken Coxe4238122014-03-04 07:58:06 -0600153
David Bindere19674c2016-06-10 21:48:17 -0400154/*
155 * Return offset of a specific queue entry (data) from the beginning of a
156 * channel header
Ken Coxe4238122014-03-04 07:58:06 -0600157 */
Colin Ian Kingbc05a9c2017-09-01 11:08:10 +0100158static int sig_data_offset(struct channel_header *chan_hdr, int q,
159 struct signal_queue_header *sig_hdr, int slot)
David Kershnerc0616452017-08-30 13:36:15 -0400160{
161 return (sig_queue_offset(chan_hdr, q) + sig_hdr->sig_base_offset +
162 (slot * sig_hdr->signal_size));
163}
Ken Coxe4238122014-03-04 07:58:06 -0600164
David Bindere19674c2016-06-10 21:48:17 -0400165/*
David Kershnercbe7e022017-09-27 13:14:09 -0400166 * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back into
167 * host memory
Ken Coxe4238122014-03-04 07:58:06 -0600168 */
David Binderc2a60102017-03-17 11:27:17 -0400169#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
170 visorchannel_write(channel, \
David Kershnerc0616452017-08-30 13:36:15 -0400171 sig_queue_offset(&channel->chan_hdr, queue) + \
David Binder1306c422016-09-26 11:03:47 -0400172 offsetof(struct signal_queue_header, FIELD), \
David Binderc2a60102017-03-17 11:27:17 -0400173 &((sig_hdr)->FIELD), \
David Binder1306c422016-09-26 11:03:47 -0400174 sizeof((sig_hdr)->FIELD))
Ken Coxe4238122014-03-04 07:58:06 -0600175
Charles Danielsf230ba62017-07-17 16:17:18 -0400176static int sig_read_header(struct visorchannel *channel, u32 queue,
177 struct signal_queue_header *sig_hdr)
Ken Coxe4238122014-03-04 07:58:06 -0600178{
Benjamin Romer0aca78442015-03-04 12:14:25 -0500179 if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
David Binder1306c422016-09-26 11:03:47 -0400180 return -EINVAL;
Ken Coxe4238122014-03-04 07:58:06 -0600181
182 /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
David Binder1306c422016-09-26 11:03:47 -0400183 return visorchannel_read(channel,
David Kershnerc0616452017-08-30 13:36:15 -0400184 sig_queue_offset(&channel->chan_hdr, queue),
David Binder1306c422016-09-26 11:03:47 -0400185 sig_hdr, sizeof(struct signal_queue_header));
Ken Coxe4238122014-03-04 07:58:06 -0600186}
187
Charles Danielsf230ba62017-07-17 16:17:18 -0400188static int sig_read_data(struct visorchannel *channel, u32 queue,
189 struct signal_queue_header *sig_hdr, u32 slot,
190 void *data)
Ken Coxe4238122014-03-04 07:58:06 -0600191{
David Kershnerc0616452017-08-30 13:36:15 -0400192 int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
Prarit Bhargavaa4ed0ba2015-05-05 18:36:19 -0400193 sig_hdr, slot);
194
David Binder1306c422016-09-26 11:03:47 -0400195 return visorchannel_read(channel, signal_data_offset,
196 data, sig_hdr->signal_size);
Ken Coxe4238122014-03-04 07:58:06 -0600197}
198
Charles Danielsf230ba62017-07-17 16:17:18 -0400199static int sig_write_data(struct visorchannel *channel, u32 queue,
200 struct signal_queue_header *sig_hdr, u32 slot,
201 void *data)
Ken Coxe4238122014-03-04 07:58:06 -0600202{
David Kershnerc0616452017-08-30 13:36:15 -0400203 int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
Prarit Bhargavaa4ed0ba2015-05-05 18:36:19 -0400204 sig_hdr, slot);
205
David Binder1306c422016-09-26 11:03:47 -0400206 return visorchannel_write(channel, signal_data_offset,
207 data, sig_hdr->signal_size);
Ken Coxe4238122014-03-04 07:58:06 -0600208}
209
Charles Danielsf230ba62017-07-17 16:17:18 -0400210static int signalremove_inner(struct visorchannel *channel, u32 queue,
211 void *msg)
Ken Coxe4238122014-03-04 07:58:06 -0600212{
Benjamin Romere0fed862014-10-23 14:30:03 -0400213 struct signal_queue_header sig_hdr;
David Binder1306c422016-09-26 11:03:47 -0400214 int error;
Ken Coxe4238122014-03-04 07:58:06 -0600215
David Binder1306c422016-09-26 11:03:47 -0400216 error = sig_read_header(channel, queue, &sig_hdr);
217 if (error)
218 return error;
David Kershner5d295bc2016-11-21 12:15:52 -0500219 /* No signals to remove; have caller try again. */
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100220 if (sig_hdr.head == sig_hdr.tail)
David Kershner5d295bc2016-11-21 12:15:52 -0500221 return -EAGAIN;
Benjamin Romer153cf712014-10-23 14:30:04 -0400222 sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
David Binder1306c422016-09-26 11:03:47 -0400223 error = sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg);
224 if (error)
225 return error;
Benjamin Romer153cf712014-10-23 14:30:04 -0400226 sig_hdr.num_received++;
David Bindere19674c2016-06-10 21:48:17 -0400227 /*
David Kershnercbe7e022017-09-27 13:14:09 -0400228 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
229 * host memory. Required for channel sync.
Ken Coxe4238122014-03-04 07:58:06 -0600230 */
Sameer Wadgaonkar0496bed2017-06-30 15:43:07 -0400231 mb();
David Binder1306c422016-09-26 11:03:47 -0400232 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;
David Binder1306c422016-09-26 11:03:47 -0400238 return 0;
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100239}
240
David Bindere19674c2016-06-10 21:48:17 -0400241/**
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 *
David Binderf621a962016-09-26 11:03:48 -0400248 * Return: integer error code indicating the status of the removal
David Bindere19674c2016-06-10 21:48:17 -0400249 */
Charles Danielsf230ba62017-07-17 16:17:18 -0400250int visorchannel_signalremove(struct visorchannel *channel, u32 queue,
251 void *msg)
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100252{
David Binderf621a962016-09-26 11:03:48 -0400253 int rc;
Tim Sell24ac1072015-07-14 14:43:30 -0400254 unsigned long flags;
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100255
256 if (channel->needs_lock) {
Tim Sell24ac1072015-07-14 14:43:30 -0400257 spin_lock_irqsave(&channel->remove_lock, flags);
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100258 rc = signalremove_inner(channel, queue, msg);
Tim Sell24ac1072015-07-14 14:43:30 -0400259 spin_unlock_irqrestore(&channel->remove_lock, flags);
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100260 } else {
261 rc = signalremove_inner(channel, queue, msg);
262 }
Ken Coxe4238122014-03-04 07:58:06 -0600263
David Binderf621a962016-09-26 11:03:48 -0400264 return rc;
Ken Coxe4238122014-03-04 07:58:06 -0600265}
266EXPORT_SYMBOL_GPL(visorchannel_signalremove);
267
Charles Danielsf230ba62017-07-17 16:17:18 -0400268static bool queue_empty(struct visorchannel *channel, u32 queue)
Cathal Mullaneyf0208b72016-10-19 22:43:25 +0100269{
270 struct signal_queue_header sig_hdr;
271
272 if (sig_read_header(channel, queue, &sig_hdr))
273 return true;
Cathal Mullaneyf0208b72016-10-19 22:43:25 +0100274 return (sig_hdr.head == sig_hdr.tail);
275}
276
David Binder7ec83df2017-02-21 12:53:20 -0500277/**
David Kershnercbe7e022017-09-27 13:14:09 -0400278 * visorchannel_signalempty() - checks if the designated channel/queue contains
279 * any messages
David Binder7ec83df2017-02-21 12:53:20 -0500280 * @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 */
Charles Danielsf230ba62017-07-17 16:17:18 -0400286bool visorchannel_signalempty(struct visorchannel *channel, u32 queue)
Neil Hormanfdc792c2015-07-31 18:56:32 -0400287{
Cathal Mullaneyf0208b72016-10-19 22:43:25 +0100288 bool rc;
289 unsigned long flags;
Neil Hormanfdc792c2015-07-31 18:56:32 -0400290
Cathal Mullaneyf0208b72016-10-19 22:43:25 +0100291 if (!channel->needs_lock)
292 return queue_empty(channel, queue);
Cathal Mullaneyf0208b72016-10-19 22:43:25 +0100293 spin_lock_irqsave(&channel->remove_lock, flags);
294 rc = queue_empty(channel, queue);
295 spin_unlock_irqrestore(&channel->remove_lock, flags);
Neil Hormanfdc792c2015-07-31 18:56:32 -0400296 return rc;
297}
298EXPORT_SYMBOL_GPL(visorchannel_signalempty);
299
Charles Danielsf230ba62017-07-17 16:17:18 -0400300static int signalinsert_inner(struct visorchannel *channel, u32 queue,
301 void *msg)
Ken Coxe4238122014-03-04 07:58:06 -0600302{
Benjamin Romere0fed862014-10-23 14:30:03 -0400303 struct signal_queue_header sig_hdr;
David Kershner9b2cae62017-04-18 16:55:07 -0400304 int err;
Ken Coxe4238122014-03-04 07:58:06 -0600305
David Kershner9b2cae62017-04-18 16:55:07 -0400306 err = sig_read_header(channel, queue, &sig_hdr);
307 if (err)
308 return err;
Janani Ravichandran90cb1472016-02-09 14:02:04 -0500309 sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots;
Benjamin Romer153cf712014-10-23 14:30:04 -0400310 if (sig_hdr.head == sig_hdr.tail) {
311 sig_hdr.num_overflows++;
David Kershner9b2cae62017-04-18 16:55:07 -0400312 err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows);
313 if (err)
314 return err;
David Binder1306c422016-09-26 11:03:47 -0400315 return -EIO;
Ken Coxe4238122014-03-04 07:58:06 -0600316 }
David Kershner9b2cae62017-04-18 16:55:07 -0400317 err = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg);
318 if (err)
319 return err;
Benjamin Romer153cf712014-10-23 14:30:04 -0400320 sig_hdr.num_sent++;
David Bindere19674c2016-06-10 21:48:17 -0400321 /*
David Kershnercbe7e022017-09-27 13:14:09 -0400322 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
323 * host memory. Required for channel sync.
Ken Coxe4238122014-03-04 07:58:06 -0600324 */
Sameer Wadgaonkar0496bed2017-06-30 15:43:07 -0400325 mb();
David Kershner9b2cae62017-04-18 16:55:07 -0400326 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;
David Binder1306c422016-09-26 11:03:47 -0400332 return 0;
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100333}
334
David Binder3a8bc4b2017-02-21 12:53:23 -0500335/*
Sameer Wadgaonkar90476672017-09-27 13:14:44 -0400336 * visorchannel_create() - creates the struct visorchannel abstraction for a
337 * data area in memory, but does NOT modify this data
338 * area
David Kershner3995c5d2016-09-02 16:41:38 -0400339 * @physaddr: physical address of start of channel
David Kershner3995c5d2016-09-02 16:41:38 -0400340 * @gfp: gfp_t to use when allocating memory for the data struct
David Kershnerd7f15892017-08-30 13:36:31 -0400341 * @guid: GUID that identifies channel type;
David Kershner3995c5d2016-09-02 16:41:38 -0400342 * @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 */
Sameer Wadgaonkar90476672017-09-27 13:14:44 -0400349struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp,
350 const guid_t *guid, bool needs_lock)
David Kershner3995c5d2016-09-02 16:41:38 -0400351{
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;
David Kershner3995c5d2016-09-02 16:41:38 -0400362 channel->needs_lock = needs_lock;
363 spin_lock_init(&channel->insert_lock);
364 spin_lock_init(&channel->remove_lock);
David Kershner3995c5d2016-09-02 16:41:38 -0400365 /*
David Kershnercbe7e022017-09-27 13:14:09 -0400366 * 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.
David Kershner3995c5d2016-09-02 16:41:38 -0400370 */
David Binderb35fae72017-06-30 15:43:17 -0400371 channel->requested = request_mem_region(physaddr, size, VISOR_DRV_NAME);
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400372 if (!channel->requested && !guid_equal(guid, &visor_video_guid))
David Kershner51646f42017-03-28 09:34:56 -0400373 /* we only care about errors if this is not the video channel */
374 goto err_destroy_channel;
David Kershner3995c5d2016-09-02 16:41:38 -0400375 channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
376 if (!channel->mapped) {
377 release_mem_region(physaddr, size);
378 goto err_destroy_channel;
379 }
David Kershner3995c5d2016-09-02 16:41:38 -0400380 channel->physaddr = physaddr;
381 channel->nbytes = size;
David Kershnerd7f15892017-08-30 13:36:31 -0400382 err = visorchannel_read(channel, 0, &channel->chan_hdr, size);
David Kershner3995c5d2016-09-02 16:41:38 -0400383 if (err)
384 goto err_destroy_channel;
David Kershnerd7f15892017-08-30 13:36:31 -0400385 size = (ulong)channel->chan_hdr.size;
David Kershner3995c5d2016-09-02 16:41:38 -0400386 memunmap(channel->mapped);
387 if (channel->requested)
388 release_mem_region(channel->physaddr, channel->nbytes);
389 channel->mapped = NULL;
David Kershnerd7f15892017-08-30 13:36:31 -0400390 channel->requested = request_mem_region(channel->physaddr, size,
391 VISOR_DRV_NAME);
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400392 if (!channel->requested && !guid_equal(guid, &visor_video_guid))
David Kershner51646f42017-03-28 09:34:56 -0400393 /* we only care about errors if this is not the video channel */
394 goto err_destroy_channel;
David Kershnerd7f15892017-08-30 13:36:31 -0400395 channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB);
David Kershner3995c5d2016-09-02 16:41:38 -0400396 if (!channel->mapped) {
David Kershnerd7f15892017-08-30 13:36:31 -0400397 release_mem_region(channel->physaddr, size);
David Kershner3995c5d2016-09-02 16:41:38 -0400398 goto err_destroy_channel;
399 }
David Kershnerd7f15892017-08-30 13:36:31 -0400400 channel->nbytes = size;
Andy Shevchenkob32c5cb2017-08-22 13:26:54 -0400401 guid_copy(&channel->guid, guid);
David Kershner3995c5d2016-09-02 16:41:38 -0400402 return channel;
403
404err_destroy_channel:
405 visorchannel_destroy(channel);
406 return NULL;
407}
408
David Kershner3995c5d2016-09-02 16:41:38 -0400409/**
David Bindere19674c2016-06-10 21:48:17 -0400410 * 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 *
David Binder264f7b82016-09-26 11:03:49 -0400416 * Return: integer error code indicating the status of the insertion
David Bindere19674c2016-06-10 21:48:17 -0400417 */
Charles Danielsf230ba62017-07-17 16:17:18 -0400418int visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
419 void *msg)
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100420{
David Binder264f7b82016-09-26 11:03:49 -0400421 int rc;
Tim Sell24ac1072015-07-14 14:43:30 -0400422 unsigned long flags;
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100423
424 if (channel->needs_lock) {
Tim Sell24ac1072015-07-14 14:43:30 -0400425 spin_lock_irqsave(&channel->insert_lock, flags);
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100426 rc = signalinsert_inner(channel, queue, msg);
Tim Sell24ac1072015-07-14 14:43:30 -0400427 spin_unlock_irqrestore(&channel->insert_lock, flags);
Zachary Warrenb12fdf72015-01-17 22:39:53 +1100428 } else {
429 rc = signalinsert_inner(channel, queue, msg);
430 }
Ken Coxe4238122014-03-04 07:58:06 -0600431
David Binder264f7b82016-09-26 11:03:49 -0400432 return rc;
Ken Coxe4238122014-03-04 07:58:06 -0600433}
434EXPORT_SYMBOL_GPL(visorchannel_signalinsert);