linux/drivers/visorbus/visorchannel.c
<<
>>
Prefs
   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);
 435