cregit-Linux how code gets into the kernel

Release 4.16 drivers/visorbus/visorchannel.c

Directory: drivers/visorbus
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2010 - 2015 UNISYS CORPORATION
 * All rights reserved.
 */

/*
 *  This provides s-Par channel communication primitives, which are
 *  independent of the mechanism used to access the channel data.
 */

#include <linux/uuid.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/visorbus.h>

#include "visorbus_private.h"
#include "controlvmchannel.h"


#define VISOR_DRV_NAME "visorchannel"


#define VISOR_CONSOLEVIDEO_CHANNEL_GUID \
	GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \
                  0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)


static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID;


struct visorchannel {
	
u64 physaddr;
	
ulong nbytes;
	
void *mapped;
	
bool requested;
	
struct channel_header chan_hdr;
	
guid_t guid;
	/*
         * channel creator knows if more than one thread will be inserting or
         * removing
         */
	
bool needs_lock;
	/* protect head writes in chan_hdr */
	
spinlock_t insert_lock;
	/* protect tail writes in chan_hdr */
	
spinlock_t remove_lock;
	
guid_t type;
	
guid_t inst;
};


void visorchannel_destroy(struct visorchannel *channel) { if (!channel) return; if (channel->mapped) { memunmap(channel->mapped); if (channel->requested) release_mem_region(channel->physaddr, channel->nbytes); } kfree(channel); }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner2547.17%222.22%
Jes Sorensen1222.64%222.22%
Ken Cox1018.87%111.11%
Bryan Thompson23.77%111.11%
Prarit Bhargava23.77%111.11%
Charles Daniels11.89%111.11%
Benjamin Romer11.89%111.11%
Total53100.00%9100.00%


u64 visorchannel_get_physaddr(struct visorchannel *channel) { return channel->physaddr; }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner1173.33%133.33%
Jes Sorensen320.00%133.33%
Charles Daniels16.67%133.33%
Total15100.00%3100.00%


ulong visorchannel_get_nbytes(struct visorchannel *channel) { return channel->nbytes; }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner1173.33%133.33%
Jes Sorensen320.00%133.33%
Charles Daniels16.67%133.33%
Total15100.00%3100.00%


char *visorchannel_guid_id(const guid_t *guid, char *s) { sprintf(s, "%pUL", guid); return s; }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner2177.78%133.33%
Andy Shevchenko311.11%133.33%
Ken Cox311.11%133.33%
Total27100.00%3100.00%


char *visorchannel_id(struct visorchannel *channel, char *s) { return visorchannel_guid_id(&channel->guid, s); }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner1869.23%125.00%
Ken Cox623.08%125.00%
Andy Shevchenko13.85%125.00%
Prarit Bhargava13.85%125.00%
Total26100.00%4100.00%


char *visorchannel_zoneid(struct visorchannel *channel, char *s) { return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s); }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox2485.71%133.33%
Andy Shevchenko27.14%133.33%
Bryan Thompson27.14%133.33%
Total28100.00%3100.00%


u64 visorchannel_get_clientpartition(struct visorchannel *channel) { return channel->chan_hdr.partition_handle; }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox1376.47%125.00%
Bryan Thompson211.76%125.00%
Charles Daniels15.88%125.00%
Benjamin Romer15.88%125.00%
Total17100.00%4100.00%


