Blame view

drivers/visorbus/visorchannel.c 11.7 KB
b79c0f4f5   Greg Kroah-Hartman   staging: unisys: ...
1
  // SPDX-License-Identifier: GPL-2.0
fa96c883d   David Binder   staging: unisys: ...
2
  /*
6f14cc18f   Benjamin Romer   staging: unisys: ...
3
   * Copyright (C) 2010 - 2015 UNISYS CORPORATION
e423812a9   Ken Cox   staging: visorcha...
4
   * All rights reserved.
e423812a9   Ken Cox   staging: visorcha...
5
6
7
   */
  
  /*
e19674ceb   David Binder   staging: unisys: ...
8
   *  This provides s-Par channel communication primitives, which are
434cbf28b   Jes Sorensen   staging: unisys: ...
9
   *  independent of the mechanism used to access the channel data.
e423812a9   Ken Cox   staging: visorcha...
10
   */
99c805f4c   David Kershner   staging: unisys: ...
11
  #include <linux/uuid.h>
3103dc030   Dan Williams   visorbus: switch ...
12
  #include <linux/io.h>
eb6eb1e14   David Kershner   staging: unisys: ...
13
  #include <linux/slab.h>
93d3ad90c   David Kershner   drivers: visorbus...
14
  #include <linux/visorbus.h>
99c805f4c   David Kershner   staging: unisys: ...
15

ae719092f   Laurent Navet   staging: unisys: ...
16
  #include "visorbus_private.h"
1fb3016ea   Don Zickus   staging: unisys: ...
17
  #include "controlvmchannel.h"
e423812a9   Ken Cox   staging: visorcha...
18

b35fae7e2   David Binder   staging: unisys: ...
19
  #define VISOR_DRV_NAME "visorchannel"
e423812a9   Ken Cox   staging: visorcha...
20

2b8ec7da9   Sameer Wadgaonkar   staging: unisys: ...
21
  #define VISOR_CONSOLEVIDEO_CHANNEL_GUID \
b32c5cb84   Andy Shevchenko   staging: unisys: ...
22
23
  	GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \
  		  0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)
c2a60109a   David Binder   staging: unisys: ...
24

b32c5cb84   Andy Shevchenko   staging: unisys: ...
25
  static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID;
99c805f4c   David Kershner   staging: unisys: ...
26

383df64e0   Bryan Thompson   staging: unisys: ...
27
  struct visorchannel {
d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
28
  	u64 physaddr;
434cbf28b   Jes Sorensen   staging: unisys: ...
29
  	ulong nbytes;
3103dc030   Dan Williams   visorbus: switch ...
30
  	void *mapped;
99c805f4c   David Kershner   staging: unisys: ...
31
  	bool requested;
9fd1b95aa   Benjamin Romer   staging: unisys: ...
32
  	struct channel_header chan_hdr;
b32c5cb84   Andy Shevchenko   staging: unisys: ...
33
  	guid_t guid;
0496bedf0   Sameer Wadgaonkar   staging: unisys: ...
34
  	/*
cbe7e02f9   David Kershner   staging: unisys: ...
35
36
  	 * channel creator knows if more than one thread will be inserting or
  	 * removing
0496bedf0   Sameer Wadgaonkar   staging: unisys: ...
37
38
39
40
41
42
  	 */
  	bool needs_lock;
  	/* protect head writes in chan_hdr */
  	spinlock_t insert_lock;
  	/* protect tail writes in chan_hdr */
  	spinlock_t remove_lock;
b32c5cb84   Andy Shevchenko   staging: unisys: ...
43
44
  	guid_t type;
  	guid_t inst;
e423812a9   Ken Cox   staging: visorcha...
45
  };
f230ba68d   Charles Daniels   staging: unisys: ...
46
  void visorchannel_destroy(struct visorchannel *channel)
e423812a9   Ken Cox   staging: visorcha...
47
  {
fc11a550d   Benjamin Romer   staging: unisys: ...
48
  	if (!channel)
e423812a9   Ken Cox   staging: visorcha...
49
  		return;
a3b726c19   David Kershner   staging: unisys: ...
50

434cbf28b   Jes Sorensen   staging: unisys: ...
51
  	if (channel->mapped) {
3103dc030   Dan Williams   visorbus: switch ...
52
  		memunmap(channel->mapped);
99c805f4c   David Kershner   staging: unisys: ...
53
54
  		if (channel->requested)
  			release_mem_region(channel->physaddr, channel->nbytes);
0dbb3fb66   Jes Sorensen   staging: unisys: ...
55
  	}
e423812a9   Ken Cox   staging: visorcha...
56
57
  	kfree(channel);
  }
