root/drivers/visorbus/visorchannel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. visorchannel_destroy
  2. visorchannel_get_physaddr
  3. visorchannel_get_nbytes
  4. visorchannel_guid_id
  5. visorchannel_id
  6. visorchannel_zoneid
  7. visorchannel_get_clientpartition
  8. visorchannel_set_clientpartition
  9. visorchannel_get_guid
  10. visorchannel_read
  11. visorchannel_write
  12. visorchannel_get_header
  13. sig_queue_offset
  14. sig_data_offset
  15. sig_read_header
  16. sig_read_data
  17. sig_write_data
  18. signalremove_inner
  19. visorchannel_signalremove
  20. queue_empty
  21. visorchannel_signalempty
  22. signalinsert_inner
  23. visorchannel_create
  24. visorchannel_signalinsert

   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 
  26 static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID;
  27 
  28 struct 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 
  48 void 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 
  61 u64 visorchannel_get_physaddr(struct visorchannel *channel)
  62 {
  63         return channel->physaddr;
  64 }
  65 
  66 ulong visorchannel_get_nbytes(struct visorchannel *channel)
  67 {
  68         return channel->nbytes;
  69 }
  70 
  71 char *visorchannel_guid_id(const guid_t *guid, char *s)
  72 {
  73         sprintf(s, "%pUL", guid);
  74         return s;
  75 }
  76 
  77 char *visorchannel_id(struct visorchannel *channel, char *s)
  78 {
  79         return visorchannel_guid_id(&channel->guid, s);
  80 }
  81 
  82 char *visorchannel_zoneid(struct visorchannel *channel, char *s)
  83 {
  84         return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s);
  85 }
  86 
  87 u64 visorchannel_get_clientpartition(struct visorchannel *channel)
  88 {
  89         return channel->chan_hdr.partition_handle;
  90 }
  91 
  92 int 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  */
 105 const guid_t *visorchannel_get_guid(struct visorchannel *channel)
 106 {
 107         return &channel->guid;
 108 }
 109 EXPORT_SYMBOL_GPL(visorchannel_get_guid);
 110 
 111 int 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 
 121 int 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 
 139 void *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  */
 148 static 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  */
 158 static 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 
 176 static 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 
 188 static 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 
 199 static 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 
 210 static 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  */
 250 int 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 }
 266 EXPORT_SYMBOL_GPL(visorchannel_signalremove);
 267 
 268 static 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  */
 286 bool 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 }
 298 EXPORT_SYMBOL_GPL(visorchannel_signalempty);
 299 
 300 static 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  */
 349 struct 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 
 404 err_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  */
 418 int 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 }
 434 EXPORT_SYMBOL_GPL(visorchannel_signalinsert);

/* [<][>][^][v][top][bottom][index][help] */