aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mvp/mvpkm/qp.h
blob: a8d7ac1ea913788b714112b38519e3f63776bab3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/*
 * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support
 *
 * Copyright (C) 2010-2012 VMware, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#line 5

/**
 * @file
 *
 * @brief MVP Queue Pairs function and structure declarations
 *
 * MVP Queue Pairs:
 *
 * Queue pairs are intended to be a generic bulk data transport mechanism
 * between the guest and host kernels. The queue pair abstraction is based
 * on two ring buffers (queues) placed on a shared memory region mapped
 * into both guest and host kernel address spaces.
 *
 * NOTE: Queue pairs are SINGLE-READER, SINGLE-WRITER. Any caller is
 * responsible for multi-reader/writer serialization!!!
 *
 * There are a maximum of QP_MAX_QUEUE_PAIRS in the system, with a maximum
 * size of QP_MAX_CAPACITY per pair. Each queue pair is identified by
 * an ID.
 *
 * Each peer follows a producer-consumer model in which one side is the
 * producer on one queue, and the other side is the consumer on that queue
 * (and vice-versa for its pair).
 *
 * Data is enqueued and dequeued into the pair in transactional stages,
 * meaning each enqueue/dequeue can be followed by zero or more
 * enqueue/dequeues, but the enqueue/dequeue is not visible to the peer
 * until it has been committed with the *Commit() function.
 * In PVTCP, for example, this is used to enqueue a short header, then
 * followed by 'segments' of iovecs, then followed by a commit. This
 * model prevents a peer from reading the header, expecting a payload,
 * but not being able to read the payload because it hasn't been
 * enqueued yet.
 *
 * Queue Pair setup:
 *
 * Before data can be passed, the guest and host kernel must perform
 * the following connection handshake:
 *
 * 1). A host kernel service registers a listener with the queue pair
 *     subsystem with a callback to be called when guests create
 *     and attach to a shared memory region.
 *
 * 2). Guest initiates an QP_Attach() operation to a shared memory region
 *     keyed by ID. This step allocates memory, maps it into the host
 *     address space, and optionally notifies any host services who are
 *     listening for attach requests from the guest (see previous step).
 *     Host listeners are provided with a copy of the initialization
 *     arguments used by the guest (id, size, service type). All registered
 *     listeners are iterated over until one of them handles the attach
 *     request and acknowledges with QP_SUCCESS.
 *
 * 3). The registered host callback is called, notifying the host that
 *     the guest has attached.
 *
 * 4). The host can now QP_Attach() to the shared memory region with the same
 *     arguments as the guest. The queue pair is now well formed and enqueues
 *     and dequeues can proceed on either side.
 *
 * Queue Pair teardown:
 *
 * 1). As before, teardowns are initiated by the guest. Hosts can register
 *     a callback to be called upon detach. Guests initiate a teardown
 *     through a call to QP_Detach().
 *
 * 2). Registered hosts are notified through the aforementioned callback.
 * 3). The host service can call QP_Detach() at its own leisure. Memory
 *     is freed, the queue pair is destroyed.
 *
 * If at any point the guest unexpectedly shuts down, the host will be
 * notified at monitor shutdown time. Memory is freed, and the queue
 * pair is destroyed.
 *
 */

#ifndef _QP_H
#define _QP_H

#define INCLUDE_ALLOW_MODULE
#define INCLUDE_ALLOW_MONITOR
#define INCLUDE_ALLOW_PV
#define INCLUDE_ALLOW_GPL
#include "include_check.h"

//#define QP_DEBUG 1

typedef enum QPState {
   QP_STATE_FREE = 0x1,          ///< No peers, not memory-backed
   QP_STATE_CONNECTED,           ///< Both peers attached , memory backed
   QP_STATE_GUEST_ATTACHED,      ///< Guest allocated memory, host not yet attached
   QP_STATE_MAX                  // leave this at the end!
} QPState;

typedef struct QPId {
   uint32 context;
   uint32 resource;
} QPId;

/*
 * Initialization arguments for each queue pair
 */
typedef struct QPInitArgs {
   QPId id;                  ///< Shared memory region ID
   uint32 capacity;          ///< Total size of shared region in bytes
   uint32 type;              ///< Type of queue pair (PVTCP, other)...
} QPInitArgs;

/*
 * Placed on the shared region, two per region
 */
typedef struct QHandle {
   volatile uint32 head;                    ///< queue head offset
   volatile uint32 tail;                    ///< queue tail offset
   volatile uint32 phantom_head;            ///< queue shadow head offset
   volatile uint32 phantom_tail;            ///< queue shadow tail offset
   uint8 data[0];                           ///< start of data, runs off
                                            //        the struct
} QHandle;

/*
 * Local to each peer
 */
typedef struct QPHandle {
   QPId          id;                        ///< shared memory region ID
   uint32        capacity;                  ///< size of region in bytes
   QHandle      *produceQ;                  ///< producer queue
   QHandle      *consumeQ;                  ///< consumer queue
   uint32        queueSize;                 ///< size of each queue in bytes
   uint32        type;                      ///< type of queue pair

   /*
    * Following fields unused by guest
    */
   QPState       state;
   void        (*peerDetachCB)(void* data); ///< detach notification callback
   void         *detachData;                ///< data for the detach cb
   struct page  **pages;                    ///< page pointers for shared region
} QPHandle;

/*
 * QP Error codes
 */
#define QP_SUCCESS                    0
#define QP_ERROR_NO_MEM             (-1)
#define QP_ERROR_INVALID_HANDLE     (-2)
#define QP_ERROR_INVALID_ARGS       (-3)
#define QP_ERROR_ALREADY_ATTACHED   (-4)