e423812a9   Ken Cox   staging: visorcha...
58

f230ba68d   Charles Daniels   staging: unisys: ...
59
  u64 visorchannel_get_physaddr(struct visorchannel *channel)
e423812a9   Ken Cox   staging: visorcha...
60
  {
434cbf28b   Jes Sorensen   staging: unisys: ...
61
  	return channel->physaddr;
e423812a9   Ken Cox   staging: visorcha...
62
  }
e423812a9   Ken Cox   staging: visorcha...
63

f230ba68d   Charles Daniels   staging: unisys: ...
64
  ulong visorchannel_get_nbytes(struct visorchannel *channel)
e423812a9   Ken Cox   staging: visorcha...
65
  {
2b9bcf81d   David Binder   staging: unisys: ...
66
  	return channel->nbytes;
e423812a9   Ken Cox   staging: visorcha...
67
  }
e423812a9   Ken Cox   staging: visorcha...
68

b32c5cb84   Andy Shevchenko   staging: unisys: ...
69
  char *visorchannel_guid_id(const guid_t *guid, char *s)
e423812a9   Ken Cox   staging: visorcha...
70
  {
90addb021   Benjamin Romer   staging: unisys: ...
71
72
  	sprintf(s, "%pUL", guid);
  	return s;
e423812a9   Ken Cox   staging: visorcha...
73
  }
e423812a9   Ken Cox   staging: visorcha...
74

f230ba68d   Charles Daniels   staging: unisys: ...
75
  char *visorchannel_id(struct visorchannel *channel, char *s)
e423812a9   Ken Cox   staging: visorcha...
76
  {
b32c5cb84   Andy Shevchenko   staging: unisys: ...
77
  	return visorchannel_guid_id(&channel->guid, s);
e423812a9   Ken Cox   staging: visorcha...
78
  }
e423812a9   Ken Cox   staging: visorcha...
79

f230ba68d   Charles Daniels   staging: unisys: ...
80
  char *visorchannel_zoneid(struct visorchannel *channel, char *s)
e423812a9   Ken Cox   staging: visorcha...
81
  {
b32c5cb84   Andy Shevchenko   staging: unisys: ...
82
  	return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s);
e423812a9   Ken Cox   staging: visorcha...
83
  }
e423812a9   Ken Cox   staging: visorcha...
84

f230ba68d   Charles Daniels   staging: unisys: ...
85
  u64 visorchannel_get_clientpartition(struct visorchannel *channel)
e423812a9   Ken Cox   staging: visorcha...
86
  {
a8a31f617   Benjamin Romer   staging: unisys: ...
87
  	return channel->chan_hdr.partition_handle;
e423812a9   Ken Cox   staging: visorcha...
88
  }
e423812a9   Ken Cox   staging: visorcha...
89

f230ba68d   Charles Daniels   staging: unisys: ...
90
91
  int visorchannel_set_clientpartition(struct visorchannel *channel,
  				     u64 partition_handle)
4f6d8a978   Don Zickus   staging: unisys: ...
92
93
94
95
  {
  	channel->chan_hdr.partition_handle = partition_handle;
  	return 0;
  }
4f6d8a978   Don Zickus   staging: unisys: ...
96

e19674ceb   David Binder   staging: unisys: ...
97
  /**
b32c5cb84   Andy Shevchenko   staging: unisys: ...
98
   * visorchannel_get_guid() - queries the GUID of the designated channel
e19674ceb   David Binder   staging: unisys: ...
99
100
   * @channel: the channel to query
   *
b32c5cb84   Andy Shevchenko   staging: unisys: ...
101
   * Return: the GUID of the provided channel
e19674ceb   David Binder   staging: unisys: ...
102
   */
b32c5cb84   Andy Shevchenko   staging: unisys: ...
103
  const guid_t *visorchannel_get_guid(struct visorchannel *channel)
