powerpc/mm: Drop the unnecessary region check
[linux-2.6-block.git] / drivers / visorbus / visorchannel.c
CommitLineData
b79c0f4f 1// SPDX-License-Identifier: GPL-2.0
fa96c883 2/*
6f14cc18 3 * Copyright (C) 2010 - 2015 UNISYS CORPORATION
e423812a 4 * All rights reserved.
e423812a
KC
5 */
6
7/*
e19674ce 8 * This provides s-Par channel communication primitives, which are
434cbf28 9 * independent of the mechanism used to access the channel data.
e423812a
KC
10 */
11
99c805f4 12#include <linux/uuid.h>
3103dc03 13#include <linux/io.h>
eb6eb1e1 14#include <linux/slab.h>
93d3ad90 15#include <linux/visorbus.h>
99c805f4 16
ae719092 17#include "visorbus_private.h"
1fb3016e 18#include "controlvmchannel.h"
e423812a 19
b35fae7e 20#define VISOR_DRV_NAME "visorchannel"
e423812a 21
2b8ec7da 22#define VISOR_CONSOLEVIDEO_CHANNEL_GUID \
b32c5cb8
AS
23 GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \
24 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)
c2a60109 25
b32c5cb8 26static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID;
99c805f4 27
383df64e 28struct visorchannel {
d5b3f1dc 29 u64 physaddr;
434cbf28 30 ulong nbytes;
3103dc03 31 void *mapped;
99c805f4 32 bool requested;
9fd1b95a 33 struct channel_header chan_hdr;
b32c5cb8 34 guid_t guid;
0496bedf 35 /*
cbe7e02f
DK
36 * channel creator knows if more than one thread will be inserting or
37 * removing
0496bedf
SW
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;
b32c5cb8
AS
44 guid_t type;
45 guid_t inst;
e423812a
KC
46};
47
f230ba68 48void visorchannel_destroy(struct visorchannel *channel)
e423812a 49{
fc11a550 50 if (!channel)
e423812a 51 return;
a3b726c1 52
434cbf28 53 if (channel->mapped) {
3103dc03 54 memunmap(channel->mapped);
99c805f4
DK
55 if (channel->requested)
56 release_mem_region(channel->physaddr, channel->nbytes);
0dbb3fb6 57 }
e423812a
KC
58 kfree(channel);
59}
e423812a 60
f230ba68 61u64 visorchannel_get_physaddr(struct visorchannel *channel)
e423812a 62{
434cbf28 63 return channel->physaddr;
e423812a 64}
e423812a 65
f230ba68 66ulong visorchannel_get_nbytes(struct visorchannel *channel)
e423812a 67{
2b9bcf81 68 return channel->nbytes;
e423812a 69}
e423812a 70
b32c5cb8 71char *visorchannel_guid_id(const guid_t *guid, char *s)
e423812a 72{
90addb02
BR
73 sprintf(s, "%pUL", guid);
74 return s;
e423812a 75}
e423812a 76
f230ba68 77char *visorchannel_id(struct visorchannel *channel, char *s)
e423812a 78{
b32c5cb8 79 return visorchannel_guid_id(&channel->guid, s);
e423812a 80}
e423812a 81
f230ba68 82char *visorchannel_zoneid(struct visorchannel *channel, char *s)
e423812a 83{
b32c5cb8 84 return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s);
e423812a 85}
e423812a 86
f230ba68 87u64 visorchannel_get_clientpartition(struct visorchannel *channel)
e423812a 88{
a8a31f61 89 return channel->chan_hdr.partition_handle;
e423812a 90}
e423812a 91
f230ba68
CD
92int visorchannel_set_clientpartition(struct visorchannel *channel,
93 u64 partition_handle)
4f6d8a97
DZ
94{
95 channel->chan_hdr.partition_handle = partition_handle;
96 return 0;
97}
4f6d8a97 98
e19674ce 99/**
b32c5cb8 100 * visorchannel_get_guid() - queries the GUID of the designated channel
e19674ce
DB
101 * @channel: the channel to query
102 *
b32c5cb8 103 * Return: the GUID of the provided channel
e19674ce 104 */
b32c5cb8 105const guid_t *visorchannel_get_guid(struct visorchannel *channel)
e423812a 106{
b32c5cb8 107 return &channel->guid;
e423812a 108}
b32c5cb8 109EXPORT_SYMBOL_GPL(visorchannel_get_guid);
e423812a 110
f230ba68
CD
111int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest,
112 ulong nbytes)
e423812a 113{
434cbf28 114 if (offset + nbytes > channel->nbytes)
36203e71
JS
115 return -EIO;
116
8c3c1e47 117 memcpy(dest, channel->mapped + offset, nbytes);
36203e71 118 return 0;
e423812a 119}
e423812a 120
f230ba68
CD
121int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest,
122 ulong nbytes)
e423812a 123{
0abb60c1
JS
124 size_t chdr_size = sizeof(struct channel_header);
125 size_t copy_size;
69141bb8 126
434cbf28 127 if (offset + nbytes > channel->nbytes)
ad44088f
JS
128 return -EIO;
129
0abb60c1 130 if (offset < chdr_size) {
56df900c 131 copy_size = min(chdr_size - offset, nbytes);
d253058f 132 memcpy(((char *)(&channel->chan_hdr)) + offset,
8c3c1e47 133 dest, copy_size);
0abb60c1 134 }
8c3c1e47 135 memcpy(channel->mapped + offset, dest, nbytes);
ad44088f 136 return 0;
e423812a 137}
e423812a 138
f230ba68 139void *visorchannel_get_header(struct visorchannel *channel)
e423812a 140{
5da77f37 141 return &channel->chan_hdr;
e423812a 142}
e423812a 143
e19674ce
DB
144/*
145 * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
146 * channel header
e423812a 147 */
bc05a9c8 148static int sig_queue_offset(struct channel_header *chan_hdr, int q)
c0616454
DK
149{
150 return ((chan_hdr)->ch_space_offset +
151 ((q) * sizeof(struct signal_queue_header)));
152}
e423812a 153
e19674ce
DB
154/*
155 * Return offset of a specific queue entry (data) from the beginning of a
156 * channel header
e423812a 157 */
bc05a9c8
CIK
158static int sig_data_offset(struct channel_header *chan_hdr, int q,
159 struct signal_queue_header *sig_hdr, int slot)
c0616454
DK
160{
161 return (sig_queue_offset(chan_hdr, q) + sig_hdr->sig_base_offset +
162 (slot * sig_hdr->signal_size));
163}
e423812a 164
e19674ce 165/*
cbe7e02f
DK
166 * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back into
167 * host memory
e423812a 168 */
c2a60109
DB
169#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
170 visorchannel_write(channel, \
c0616454 171 sig_queue_offset(&channel->chan_hdr, queue) + \
1306c429 172 offsetof(struct signal_queue_header, FIELD), \
c2a60109 173 &((sig_hdr)->FIELD), \
1306c429 174 sizeof((sig_hdr)->FIELD))
e423812a 175
f230ba68
CD
176static int sig_read_header(struct visorchannel *channel, u32 queue,
177 struct signal_queue_header *sig_hdr)
e423812a 178{
0aca7844 179 if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
1306c429 180 return -EINVAL;
e423812a
KC
181
182 /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
1306c429 183 return visorchannel_read(channel,
c0616454 184 sig_queue_offset(&channel->chan_hdr, queue),
1306c429 185 sig_hdr, sizeof(struct signal_queue_header));
e423812a
KC
186}
187
f230ba68
CD
188static int sig_read_data(struct visorchannel *channel, u32 queue,
189 struct signal_queue_header *sig_hdr, u32 slot,
190 void *data)
e423812a 191{
c0616454 192 int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
e423812a 193 sig_hdr, slot);
e423812a 194
1306c429
DB
195 return visorchannel_read(channel, signal_data_offset,
196 data, sig_hdr->signal_size);
e423812a
KC
197}
198
f230ba68
CD
199static int sig_write_data(struct visorchannel *channel, u32 queue,
200 struct signal_queue_header *sig_hdr, u32 slot,
201 void *data)
e423812a 202{
c0616454 203 int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
a4ed0ba9
PB
204 sig_hdr, slot);
205
1306c429
DB
206 return visorchannel_write(channel, signal_data_offset,
207 data, sig_hdr->signal_size);
e423812a
KC
208}
209
f230ba68
CD
210static int signalremove_inner(struct visorchannel *channel, u32 queue,
211 void *msg)
e423812a 212{
e0fed862 213 struct signal_queue_header sig_hdr;
1306c429
DB
214 int error;
215
216 error = sig_read_header(channel, queue, &sig_hdr);
217 if (error)
218 return error;
5d295bc3 219 /* No signals to remove; have caller try again. */
b12fdf7d 220 if (sig_hdr.head == sig_hdr.tail)
5d295bc3 221 return -EAGAIN;
153cf710 222 sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
1306c429
DB
223 error = sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg);
224 if (error)
225 return error;
153cf710 226 sig_hdr.num_received++;
e19674ce 227 /*
cbe7e02f
DK
228 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
229 * host memory. Required for channel sync.
e423812a 230 */
0496bedf 231 mb();
1306c429
DB
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;
1306c429 238 return 0;
b12fdf7d
ZW
239}
240
e19674ce
DB
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 *
f621a968 248 * Return: integer error code indicating the status of the removal
e19674ce 249 */
f230ba68
CD
250int visorchannel_signalremove(struct visorchannel *channel, u32 queue,
251 void *msg)
b12fdf7d 252{
f621a968 253 int rc;
24ac1074 254 unsigned long flags;
b12fdf7d
ZW
255
256 if (channel->needs_lock) {
24ac1074 257 spin_lock_irqsave(&channel->remove_lock, flags);
b12fdf7d 258 rc = signalremove_inner(channel, queue, msg);
24ac1074 259 spin_unlock_irqrestore(&channel->remove_lock, flags);
b12fdf7d
ZW
260 } else {
261 rc = signalremove_inner(channel, queue, msg);
262 }
e423812a 263
f621a968 264 return rc;
e423812a
KC
265}
266EXPORT_SYMBOL_GPL(visorchannel_signalremove);
267
f230ba68 268static bool queue_empty(struct visorchannel *channel, u32 queue)
f0208b71
CM
269{
270 struct signal_queue_header sig_hdr;
271
272 if (sig_read_header(channel, queue, &sig_hdr))
273 return true;
f0208b71
CM
274 return (sig_hdr.head == sig_hdr.tail);
275}
276
7ec83df0 277/**
cbe7e02f
DK
278 * visorchannel_signalempty() - checks if the designated channel/queue contains
279 * any messages
7ec83df0
DB
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 */
f230ba68 286bool visorchannel_signalempty(struct visorchannel *channel, u32 queue)
fdc792cd 287{
f0208b71
CM
288 bool rc;
289 unsigned long flags;
fdc792cd 290
f0208b71
CM
291 if (!channel->needs_lock)
292 return queue_empty(channel, queue);
f0208b71
CM
293 spin_lock_irqsave(&channel->remove_lock, flags);
294 rc = queue_empty(channel, queue);
295 spin_unlock_irqrestore(&channel->remove_lock, flags);
fdc792cd
NH
296 return rc;
297}
298EXPORT_SYMBOL_GPL(visorchannel_signalempty);
299
f230ba68
CD
300static int signalinsert_inner(struct visorchannel *channel, u32 queue,
301 void *msg)
e423812a 302{
e0fed862 303 struct signal_queue_header sig_hdr;
9b2cae6d 304 int err;
e423812a 305
9b2cae6d
DK
306 err = sig_read_header(channel, queue, &sig_hdr);
307 if (err)
308 return err;
90cb147f 309 sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots;
153cf710
BR
310 if (sig_hdr.head == sig_hdr.tail) {
311 sig_hdr.num_overflows++;
9b2cae6d
DK
312 err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows);
313 if (err)
314 return err;
1306c429 315 return -EIO;
e423812a 316 }
9b2cae6d
DK
317 err = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg);
318 if (err)
319 return err;
153cf710 320 sig_hdr.num_sent++;
e19674ce 321 /*
cbe7e02f
DK
322 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
323 * host memory. Required for channel sync.
e423812a 324 */
0496bedf 325 mb();
9b2cae6d
DK
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;
1306c429 332 return 0;
b12fdf7d
ZW
333}
334
3a8bc4b7 335/*
90476670
SW
336 * visorchannel_create() - creates the struct visorchannel abstraction for a
337 * data area in memory, but does NOT modify this data
338 * area
3995c5da 339 * @physaddr: physical address of start of channel
3995c5da 340 * @gfp: gfp_t to use when allocating memory for the data struct
d7f1589a 341 * @guid: GUID that identifies channel type;
3995c5da
DK
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 */
90476670
SW
349struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp,
350 const guid_t *guid, bool needs_lock)
3995c5da
DK
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;
3995c5da
DK
362 channel->needs_lock = needs_lock;
363 spin_lock_init(&channel->insert_lock);
364 spin_lock_init(&channel->remove_lock);
3995c5da 365 /*
cbe7e02f
DK
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.
3995c5da 370 */
b35fae7e 371 channel->requested = request_mem_region(physaddr, size, VISOR_DRV_NAME);
b32c5cb8 372 if (!channel->requested && !guid_equal(guid, &visor_video_guid))
51646f4d
DK
373 /* we only care about errors if this is not the video channel */
374 goto err_destroy_channel;
3995c5da
DK
375 channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
376 if (!channel->mapped) {
377 release_mem_region(physaddr, size);
378 goto err_destroy_channel;
379 }
3995c5da
DK
380 channel->physaddr = physaddr;
381 channel->nbytes = size;
d7f1589a 382 err = visorchannel_read(channel, 0, &channel->chan_hdr, size);
3995c5da
DK
383 if (err)
384 goto err_destroy_channel;
d7f1589a 385 size = (ulong)channel->chan_hdr.size;
3995c5da
DK
386 memunmap(channel->mapped);
387 if (channel->requested)
388 release_mem_region(channel->physaddr, channel->nbytes);
389 channel->mapped = NULL;
d7f1589a
DK
390 channel->requested = request_mem_region(channel->physaddr, size,
391 VISOR_DRV_NAME);
b32c5cb8 392 if (!channel->requested && !guid_equal(guid, &visor_video_guid))
51646f4d
DK
393 /* we only care about errors if this is not the video channel */
394 goto err_destroy_channel;
d7f1589a 395 channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB);
3995c5da 396 if (!channel->mapped) {
d7f1589a 397 release_mem_region(channel->physaddr, size);
3995c5da
DK
398 goto err_destroy_channel;
399 }
d7f1589a 400 channel->nbytes = size;
b32c5cb8 401 guid_copy(&channel->guid, guid);
3995c5da
DK
402 return channel;
403
404err_destroy_channel:
405 visorchannel_destroy(channel);
406 return NULL;
407}
408
e19674ce
DB
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 *
264f7b8a 416 * Return: integer error code indicating the status of the insertion
e19674ce 417 */
f230ba68
CD
418int visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
419 void *msg)
b12fdf7d 420{
264f7b8a 421 int rc;
24ac1074 422 unsigned long flags;
b12fdf7d
ZW
423
424 if (channel->needs_lock) {
24ac1074 425 spin_lock_irqsave(&channel->insert_lock, flags);
b12fdf7d 426 rc = signalinsert_inner(channel, queue, msg);
24ac1074 427 spin_unlock_irqrestore(&channel->insert_lock, flags);
b12fdf7d
ZW
428 } else {
429 rc = signalinsert_inner(channel, queue, msg);
430 }
e423812a 431
264f7b8a 432 return rc;
e423812a
KC
433}
434EXPORT_SYMBOL_GPL(visorchannel_signalinsert);