staging: unisys: Eliminate visor_memregion_read()
[platform/kernel/linux-starfive.git] / drivers / staging / unisys / visorbus / visorchannel.c
1 /* visorchannel_funcs.c
2  *
3  * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  */
17
18 /*
19  *  This provides Supervisor channel communication primitives, which are
20  *  independent of the mechanism used to access the channel data.  All channel
21  *  data is accessed using the memregion abstraction.  (memregion has both
22  *  a CM2 implementation and a direct memory implementation.)
23  */
24
25 #include "memregion.h"
26 #include "version.h"
27 #include "visorbus.h"
28 #include <linux/uuid.h>
29
30 #define MYDRVNAME "visorchannel"
31
32 struct visorchannel {
33         struct memregion memregion;     /* from visor_memregion_create() */
34         struct channel_header chan_hdr;
35         uuid_le guid;
36         ulong size;
37         BOOL needs_lock;        /* channel creator knows if more than one
38                                  * thread will be inserting or removing */
39         spinlock_t insert_lock; /* protect head writes in chan_hdr */
40         spinlock_t remove_lock; /* protect tail writes in chan_hdr */
41
42         struct {
43                 struct signal_queue_header req_queue;
44                 struct signal_queue_header rsp_queue;
45                 struct signal_queue_header event_queue;
46                 struct signal_queue_header ack_queue;
47         } safe_uis_queue;
48 };
49
50 /* Creates the struct visorchannel abstraction for a data area in memory,
51  * but does NOT modify this data area.
52  */
53 static struct visorchannel *
54 visorchannel_create_guts(HOSTADDRESS physaddr, ulong channel_bytes,
55                          ulong off, uuid_le guid, BOOL needs_lock)
56 {
57         struct visorchannel *channel;
58         int err;
59         size_t size = sizeof(struct channel_header);
60
61         channel = kzalloc(sizeof(*channel), GFP_KERNEL|__GFP_NORETRY);
62         if (!channel)
63                 goto cleanup;
64
65         channel->needs_lock = needs_lock;
66         spin_lock_init(&channel->insert_lock);
67         spin_lock_init(&channel->remove_lock);
68
69         if (!request_mem_region(physaddr, size, MYDRVNAME))
70                 goto cleanup;
71
72         channel->memregion.mapped = ioremap_cache(physaddr, size);
73         if (!channel->memregion.mapped) {
74                 release_mem_region(physaddr, size);
75                 goto cleanup;
76         }
77
78         channel->memregion.physaddr = physaddr;
79         channel->memregion.nbytes = size;
80
81         err = visorchannel_read(channel, 0, &channel->chan_hdr,
82                                 sizeof(struct channel_header));
83         if (err)
84                 goto cleanup;
85
86         /* we had better be a CLIENT of this channel */
87         if (channel_bytes == 0)
88                 channel_bytes = (ulong)channel->chan_hdr.size;
89         if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
90                 guid = channel->chan_hdr.chtype;
91
92         iounmap(channel->memregion.mapped);
93         release_mem_region(channel->memregion.physaddr,
94                            channel->memregion.nbytes);
95         channel->memregion.mapped = NULL;
96         if (!request_mem_region(channel->memregion.physaddr, channel_bytes,
97                                 MYDRVNAME))
98                 goto cleanup;
99
100         channel->memregion.mapped = ioremap_cache(channel->memregion.physaddr,
101                                                   channel_bytes);
102         if (!channel->memregion.mapped) {
103                 release_mem_region(channel->memregion.physaddr, channel_bytes);
104                 goto cleanup;
105         }
106
107         channel->memregion.nbytes = channel_bytes;
108
109         channel->size = channel_bytes;
110         channel->guid = guid;
111         return channel;
112
113 cleanup:
114         visorchannel_destroy(channel);
115         return NULL;
116 }
117
118 struct visorchannel *
119 visorchannel_create(HOSTADDRESS physaddr, ulong channel_bytes, uuid_le guid)
120 {
121         return visorchannel_create_guts(physaddr, channel_bytes, 0, guid,
122                                         FALSE);
123 }
124 EXPORT_SYMBOL_GPL(visorchannel_create);
125
126 struct visorchannel *
127 visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channel_bytes,
128                               uuid_le guid)
129 {
130         return visorchannel_create_guts(physaddr, channel_bytes, 0, guid,
131                                         TRUE);
132 }
133 EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
134
135 void
136 visorchannel_destroy(struct visorchannel *channel)
137 {
138         if (!channel)
139                 return;
140         if (channel->memregion.mapped) {
141                 iounmap(channel->memregion.mapped);
142                 release_mem_region(channel->memregion.physaddr,
143                                    channel->memregion.nbytes);
144         }
145         kfree(channel);
146 }
147 EXPORT_SYMBOL_GPL(visorchannel_destroy);
148
149 HOSTADDRESS
150 visorchannel_get_physaddr(struct visorchannel *channel)
151 {
152         return channel->memregion.physaddr;
153 }
154 EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
155
156 ulong
157 visorchannel_get_nbytes(struct visorchannel *channel)
158 {
159         return channel->size;
160 }
161 EXPORT_SYMBOL_GPL(visorchannel_get_nbytes);
162
163 char *
164 visorchannel_uuid_id(uuid_le *guid, char *s)
165 {
166         sprintf(s, "%pUL", guid);
167         return s;
168 }
169 EXPORT_SYMBOL_GPL(visorchannel_uuid_id);
170
171 char *
172 visorchannel_id(struct visorchannel *channel, char *s)
173 {
174         return visorchannel_uuid_id(&channel->guid, s);
175 }
176 EXPORT_SYMBOL_GPL(visorchannel_id);
177
178 char *
179 visorchannel_zoneid(struct visorchannel *channel, char *s)
180 {
181         return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s);
182 }
183 EXPORT_SYMBOL_GPL(visorchannel_zoneid);
184
185 HOSTADDRESS
186 visorchannel_get_clientpartition(struct visorchannel *channel)
187 {
188         return channel->chan_hdr.partition_handle;
189 }
190 EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
191
192 uuid_le
193 visorchannel_get_uuid(struct visorchannel *channel)
194 {
195         return channel->guid;
196 }
197 EXPORT_SYMBOL_GPL(visorchannel_get_uuid);
198
199 int
200 visorchannel_read(struct visorchannel *channel, ulong offset,
201                   void *local, ulong nbytes)
202 {
203         if (offset + nbytes > channel->memregion.nbytes)
204                 return -EIO;
205
206         memcpy_fromio(local, channel->memregion.mapped + offset, nbytes);
207
208         return 0;
209 }
210 EXPORT_SYMBOL_GPL(visorchannel_read);
211
212 int
213 visorchannel_write(struct visorchannel *channel, ulong offset,
214                    void *local, ulong nbytes)
215 {
216         size_t chdr_size = sizeof(struct channel_header);
217         size_t copy_size;
218
219         if (offset + nbytes > channel->memregion.nbytes)
220                 return -EIO;
221
222         if (offset < chdr_size) {
223                 copy_size = min(chdr_size, nbytes) - offset;
224                 memcpy(&channel->chan_hdr + offset, local, copy_size);
225         }
226
227         memcpy_toio(channel->memregion.mapped + offset, local, nbytes);
228
229         return 0;
230 }
231 EXPORT_SYMBOL_GPL(visorchannel_write);
232
233 int
234 visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch,
235                    ulong nbytes)
236 {
237         int err;
238         int bufsize = PAGE_SIZE;
239         int written = 0;
240         u8 *buf;
241
242         buf = (u8 *) __get_free_page(GFP_KERNEL);
243         if (!buf)
244                 return -ENOMEM;
245
246         memset(buf, ch, bufsize);
247
248         while (nbytes > 0) {
249                 int thisbytes = bufsize;
250
251                 if (nbytes < thisbytes)
252                         thisbytes = nbytes;
253                 err = visor_memregion_write(&channel->memregion,
254                                             offset + written, buf, thisbytes);
255                 if (err)
256                         goto cleanup;
257
258                 written += thisbytes;
259                 nbytes -= thisbytes;
260         }
261         err = 0;
262
263 cleanup:
264         free_page((unsigned long) buf);
265         return err;
266 }
267 EXPORT_SYMBOL_GPL(visorchannel_clear);
268
269 void __iomem  *
270 visorchannel_get_header(struct visorchannel *channel)
271 {
272         return (void __iomem *)&channel->chan_hdr;
273 }
274 EXPORT_SYMBOL_GPL(visorchannel_get_header);
275
276 /** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
277  *  channel header
278  */
279 #define SIG_QUEUE_OFFSET(chan_hdr, q) \
280         ((chan_hdr)->ch_space_offset + \
281          ((q) * sizeof(struct signal_queue_header)))
282
283 /** Return offset of a specific queue entry (data) from the beginning of a
284  *  channel header
285  */
286 #define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
287         (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->sig_base_offset + \
288             ((slot) * (sig_hdr)->signal_size))
289
290 /** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
291  *  into host memory
292  */
293 #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD)                 \
294         (visor_memregion_write(&channel->memregion,                     \
295                                SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \
296                                offsetof(struct signal_queue_header, FIELD),\
297                                &((sig_hdr)->FIELD),                     \
298                                sizeof((sig_hdr)->FIELD)) >= 0)
299
300 static BOOL
301 sig_read_header(struct visorchannel *channel, u32 queue,
302                 struct signal_queue_header *sig_hdr)
303 {
304         int err;
305
306         if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
307                 return FALSE;
308
309         /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
310         err = visorchannel_read(channel,
311                                 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
312                                 sig_hdr, sizeof(struct signal_queue_header));
313         if (err)
314                 return FALSE;
315
316         return TRUE;
317 }
318
319 static inline BOOL
320 sig_read_data(struct visorchannel *channel, u32 queue,
321               struct signal_queue_header *sig_hdr, u32 slot, void *data)
322 {
323         int err;
324         int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
325                                                  sig_hdr, slot);
326
327         err = visorchannel_read(channel, signal_data_offset,
328                                 data, sig_hdr->signal_size);
329         if (err)
330                 return FALSE;
331
332         return TRUE;
333 }
334
335 static inline BOOL
336 sig_write_data(struct visorchannel *channel, u32 queue,
337                struct signal_queue_header *sig_hdr, u32 slot, void *data)
338 {
339         int err;
340         int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
341                                                  sig_hdr, slot);
342
343         err = visor_memregion_write(&channel->memregion,
344                                     signal_data_offset,
345                                     data, sig_hdr->signal_size);
346         if (err)
347                 return FALSE;
348
349         return TRUE;
350 }
351
352 static BOOL
353 signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
354 {
355         struct signal_queue_header sig_hdr;
356
357         if (!sig_read_header(channel, queue, &sig_hdr))
358                 return FALSE;
359         if (sig_hdr.head == sig_hdr.tail)
360                 return FALSE;   /* no signals to remove */
361
362         sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
363         if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg))
364                 return FALSE;
365         sig_hdr.num_received++;
366
367         /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
368          * update host memory.
369          */
370         mb(); /* required for channel synch */
371         if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail))
372                 return FALSE;
373         if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received))
374                 return FALSE;
375         return TRUE;
376 }
377
378 BOOL
379 visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
380 {
381         BOOL rc;
382
383         if (channel->needs_lock) {
384                 spin_lock(&channel->remove_lock);
385                 rc = signalremove_inner(channel, queue, msg);
386                 spin_unlock(&channel->remove_lock);
387         } else {
388                 rc = signalremove_inner(channel, queue, msg);
389         }
390
391         return rc;
392 }
393 EXPORT_SYMBOL_GPL(visorchannel_signalremove);
394
395 static BOOL
396 signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
397 {
398         struct signal_queue_header sig_hdr;
399
400         if (!sig_read_header(channel, queue, &sig_hdr))
401                 return FALSE;
402
403         sig_hdr.head = ((sig_hdr.head + 1) % sig_hdr.max_slots);
404         if (sig_hdr.head == sig_hdr.tail) {
405                 sig_hdr.num_overflows++;
406                 visor_memregion_write(&channel->memregion,
407                                       SIG_QUEUE_OFFSET(&channel->chan_hdr,
408                                                        queue) +
409                                       offsetof(struct signal_queue_header,
410                                                num_overflows),
411                                       &(sig_hdr.num_overflows),
412                                       sizeof(sig_hdr.num_overflows));
413                 return FALSE;
414         }
415
416         if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg))
417                 return FALSE;
418
419         sig_hdr.num_sent++;
420
421         /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
422          * update host memory.
423          */
424         mb(); /* required for channel synch */
425         if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head))
426                 return FALSE;
427         if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent))
428                 return FALSE;
429
430         return TRUE;
431 }
432
433 BOOL
434 visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
435 {
436         BOOL rc;
437
438         if (channel->needs_lock) {
439                 spin_lock(&channel->insert_lock);
440                 rc = signalinsert_inner(channel, queue, msg);
441                 spin_unlock(&channel->insert_lock);
442         } else {
443                 rc = signalinsert_inner(channel, queue, msg);
444         }
445
446         return rc;
447 }
448 EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
449
450 int
451 visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue)
452 {
453         struct signal_queue_header sig_hdr;
454         u32 slots_avail, slots_used;
455         u32 head, tail;
456
457         if (!sig_read_header(channel, queue, &sig_hdr))
458                 return 0;
459         head = sig_hdr.head;
460         tail = sig_hdr.tail;
461         if (head < tail)
462                 head = head + sig_hdr.max_slots;
463         slots_used = (head - tail);
464         slots_avail = sig_hdr.max_signals - slots_used;
465         return (int)slots_avail;
466 }
467 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
468
469 int
470 visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue)
471 {
472         struct signal_queue_header sig_hdr;
473
474         if (!sig_read_header(channel, queue, &sig_hdr))
475                 return 0;
476         return (int)sig_hdr.max_signals;
477 }
478 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots);
479
480 static void
481 sigqueue_debug(struct signal_queue_header *q, int which, struct seq_file *seq)
482 {
483         seq_printf(seq, "Signal Queue #%d\n", which);
484         seq_printf(seq, "   VersionId          = %lu\n", (ulong)q->version);
485         seq_printf(seq, "   Type               = %lu\n", (ulong)q->chtype);
486         seq_printf(seq, "   oSignalBase        = %llu\n",
487                    (long long)q->sig_base_offset);
488         seq_printf(seq, "   SignalSize         = %lu\n", (ulong)q->signal_size);
489         seq_printf(seq, "   MaxSignalSlots     = %lu\n",
490                    (ulong)q->max_slots);
491         seq_printf(seq, "   MaxSignals         = %lu\n", (ulong)q->max_signals);
492         seq_printf(seq, "   FeatureFlags       = %-16.16Lx\n",
493                    (long long)q->features);
494         seq_printf(seq, "   NumSignalsSent     = %llu\n",
495                    (long long)q->num_sent);
496         seq_printf(seq, "   NumSignalsReceived = %llu\n",
497                    (long long)q->num_received);
498         seq_printf(seq, "   NumOverflows       = %llu\n",
499                    (long long)q->num_overflows);
500         seq_printf(seq, "   Head               = %lu\n", (ulong)q->head);
501         seq_printf(seq, "   Tail               = %lu\n", (ulong)q->tail);
502 }
503
504 void
505 visorchannel_debug(struct visorchannel *channel, int num_queues,
506                    struct seq_file *seq, u32 off)
507 {
508         HOSTADDRESS addr = 0;
509         ulong nbytes = 0, nbytes_region = 0;
510         struct channel_header hdr;
511         struct channel_header *phdr = &hdr;
512         int i = 0;
513         int errcode = 0;
514
515         if (!channel)
516                 return;
517
518         addr = visorchannel_get_physaddr(channel);
519         nbytes_region = visorchannel_get_nbytes(channel);
520         errcode = visorchannel_read(channel, off,
521                                     phdr, sizeof(struct channel_header));
522         if (errcode < 0) {
523                 seq_printf(seq,
524                            "Read of channel header failed with errcode=%d)\n",
525                            errcode);
526                 if (off == 0) {
527                         phdr = &channel->chan_hdr;
528                         seq_puts(seq, "(following data may be stale)\n");
529                 } else {
530                         return;
531                 }
532         }
533         nbytes = (ulong)(phdr->size);
534         seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
535                    addr + off, nbytes, nbytes_region);
536         seq_printf(seq, "Type            = %pUL\n", &phdr->chtype);
537         seq_printf(seq, "ZoneGuid        = %pUL\n", &phdr->zone_uuid);
538         seq_printf(seq, "Signature       = 0x%-16.16Lx\n",
539                    (long long)phdr->signature);
540         seq_printf(seq, "LegacyState     = %lu\n", (ulong)phdr->legacy_state);
541         seq_printf(seq, "SrvState        = %lu\n", (ulong)phdr->srv_state);
542         seq_printf(seq, "CliStateBoot    = %lu\n", (ulong)phdr->cli_state_boot);
543         seq_printf(seq, "CliStateOS      = %lu\n", (ulong)phdr->cli_state_os);
544         seq_printf(seq, "HeaderSize      = %lu\n", (ulong)phdr->header_size);
545         seq_printf(seq, "Size            = %llu\n", (long long)phdr->size);
546         seq_printf(seq, "Features        = 0x%-16.16llx\n",
547                    (long long)phdr->features);
548         seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n",
549                    (long long)phdr->partition_handle);
550         seq_printf(seq, "Handle          = 0x%-16.16llx\n",
551                    (long long)phdr->handle);
552         seq_printf(seq, "VersionId       = %lu\n", (ulong)phdr->version_id);
553         seq_printf(seq, "oChannelSpace   = %llu\n",
554                    (long long)phdr->ch_space_offset);
555         if ((phdr->ch_space_offset == 0) || (errcode < 0))
556                 ;
557         else
558                 for (i = 0; i < num_queues; i++) {
559                         struct signal_queue_header q;
560
561                         errcode = visorchannel_read(channel,
562                                                     off +
563                                                     phdr->ch_space_offset +
564                                                     (i * sizeof(q)),
565                                                     &q, sizeof(q));
566                         if (errcode < 0) {
567                                 seq_printf(seq,
568                                            "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
569                                            i, addr, errcode);
570                                 continue;
571                         }
572                         sigqueue_debug(&q, i, seq);
573                 }
574         seq_printf(seq, "--- End   channel @0x%-16.16Lx for 0x%lx bytes ---\n",
575                    addr + off, nbytes);
576 }
577 EXPORT_SYMBOL_GPL(visorchannel_debug);