e423812a9   Ken Cox   staging: visorcha...
104
  {
b32c5cb84   Andy Shevchenko   staging: unisys: ...
105
  	return &channel->guid;
e423812a9   Ken Cox   staging: visorcha...
106
  }
b32c5cb84   Andy Shevchenko   staging: unisys: ...
107
  EXPORT_SYMBOL_GPL(visorchannel_get_guid);
e423812a9   Ken Cox   staging: visorcha...
108

f230ba68d   Charles Daniels   staging: unisys: ...
109
110
  int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest,
  		      ulong nbytes)
e423812a9   Ken Cox   staging: visorcha...
111
  {
434cbf28b   Jes Sorensen   staging: unisys: ...
112
  	if (offset + nbytes > channel->nbytes)
36203e71a   Jes Sorensen   staging: unisys: ...
113
  		return -EIO;
8c3c1e47f   Erik Arfvidson   staging: unisys: ...
114
  	memcpy(dest, channel->mapped + offset, nbytes);
36203e71a   Jes Sorensen   staging: unisys: ...
115
  	return 0;
e423812a9   Ken Cox   staging: visorcha...
116
  }
e423812a9   Ken Cox   staging: visorcha...
117

f230ba68d   Charles Daniels   staging: unisys: ...
118
119
  int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest,
  		       ulong nbytes)
e423812a9   Ken Cox   staging: visorcha...
120
  {
0abb60c1c   Jes Sorensen   staging: unisys: ...
121
122
  	size_t chdr_size = sizeof(struct channel_header);
  	size_t copy_size;
69141bb8e   Prarit Bhargava   staging: unisys: ...
123

434cbf28b   Jes Sorensen   staging: unisys: ...
124
  	if (offset + nbytes > channel->nbytes)
ad44088f0   Jes Sorensen   staging: unisys: ...
125
  		return -EIO;
0abb60c1c   Jes Sorensen   staging: unisys: ...
126
  	if (offset < chdr_size) {
56df900cb   Jes Sorensen   staging: unisys: ...
127
  		copy_size = min(chdr_size - offset, nbytes);
d253058f4   Tim Sell   staging: unisys: ...
128
  		memcpy(((char *)(&channel->chan_hdr)) + offset,
8c3c1e47f   Erik Arfvidson   staging: unisys: ...
129
  		       dest, copy_size);
0abb60c1c   Jes Sorensen   staging: unisys: ...
130
  	}
8c3c1e47f   Erik Arfvidson   staging: unisys: ...
131
  	memcpy(channel->mapped + offset, dest, nbytes);
ad44088f0   Jes Sorensen   staging: unisys: ...
132
  	return 0;
e423812a9   Ken Cox   staging: visorcha...
133
  }
e423812a9   Ken Cox   staging: visorcha...
134

f230ba68d   Charles Daniels   staging: unisys: ...
135
  void *visorchannel_get_header(struct visorchannel *channel)
e423812a9   Ken Cox   staging: visorcha...
136
  {
5da77f375   David Binder   staging: unisys: ...
137
  	return &channel->chan_hdr;
e423812a9   Ken Cox   staging: visorcha...
138
  }
e423812a9   Ken Cox   staging: visorcha...
139

e19674ceb   David Binder   staging: unisys: ...
140
141
142
  /*
   * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
   * channel header
e423812a9   Ken Cox   staging: visorcha...
143
   */
bc05a9c87   Colin Ian King   staging: unisys: ...
144
  static int sig_queue_offset(struct channel_header *chan_hdr, int q)
c0616454c   David Kershner   staging: unisys: ...
145
146
147
148
  {
  	return ((chan_hdr)->ch_space_offset +
  	       ((q) * sizeof(struct signal_queue_header)));
  }
e423812a9   Ken Cox   staging: visorcha...
149

e19674ceb   David Binder   staging: unisys: ...
150
151
152
  /*
   * Return offset of a specific queue entry (data) from the beginning of a
   * channel header
e423812a9   Ken Cox   staging: visorcha...
153
   */
bc05a9c87   Colin Ian King   staging: unisys: ...
154
155
  static int sig_data_offset(struct channel_header *chan_hdr, int q,
  			   struct signal_queue_header *sig_hdr, int slot)