int visorchannel_set_clientpartition(struct visorchannel *channel, u64 partition_handle) { channel->chan_hdr.partition_handle = partition_handle; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Don Zickus2395.83%150.00%
Charles Daniels14.17%150.00%
Total24100.00%2100.00%

/** * visorchannel_get_guid() - queries the GUID of the designated channel * @channel: the channel to query * * Return: the GUID of the provided channel */
const guid_t *visorchannel_get_guid(struct visorchannel *channel) { return &channel->guid; }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox1161.11%133.33%
Andy Shevchenko527.78%133.33%
Bryan Thompson211.11%133.33%
Total18100.00%3100.00%

EXPORT_SYMBOL_GPL(visorchannel_get_guid);
int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest, ulong nbytes) { if (offset + nbytes > channel->nbytes) return -EIO; memcpy(dest, channel->mapped + offset, nbytes); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox2958.00%116.67%
Jes Sorensen1530.00%116.67%
Erik Arfvidson24.00%116.67%
Bryan Thompson24.00%116.67%
Dan J Williams12.00%116.67%
Charles Daniels12.00%116.67%
Total50100.00%6100.00%


int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest, ulong nbytes) { size_t chdr_size = sizeof(struct channel_header); size_t copy_size; if (offset + nbytes > channel->nbytes) return -EIO; if (offset < chdr_size) { copy_size = min(chdr_size - offset, nbytes); memcpy(((char *)(&channel->chan_hdr)) + offset, dest, copy_size); } memcpy(channel->mapped + offset, dest, nbytes); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jes Sorensen4139.81%330.00%
Ken Cox3937.86%110.00%
Prarit Bhargava87.77%110.00%
Tim Sell87.77%110.00%
Erik Arfvidson32.91%110.00%
Bryan Thompson21.94%110.00%
Dan J Williams10.97%110.00%
Charles Daniels10.97%110.00%
Total103100.00%10100.00%


void *visorchannel_get_header(struct visorchannel *channel) { return &channel->chan_hdr; }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox1588.24%150.00%
Bryan Thompson211.76%150.00%
Total17100.00%2100.00%

/* * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a * channel header */
static int sig_queue_offset(struct channel_header *chan_hdr, int q) { return ((chan_hdr)->ch_space_offset + ((q) * sizeof(struct signal_queue_header))); }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner2982.86%133.33%
Ken Cox514.29%133.33%
Colin Ian King12.86%133.33%
Total35100.00%3100.00%

/* * Return offset of a specific queue entry (data) from the beginning of a * channel header */
static int sig_data_offset(struct channel_header *chan_hdr, int q, struct signal_queue_header *sig_hdr, int slot) { return (sig_queue_offset(chan_hdr, q) + sig_hdr->sig_base_offset + (slot * sig_hdr->signal_size)); }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner3477.27%133.33%
Ken Cox920.45%133.33%
Colin Ian King12.27%133.33%
Total44100.00%3100.00%

/* * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back into * host memory */ #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \ visorchannel_write(channel, \ sig_queue_offset(&channel->chan_hdr, queue) + \ offsetof(struct signal_queue_header, FIELD), \ &((sig_hdr)->FIELD), \ sizeof((sig_hdr)->FIELD))
static int sig_read_header(struct visorchannel *channel, u32 queue, struct signal_queue_header *sig_hdr) { if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header)) return -EINVAL; /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */ return visorchannel_read(channel, sig_queue_offset(&channel->chan_hdr, queue), sig_hdr, sizeof(struct signal_queue_header)); }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox4470.97%110.00%
Benjamin Romer812.90%440.00%
David Binder46.45%110.00%
Prarit Bhargava23.23%110.00%
Bryan Thompson23.23%110.00%
David Kershner11.61%110.00%
Jes Sorensen11.61%110.00%
Total62100.00%10100.00%


static int sig_read_data(struct visorchannel *channel, u32 queue, struct signal_queue_header *sig_hdr, u32 slot, void *data) { int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue, sig_hdr, slot); return visorchannel_read(channel, signal_data_offset, data, sig_hdr->signal_size); }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner5494.74%250.00%
David Binder23.51%125.00%
Ken Cox11.75%125.00%
Total57100.00%4100.00%


static int sig_write_data(struct visorchannel *channel, u32 queue, struct signal_queue_header *sig_hdr, u32 slot, void *data) { int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue, sig_hdr, slot); return visorchannel_write(channel, signal_data_offset, data, sig_hdr->signal_size); }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox4375.44%111.11%
Benjamin Romer58.77%333.33%
David Kershner47.02%222.22%
David Binder23.51%111.11%
Bryan Thompson23.51%111.11%
Prarit Bhargava11.75%111.11%
Total57100.00%9100.00%