/*
 * Hard-coded limits
 */
#define QP_MIN_CAPACITY            (PAGE_SIZE * 2)
#define QP_MAX_CAPACITY            (1024*1024)                 // 1M
#define QP_MAX_QUEUE_PAIRS         32
#define QP_MAX_ID                  QP_MAX_QUEUE_PAIRS
#define QP_MAX_LISTENERS           QP_MAX_QUEUE_PAIRS
#define QP_MAX_PAGES               (QP_MAX_CAPACITY/PAGE_SIZE) // 256 pages

#define QP_INVALID_ID              0xFFFFFFFF
#define QP_INVALID_SIZE            0xFFFFFFFF
#define QP_INVALID_REGION          0xFFFFFFFF
#define QP_INVALID_TYPE            0xFFFFFFFF

#ifdef __KERNEL__
/**
 *  @brief Utility function to sanity check arguments
 *  @param args argument structure to check
 *  @return true if arguments are sane, false otherwise
 */
static inline
_Bool QP_CheckArgs(QPInitArgs *args)
{
   if (!args                                                                  ||
       !is_power_of_2(args->capacity)                                         ||
        (args->capacity < QP_MIN_CAPACITY)                                    ||
        (args->capacity > QP_MAX_CAPACITY)                                    ||
       !(args->id.resource < QP_MAX_ID || args->id.resource == QP_INVALID_ID) ||
        (args->type == QP_INVALID_TYPE)) {
      return false;
   } else {
      return true;
   }
}
#endif


/**
 *  @brief Utility function to sanity check a queue pair handle
 *  @param qp handle to the queue pair
 *  @return true if the handle is sane, false otherwise
 */
static inline
_Bool QP_CheckHandle(QPHandle *qp)
{
#ifdef MVP_DEBUG
   if (!(qp)                                            ||
       !(qp->produceQ)                                  ||
       !(qp->consumeQ)                                  ||
        (qp->state >= (uint32)QP_STATE_MAX)             ||
       !(qp->queueSize < (QP_MAX_CAPACITY/2))) {
      return false;
   } else {
      return true;
   }
#else
   return true;
#endif
}


/**
 *  @brief Initializes an invalid handle
 *  @param[in, out] qp handle to the queue pair
 */
static inline void
QP_MakeInvalidQPHandle(QPHandle *qp)
{
   if (!qp) {
      return;
   }

   qp->id.context       = QP_INVALID_ID;
   qp->id.resource      = QP_INVALID_ID;
   qp->capacity         = QP_INVALID_SIZE;
   qp->produceQ         = NULL;
   qp->consumeQ         = NULL;
   qp->queueSize        = QP_INVALID_SIZE;
   qp->type             = QP_INVALID_TYPE;
   qp->state            = QP_STATE_FREE;
   qp->peerDetachCB     = NULL;
   qp->detachData       = NULL;
}

/*
 * Host only
 */
typedef int32 (*QPListener)(const QPInitArgs*);
int32 QP_RegisterListener(const QPListener);
int32 QP_UnregisterListener(const QPListener);
int32 QP_RegisterDetachCB(QPHandle *qp, void (*callback)(void*), void *data);


/*
 * Host and guest specific implementations, see qp_host.c and qp_guest.c
 */
int32 QP_Attach(QPInitArgs *args, QPHandle** qp);
int32 QP_Detach(QPHandle* qp);
int32 QP_Notify(QPInitArgs *args);

/*
 * Common implementation, see qp_common.c
 */
int32 QP_EnqueueSpace(QPHandle *qp);
int32 QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t length);
int32 QP_EnqueueCommit(QPHandle *qp);
int32 QP_EnqueueReset(QPHandle *qp);

static inline int32
QP_EnqueueAtomic(QPHandle *qp, const void *buf, size_t length)
{
   int32 rc;
   QP_EnqueueReset(qp);
   rc = QP_EnqueueSegment(qp, buf, length);
   if (rc < 0) {
      return rc;
   } else {
      QP_EnqueueCommit(qp);
   }
   return rc;
}

int32 QP_DequeueSpace(QPHandle *qp);
int32 QP_DequeueSegment(QPHandle *qp, const void *buf, size_t length);
int32 QP_DequeueReset(QPHandle *qp);
int32 QP_DequeueCommit(QPHandle *qp);

static inline int32
QP_DequeueAtomic(QPHandle *qp, const void *buf, size_t length)
{
   int32 rc;
   QP_DequeueReset(qp);
   rc = QP_DequeueSegment(qp, buf, length);
   if (rc < 0) {
      return rc;
   } else {
      QP_DequeueCommit(qp);
   }
   return rc;
}

/*
 * HVC methods and signatures
 */
#define MVP_QP_SIGNATURE       0x53525051                   ///< 'QPRS'
#define MVP_QP_ATTACH          (MVP_OBJECT_CUSTOM_BASE + 0) ///< attach to a queue pair
#define MVP_QP_DETACH          (MVP_OBJECT_CUSTOM_BASE + 1) ///< detach from a queue pair
#define MVP_QP_NOTIFY          (MVP_OBJECT_CUSTOM_BASE + 2) ///< notify host of attach
#define MVP_QP_LAST            (MVP_OBJECT_CUSTOM_BASE + 3) ///< Number of methods

/*
 * Debug macros
 */
#ifdef QP_DEBUG
   #ifdef IN_MONITOR
      #define QP_DBG(...) Log(__VA_ARGS__)
   #else
      #define QP_DBG(...) printk(KERN_INFO __VA_ARGS__)
   #endif
#else
   #define QP_DBG(...)
#endif

#endif