c0616454c   David Kershner   staging: unisys: ...
156
157
158
159
  {
  	return (sig_queue_offset(chan_hdr, q) + sig_hdr->sig_base_offset +
  	       (slot * sig_hdr->signal_size));
  }
e423812a9   Ken Cox   staging: visorcha...
160

e19674ceb   David Binder   staging: unisys: ...
161
  /*
cbe7e02f9   David Kershner   staging: unisys: ...
162
163
   * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back into
   * host memory
e423812a9   Ken Cox   staging: visorcha...
164
   */
c2a60109a   David Binder   staging: unisys: ...
165
166
  #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
  	visorchannel_write(channel, \
c0616454c   David Kershner   staging: unisys: ...
167
  			   sig_queue_offset(&channel->chan_hdr, queue) + \
1306c429e   David Binder   staging: unisys: ...
168
  			   offsetof(struct signal_queue_header, FIELD), \
c2a60109a   David Binder   staging: unisys: ...
169
  			   &((sig_hdr)->FIELD), \
1306c429e   David Binder   staging: unisys: ...
170
  			   sizeof((sig_hdr)->FIELD))
e423812a9   Ken Cox   staging: visorcha...
171

f230ba68d   Charles Daniels   staging: unisys: ...
172
173
  static int sig_read_header(struct visorchannel *channel, u32 queue,
  			   struct signal_queue_header *sig_hdr)
e423812a9   Ken Cox   staging: visorcha...
174
  {
0aca78449   Benjamin Romer   staging: unisys: ...
175
  	if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
1306c429e   David Binder   staging: unisys: ...
176
  		return -EINVAL;
e423812a9   Ken Cox   staging: visorcha...
177
178
  
  	/* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
1306c429e   David Binder   staging: unisys: ...
179
  	return visorchannel_read(channel,
c0616454c   David Kershner   staging: unisys: ...
180
  				 sig_queue_offset(&channel->chan_hdr, queue),
1306c429e   David Binder   staging: unisys: ...
181
  				 sig_hdr, sizeof(struct signal_queue_header));
e423812a9   Ken Cox   staging: visorcha...
182
  }
f230ba68d   Charles Daniels   staging: unisys: ...
183
184
185
  static int sig_read_data(struct visorchannel *channel, u32 queue,
  			 struct signal_queue_header *sig_hdr, u32 slot,
  			 void *data)
e423812a9   Ken Cox   staging: visorcha...
186
  {
c0616454c   David Kershner   staging: unisys: ...
187
  	int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
e423812a9   Ken Cox   staging: visorcha...
188
  						 sig_hdr, slot);
e423812a9   Ken Cox   staging: visorcha...
189

1306c429e   David Binder   staging: unisys: ...
190
191
  	return visorchannel_read(channel, signal_data_offset,
  				 data, sig_hdr->signal_size);
e423812a9   Ken Cox   staging: visorcha...
192
  }
f230ba68d   Charles Daniels   staging: unisys: ...
193
194
195
  static int sig_write_data(struct visorchannel *channel, u32 queue,
  			  struct signal_queue_header *sig_hdr, u32 slot,
  			  void *data)
e423812a9   Ken Cox   staging: visorcha...
196
  {
c0616454c   David Kershner   staging: unisys: ...
197
  	int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue,
a4ed0ba9a   Prarit Bhargava   staging: unisys: ...
198
  						 sig_hdr, slot);
1306c429e   David Binder   staging: unisys: ...
199
200
  	return visorchannel_write(channel, signal_data_offset,
  				  data, sig_hdr->signal_size);
e423812a9   Ken Cox   staging: visorcha...
201
  }
f230ba68d   Charles Daniels   staging: unisys: ...
202
203
  static int signalremove_inner(struct visorchannel *channel, u32 queue,
  			      void *msg)
e423812a9   Ken Cox   staging: visorcha...
204
  {
e0fed862c   Benjamin Romer   staging: unisys: ...
205
  	struct signal_queue_header sig_hdr;
1306c429e   David Binder   staging: unisys: ...
206
207
208
209
210
  	int error;
  
  	error = sig_read_header(channel, queue, &sig_hdr);
  	if (error)
  		return error;
5d295bc3e   David Kershner   staging: unisys: ...
211
  	/* No signals to remove; have caller try again. */
b12fdf7da   Zachary Warren   staging: unisys: ...
212
  	if (sig_hdr.head == sig_hdr.tail)
5d295bc3e   David Kershner   staging: unisys: ...
213
  		return -EAGAIN;
153cf7107   Benjamin Romer   staging: unisys: ...
214
  	sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
1306c429e   David Binder   staging: unisys: ...
215
216
217
  	error = sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg);
  	if (error)
  		return error;
