xref: /netbsd-src/sys/rump/net/lib/libshmif/shmif_busops.c (revision dc24e61692cba434059d23b3a91d27e09fb69d3b)
1 /*	$NetBSD: shmif_busops.c,v 1.3 2010/08/15 18:47:38 pooka Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
5  *
6  * Development of this software was supported by The Nokia Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: shmif_busops.c,v 1.3 2010/08/15 18:47:38 pooka Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/atomic.h>
35 
36 #include "shmifvar.h"
37 
38 #ifndef _KERNEL
39 #include <assert.h>
40 #define KASSERT(a) assert(a)
41 #else
42 #include <rump/rumpuser.h>
43 #endif
44 
45 #define LOCK_UNLOCKED	0
46 #define LOCK_LOCKED	1
47 #define LOCK_COOLDOWN	1001
48 
49 /*
50  * This locking needs work and will misbehave severely if:
51  * 1) the backing memory has to be paged in
52  * 2) some lockholder exits while holding the lock
53  */
54 void
55 shmif_lockbus(struct shmif_mem *busmem)
56 {
57 	int i = 0;
58 
59 	while (__predict_false(atomic_cas_32(&busmem->shm_lock,
60 	    LOCK_UNLOCKED, LOCK_LOCKED) == LOCK_LOCKED)) {
61 		if (__predict_false(++i > LOCK_COOLDOWN)) {
62 			uint64_t sec, nsec;
63 			int error;
64 
65 			sec = 0;
66 			nsec = 1000*1000; /* 1ms */
67 			rumpuser_nanosleep(&sec, &nsec, &error);
68 			i = 0;
69 		}
70 		continue;
71 	}
72 	membar_enter();
73 }
74 
75 void
76 shmif_unlockbus(struct shmif_mem *busmem)
77 {
78 	unsigned int old;
79 
80 	membar_exit();
81 	old = atomic_swap_32(&busmem->shm_lock, LOCK_UNLOCKED);
82 	KASSERT(old == LOCK_LOCKED);
83 }
84 
85 uint32_t
86 shmif_advance(uint32_t oldoff, uint32_t delta)
87 {
88 	uint32_t newoff;
89 
90 	newoff = oldoff + delta;
91 	if (newoff >= BUSMEM_DATASIZE)
92 		newoff -= (BUSMEM_DATASIZE);
93 	return newoff;
94 
95 }
96 
97 uint32_t
98 shmif_busread(struct shmif_mem *busmem, void *dest, uint32_t off, size_t len,
99 	bool *wrap)
100 {
101 	size_t chunk;
102 
103 	KASSERT(len < (BUSMEM_DATASIZE) && off <= BUSMEM_DATASIZE);
104 	chunk = MIN(len, BUSMEM_DATASIZE - off);
105 	memcpy(dest, busmem->shm_data + off, chunk);
106 	len -= chunk;
107 
108 	if (len == 0)
109 		return off + chunk;
110 
111 	/* else, wraps around */
112 	off = 0;
113 	*wrap = true;
114 
115 	/* finish reading */
116 	memcpy((uint8_t *)dest + chunk, busmem->shm_data + off, len);
117 	return off + len;
118 }
119 
120 void
121 shmif_advancefirst(struct shmif_mem *busmem, uint32_t off, size_t len)
122 {
123 
124 	while (off <= busmem->shm_first + sizeof(struct shmif_pkthdr)
125 	    && off+len > busmem->shm_first) {
126 		DPRINTF(("advancefirst: old offset %d, ", busmem->shm_first));
127 		busmem->shm_first = shmif_nextpktoff(busmem, busmem->shm_first);
128 		DPRINTF(("new offset: %d\n", busmem->shm_first));
129 	}
130 }
131 
132 uint32_t
133 shmif_buswrite(struct shmif_mem *busmem, uint32_t off, void *data, size_t len,
134 	bool *wrap)
135 {
136 	size_t chunk;
137 
138 	KASSERT(len < (BUSMEM_DATASIZE) && off <= BUSMEM_DATASIZE);
139 
140 	chunk = MIN(len, BUSMEM_DATASIZE - off);
141 	len -= chunk;
142 
143 	shmif_advancefirst(busmem, off, chunk + (len ? 1 : 0));
144 
145 	memcpy(busmem->shm_data + off, data, chunk);
146 
147 	DPRINTF(("buswrite: wrote %d bytes to %d", chunk, off));
148 
149 	if (len == 0) {
150 		DPRINTF(("\n"));
151 		return off + chunk;
152 	}
153 
154 	DPRINTF((", wrapped bytes %d to 0\n", len));
155 
156 	/* else, wraps around */
157 	off = 0;
158 	*wrap = true;
159 
160 	shmif_advancefirst(busmem, off, len);
161 
162 	/* finish writing */
163 	memcpy(busmem->shm_data + off, (uint8_t *)data + chunk, len);
164 	return off + len;
165 }
166 
167 uint32_t
168 shmif_nextpktoff(struct shmif_mem *busmem, uint32_t oldoff)
169 {
170 	struct shmif_pkthdr sp;
171 	bool dummy;
172 
173 	shmif_busread(busmem, &sp, oldoff, sizeof(sp), &dummy);
174 	KASSERT(sp.sp_len < BUSMEM_DATASIZE);
175 
176 	return shmif_advance(oldoff, sizeof(sp) + sp.sp_len);
177 }
178