static int signalremove_inner(struct visorchannel *channel, u32 queue, void *msg) { struct signal_queue_header sig_hdr; int error; error = sig_read_header(channel, queue, &sig_hdr); if (error) return error; /* No signals to remove; have caller try again. */ if (sig_hdr.head == sig_hdr.tail) return -EAGAIN; sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots; error = sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg); if (error) return error; sig_hdr.num_received++; /* * For each data field in SIGNAL_QUEUE_HEADER that was modified, update * host memory. Required for channel sync. */ mb(); error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail); if (error) return error; error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received); if (error) return error; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner10769.48%337.50%
David Binder3422.08%112.50%
Ken Cox85.19%112.50%
Benjamin Romer31.95%225.00%
Bryan Thompson21.30%112.50%
Total154100.00%8100.00%

/** * visorchannel_signalremove() - removes a message from the designated * channel/queue * @channel: the channel the message will be removed from * @queue: the queue the message will be removed from * @msg: the message to remove * * Return: integer error code indicating the status of the removal */
int visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg) { int rc; unsigned long flags; if (channel->needs_lock) { spin_lock_irqsave(&channel->remove_lock, flags); rc = signalremove_inner(channel, queue, msg); spin_unlock_irqrestore(&channel->remove_lock, flags); } else { rc = signalremove_inner(channel, queue, msg); } return rc; }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner7188.75%120.00%
Ken Cox67.50%120.00%
Charles Daniels11.25%120.00%
Benjamin Romer11.25%120.00%
David Binder11.25%120.00%
Total80100.00%5100.00%

EXPORT_SYMBOL_GPL(visorchannel_signalremove);
static bool queue_empty(struct visorchannel *channel, u32 queue) { struct signal_queue_header sig_hdr; if (sig_read_header(channel, queue, &sig_hdr)) return true; return (sig_hdr.head == sig_hdr.tail); }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner2965.91%125.00%
Cathal Mullaney920.45%125.00%
Ken Cox511.36%125.00%
Prarit Bhargava12.27%125.00%
Total44100.00%4100.00%

/** * visorchannel_signalempty() - checks if the designated channel/queue contains * any messages * @channel: the channel to query * @queue: the queue in the channel to query * * Return: boolean indicating whether any messages in the designated * channel/queue are present */
bool visorchannel_signalempty(struct visorchannel *channel, u32 queue) { bool rc; unsigned long flags; if (!channel->needs_lock) return queue_empty(channel, queue); spin_lock_irqsave(&channel->remove_lock, flags); rc = queue_empty(channel, queue); spin_unlock_irqrestore(&channel->remove_lock, flags); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Cathal Mullaney4567.16%125.00%
David Kershner1928.36%125.00%
Ken Cox22.99%125.00%
Charles Daniels11.49%125.00%
Total67100.00%4100.00%

EXPORT_SYMBOL_GPL(visorchannel_signalempty);
static int signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) { struct signal_queue_header sig_hdr; int err; err = sig_read_header(channel, queue, &sig_hdr); if (err) return err; sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots; if (sig_hdr.head == sig_hdr.tail) { sig_hdr.num_overflows++; err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows); if (err) return err; return -EIO; } err = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg); if (err) return err; sig_hdr.num_sent++; /* * For each data field in SIGNAL_QUEUE_HEADER that was modified, update * host memory. Required for channel sync. */ mb(); err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, head); if (err) return err; err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent); if (err) return err; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox7742.54%19.09%
David Kershner6234.25%327.27%
David Binder2212.15%19.09%
Zachary Warren116.08%19.09%
Benjamin Romer73.87%436.36%
Bryan Thompson21.10%19.09%
Total181100.00%11100.00%