153cf7107   Benjamin Romer   staging: unisys: ...
218
  	sig_hdr.num_received++;
e19674ceb   David Binder   staging: unisys: ...
219
  	/*
cbe7e02f9   David Kershner   staging: unisys: ...
220
221
  	 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
  	 * host memory. Required for channel sync.
e423812a9   Ken Cox   staging: visorcha...
222
  	 */
0496bedf0   Sameer Wadgaonkar   staging: unisys: ...
223
  	mb();
1306c429e   David Binder   staging: unisys: ...
224
225
226
227
228
229
  	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;
1306c429e   David Binder   staging: unisys: ...
230
  	return 0;
b12fdf7da   Zachary Warren   staging: unisys: ...
231
  }
e19674ceb   David Binder   staging: unisys: ...
232
233
234
235
236
237
238
  /**
   * 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
   *
f621a9685   David Binder   staging: unisys: ...
239
   * Return: integer error code indicating the status of the removal
e19674ceb   David Binder   staging: unisys: ...
240
   */
f230ba68d   Charles Daniels   staging: unisys: ...
241
242
  int visorchannel_signalremove(struct visorchannel *channel, u32 queue,
  			      void *msg)
b12fdf7da   Zachary Warren   staging: unisys: ...
243
  {
f621a9685   David Binder   staging: unisys: ...
244
  	int rc;
24ac1074c   Tim Sell   staging: unisys: ...
245
  	unsigned long flags;
b12fdf7da   Zachary Warren   staging: unisys: ...
246
247
  
  	if (channel->needs_lock) {
24ac1074c   Tim Sell   staging: unisys: ...
248
  		spin_lock_irqsave(&channel->remove_lock, flags);
b12fdf7da   Zachary Warren   staging: unisys: ...
249
  		rc = signalremove_inner(channel, queue, msg);
24ac1074c   Tim Sell   staging: unisys: ...
250
  		spin_unlock_irqrestore(&channel->remove_lock, flags);
b12fdf7da   Zachary Warren   staging: unisys: ...
251
252
253
  	} else {
  		rc = signalremove_inner(channel, queue, msg);
  	}
e423812a9   Ken Cox   staging: visorcha...
254

f621a9685   David Binder   staging: unisys: ...
255
  	return rc;
e423812a9   Ken Cox   staging: visorcha...
256
257
  }
  EXPORT_SYMBOL_GPL(visorchannel_signalremove);
f230ba68d   Charles Daniels   staging: unisys: ...
258
  static bool queue_empty(struct visorchannel *channel, u32 queue)
f0208b715   Cathal Mullaney   staging: unisys: ...
259
260
261
262
263
  {
  	struct signal_queue_header sig_hdr;
  
  	if (sig_read_header(channel, queue, &sig_hdr))
  		return true;
f0208b715   Cathal Mullaney   staging: unisys: ...
264
265
  	return (sig_hdr.head == sig_hdr.tail);
  }
7ec83df07   David Binder   staging: unisys: ...
266
  /**
cbe7e02f9   David Kershner   staging: unisys: ...
267
268
   * visorchannel_signalempty() - checks if the designated channel/queue contains
   *				any messages
7ec83df07   David Binder   staging: unisys: ...
269
270
271
272
273
274
   * @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
   */
f230ba68d   Charles Daniels   staging: unisys: ...
275
  bool visorchannel_signalempty(struct visorchannel *channel, u32 queue)
fdc792cd1   Neil Horman   staging: unisys: ...
276
  {
f0208b715   Cathal Mullaney   staging: unisys: ...
277
278
  	bool rc;
  	unsigned long flags;
fdc792cd1   Neil Horman   staging: unisys: ...
279

f0208b715   Cathal Mullaney   staging: unisys: ...
280
281
  	if (!channel->needs_lock)
  		return queue_empty(channel, queue);
f0208b715   Cathal Mullaney   staging: unisys: ...
282
283
284
  	spin_lock_irqsave(&channel->remove_lock, flags);
  	rc = queue_empty(channel, queue);
  	spin_unlock_irqrestore(&channel->remove_lock, flags);
fdc792cd1   Neil Horman   staging: unisys: ...
285
286
287
  	return rc;
  }
  EXPORT_SYMBOL_GPL(visorchannel_signalempty);
f230ba68d   Charles Daniels   staging: unisys: ...
288
289
  static int signalinsert_inner(struct visorchannel *channel, u32 queue,
  			      void *msg)
e423812a9   Ken Cox   staging: visorcha...
290
  {
e0fed862c   Benjamin Romer   staging: unisys: ...
291
  	struct signal_queue_header sig_hdr;
9b2cae6de   David Kershner   staging: unisys: ...
292
  	int err;
e423812a9   Ken Cox   staging: visorcha...
293

9b2cae6de   David Kershner   staging: unisys: ...
294
295
296
  	err = sig_read_header(channel, queue, &sig_hdr);
  	if (err)
  		return err;
90cb147f3   Janani Ravichandran   staging: unisys: ...
297
  	sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots;
153cf7107   Benjamin Romer   staging: unisys: ...
298
299
  	if (sig_hdr.head == sig_hdr.tail) {
  		sig_hdr.num_overflows++;
9b2cae6de   David Kershner   staging: unisys: ...
300
301
302
  		err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows);
  		if (err)
  			return err;
1306c429e   David Binder   staging: unisys: ...
303
  		return -EIO;
e423812a9   Ken Cox   staging: visorcha...
304
  	}
9b2cae6de   David Kershner   staging: unisys: ...
305
306
307
  	err = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg);
  	if (err)
  		return err;
153cf7107   Benjamin Romer   staging: unisys: ...
308
  	sig_hdr.num_sent++;
e19674ceb   David Binder   staging: unisys: ...
309
  	/*
cbe7e02f9   David Kershner   staging: unisys: ...
310
311
  	 * For each data field in SIGNAL_QUEUE_HEADER that was modified, update
  	 * host memory. Required for channel sync.
e423812a9   Ken Cox   staging: visorcha...
312
  	 */
0496bedf0   Sameer Wadgaonkar   staging: unisys: ...
313
  	mb();
9b2cae6de   David Kershner   staging: unisys: ...
314
315
316
317
318
319
  	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;
1306c429e   David Binder   staging: unisys: ...
320
  	return 0;
b12fdf7da   Zachary Warren   staging: unisys: ...
321
  }
3a8bc4b72   David Binder   staging: unisys: ...
322
  /*
90476670a   Sameer Wadgaonkar   staging: unisys: ...
323
324
325
   * visorchannel_create() - creates the struct visorchannel abstraction for a
   *                         data area in memory, but does NOT modify this data
   *                         area
3995c5da2   David Kershner   staging: unisys: ...
326
   * @physaddr:      physical address of start of channel
3995c5da2   David Kershner   staging: unisys: ...
327
   * @gfp:           gfp_t to use when allocating memory for the data struct
d7f1589a1   David Kershner   staging: unisys: ...
328
   * @guid:          GUID that identifies channel type;
3995c5da2   David Kershner   staging: unisys: ...
329
330
331
332
333
334
335
   * @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
   */
90476670a   Sameer Wadgaonkar   staging: unisys: ...
336
337
  struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp,
  					 const guid_t *guid, bool needs_lock)