/* * visorchannel_create() - creates the struct visorchannel abstraction for a * data area in memory, but does NOT modify this data * area * @physaddr: physical address of start of channel * @gfp: gfp_t to use when allocating memory for the data struct * @guid: GUID that identifies channel type; * @needs_lock: must specify true if you have multiple threads of execution * that will be calling visorchannel methods of this * visorchannel at the same time * * Return: pointer to visorchannel that was created if successful, * otherwise NULL */
struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp, const guid_t *guid, bool needs_lock) { struct visorchannel *channel; int err; size_t size = sizeof(struct channel_header); if (physaddr == 0) return NULL; channel = kzalloc(sizeof(*channel), gfp); if (!channel) return NULL; channel->needs_lock = needs_lock; spin_lock_init(&channel->insert_lock); spin_lock_init(&channel->remove_lock); /* * Video driver constains the efi framebuffer so it will get a conflict * resource when requesting its full mem region. Since we are only * using the efi framebuffer for video we can ignore this. Remember that * we haven't requested it so we don't try to release later on. */ channel->requested = request_mem_region(physaddr, size, VISOR_DRV_NAME); if (!channel->requested && !guid_equal(guid, &visor_video_guid)) /* we only care about errors if this is not the video channel */ goto err_destroy_channel; channel->mapped = memremap(physaddr, size, MEMREMAP_WB); if (!channel->mapped) { release_mem_region(physaddr, size); goto err_destroy_channel; } channel->physaddr = physaddr; channel->nbytes = size; err = visorchannel_read(channel, 0, &channel->chan_hdr, size); if (err) goto err_destroy_channel; size = (ulong)channel->chan_hdr.size; memunmap(channel->mapped); if (channel->requested) release_mem_region(channel->physaddr, channel->nbytes); channel->mapped = NULL; channel->requested = request_mem_region(channel->physaddr, size, VISOR_DRV_NAME); if (!channel->requested && !guid_equal(guid, &visor_video_guid)) /* we only care about errors if this is not the video channel */ goto err_destroy_channel; channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB); if (!channel->mapped) { release_mem_region(channel->physaddr, size); goto err_destroy_channel; } channel->nbytes = size; guid_copy(&channel->guid, guid); return channel; err_destroy_channel: visorchannel_destroy(channel); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
David Kershner21364.16%428.57%
Ken Cox4714.16%214.29%
Neil Horman288.43%17.14%
Zachary Warren195.72%17.14%
Andy Shevchenko144.22%17.14%
Benjamin Romer51.51%17.14%
Sameer Wadgaonkar30.90%214.29%
David Binder20.60%17.14%
Tim Sell10.30%17.14%
Total332100.00%14100.00%

/** * visorchannel_signalinsert() - inserts a message into the designated * channel/queue * @channel: the channel the message will be added to * @queue: the queue the message will be added to * @msg: the message to insert * * Return: integer error code indicating the status of the insertion */
int visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg) { int rc; unsigned long flags; if (channel->needs_lock) { spin_lock_irqsave(&channel->insert_lock, flags); rc = signalinsert_inner(channel, queue, msg); spin_unlock_irqrestore(&channel->insert_lock, flags); } else { rc = signalinsert_inner(channel, queue, msg); } return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Zachary Warren5163.75%116.67%
Ken Cox1721.25%233.33%
Tim Sell1012.50%116.67%
David Binder11.25%116.67%
Charles Daniels11.25%116.67%
Total80100.00%6100.00%

EXPORT_SYMBOL_GPL(visorchannel_signalinsert);

Overall Contributors

PersonTokensPropCommitsCommitProp
David Kershner73843.21%1017.54%
Ken Cox46026.93%23.51%
Jes Sorensen834.86%814.04%
Zachary Warren814.74%11.75%
David Binder744.33%58.77%
Cathal Mullaney543.16%11.75%
Benjamin Romer331.93%814.04%
Andy Shevchenko321.87%11.75%
Don Zickus301.76%23.51%
Neil Horman281.64%11.75%
Bryan Thompson231.35%11.75%
Tim Sell191.11%23.51%
Prarit Bhargava160.94%47.02%
Charles Daniels100.59%11.75%
Sameer Wadgaonkar90.53%35.26%
Erik Arfvidson60.35%23.51%
Dan J Williams50.29%11.75%
Laurent Navet30.18%11.75%
Colin Ian King20.12%11.75%
Greg Kroah-Hartman20.12%23.51%
Total1708100.00%57100.00%
Directory: drivers/visorbus
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.