3995c5da2   David Kershner   staging: unisys: ...
338
339
340
341
342
343
344
345
346
347
348
  {
  	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;
3995c5da2   David Kershner   staging: unisys: ...
349
350
351
  	channel->needs_lock = needs_lock;
  	spin_lock_init(&channel->insert_lock);
  	spin_lock_init(&channel->remove_lock);
3995c5da2   David Kershner   staging: unisys: ...
352
  	/*
cbe7e02f9   David Kershner   staging: unisys: ...
353
354
355
356
  	 * 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.
3995c5da2   David Kershner   staging: unisys: ...
357
  	 */
b35fae7e2   David Binder   staging: unisys: ...
358
  	channel->requested = request_mem_region(physaddr, size, VISOR_DRV_NAME);
b32c5cb84   Andy Shevchenko   staging: unisys: ...
359
  	if (!channel->requested && !guid_equal(guid, &visor_video_guid))
51646f4d4   David Kershner   staging: unisys: ...
360
361
  		/* we only care about errors if this is not the video channel */
  		goto err_destroy_channel;
3995c5da2   David Kershner   staging: unisys: ...
362
363
364
365
366
  	channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
  	if (!channel->mapped) {
  		release_mem_region(physaddr, size);
  		goto err_destroy_channel;
  	}
3995c5da2   David Kershner   staging: unisys: ...
367
368
  	channel->physaddr = physaddr;
  	channel->nbytes = size;
d7f1589a1   David Kershner   staging: unisys: ...
369
  	err = visorchannel_read(channel, 0, &channel->chan_hdr, size);
3995c5da2   David Kershner   staging: unisys: ...
370
371
  	if (err)
  		goto err_destroy_channel;
d7f1589a1   David Kershner   staging: unisys: ...
372
  	size = (ulong)channel->chan_hdr.size;
3995c5da2   David Kershner   staging: unisys: ...
373
374
375
376
  	memunmap(channel->mapped);
  	if (channel->requested)
  		release_mem_region(channel->physaddr, channel->nbytes);
  	channel->mapped = NULL;
d7f1589a1   David Kershner   staging: unisys: ...
377
378
  	channel->requested = request_mem_region(channel->physaddr, size,
  						VISOR_DRV_NAME);
b32c5cb84   Andy Shevchenko   staging: unisys: ...
379
  	if (!channel->requested && !guid_equal(guid, &visor_video_guid))
51646f4d4   David Kershner   staging: unisys: ...
380
381
  		/* we only care about errors if this is not the video channel */
  		goto err_destroy_channel;
d7f1589a1   David Kershner   staging: unisys: ...
382
  	channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB);
3995c5da2   David Kershner   staging: unisys: ...
383
  	if (!channel->mapped) {
d7f1589a1   David Kershner   staging: unisys: ...
384
  		release_mem_region(channel->physaddr, size);
3995c5da2   David Kershner   staging: unisys: ...
385
386
  		goto err_destroy_channel;
  	}
d7f1589a1   David Kershner   staging: unisys: ...
387
  	channel->nbytes = size;
b32c5cb84   Andy Shevchenko   staging: unisys: ...
388
  	guid_copy(&channel->guid, guid);
3995c5da2   David Kershner   staging: unisys: ...
389
390
391
392
393
394
  	return channel;
  
  err_destroy_channel:
  	visorchannel_destroy(channel);
  	return NULL;
  }
3995c5da2   David Kershner   staging: unisys: ...
395
  /**
e19674ceb   David Binder   staging: unisys: ...
396
397
398
399
400
401
   * 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
   *
264f7b8ac   David Binder   staging: unisys: ...
402
   * Return: integer error code indicating the status of the insertion
e19674ceb   David Binder   staging: unisys: ...
403
   */
f230ba68d   Charles Daniels   staging: unisys: ...
404
405
  int visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
  			      void *msg)
b12fdf7da   Zachary Warren   staging: unisys: ...
406
  {
264f7b8ac   David Binder   staging: unisys: ...
407
  	int rc;
24ac1074c   Tim Sell   staging: unisys: ...
408
  	unsigned long flags;
b12fdf7da   Zachary Warren   staging: unisys: ...
409
410
  
  	if (channel->needs_lock) {
24ac1074c   Tim Sell   staging: unisys: ...
411
  		spin_lock_irqsave(&channel->insert_lock, flags);
b12fdf7da   Zachary Warren   staging: unisys: ...
412
  		rc = signalinsert_inner(channel, queue, msg);
24ac1074c   Tim Sell   staging: unisys: ...
413
  		spin_unlock_irqrestore(&channel->insert_lock, flags);
b12fdf7da   Zachary Warren   staging: unisys: ...
414
415
416
  	} else {
  		rc = signalinsert_inner(channel, queue, msg);
  	}
e423812a9   Ken Cox   staging: visorcha...
417

264f7b8ac   David Binder   staging: unisys: ...
418
  	return rc;
e423812a9   Ken Cox   staging: visorcha...
419
420
  }
  EXPORT_SYMBOL_GPL(visorchannel_signalinsert);