diff options
Diffstat (limited to 'drivers/uwb/drp-avail.c')
-rw-r--r-- | drivers/uwb/drp-avail.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c new file mode 100644 index 000000000000..3febd8552808 --- /dev/null +++ b/drivers/uwb/drp-avail.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * DRP availability management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | * | ||
22 | * Manage DRP Availability (the MAS available for DRP | ||
23 | * reservations). Thus: | ||
24 | * | ||
25 | * - Handle DRP Availability Change notifications | ||
26 | * | ||
27 | * - Allow the reservation manager to indicate MAS reserved/released | ||
28 | * by local (owned by/targeted at the radio controller) | ||
29 | * reservations. | ||
30 | * | ||
31 | * - Based on the two sources above, generate a DRP Availability IE to | ||
32 | * be included in the beacon. | ||
33 | * | ||
34 | * See also the documentation for struct uwb_drp_avail. | ||
35 | */ | ||
36 | |||
37 | #include <linux/errno.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/device.h> | ||
40 | #include <linux/bitmap.h> | ||
41 | #include "uwb-internal.h" | ||
42 | |||
43 | /** | ||
44 | * uwb_drp_avail_init - initialize an RC's MAS availability | ||
45 | * | ||
46 | * All MAS are available initially. The RC will inform use which | ||
47 | * slots are used for the BP (it may change in size). | ||
48 | */ | ||
49 | void uwb_drp_avail_init(struct uwb_rc *rc) | ||
50 | { | ||
51 | bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS); | ||
52 | bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS); | ||
53 | bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Determine MAS available for new local reservations. | ||
58 | * | ||
59 | * avail = global & local & pending | ||
60 | */ | ||
61 | static void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail) | ||
62 | { | ||
63 | bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); | ||
64 | bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS); | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation | ||
69 | * @rc: the radio controller | ||
70 | * @mas: the MAS to reserve | ||
71 | * | ||
72 | * Returns 0 on success, or -EBUSY if the MAS requested aren't available. | ||
73 | */ | ||
74 | int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
75 | { | ||
76 | struct uwb_mas_bm avail; | ||
77 | |||
78 | uwb_drp_available(rc, &avail); | ||
79 | if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS)) | ||
80 | return -EBUSY; | ||
81 | |||
82 | bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * uwb_drp_avail_reserve - reserve MAS for an established reservation | ||
88 | * @rc: the radio controller | ||
89 | * @mas: the MAS to reserve | ||
90 | */ | ||
91 | void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
92 | { | ||
93 | bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
94 | bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); | ||
95 | rc->drp_avail.ie_valid = false; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * uwb_drp_avail_release - release MAS from a pending or established reservation | ||
100 | * @rc: the radio controller | ||
101 | * @mas: the MAS to release | ||
102 | */ | ||
103 | void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
104 | { | ||
105 | bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); | ||
106 | bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
107 | rc->drp_avail.ie_valid = false; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * uwb_drp_avail_ie_update - update the DRP Availability IE | ||
112 | * @rc: the radio controller | ||
113 | * | ||
114 | * avail = global & local | ||
115 | */ | ||
116 | void uwb_drp_avail_ie_update(struct uwb_rc *rc) | ||
117 | { | ||
118 | struct uwb_mas_bm avail; | ||
119 | |||
120 | bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); | ||
121 | |||
122 | rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY; | ||
123 | rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8; | ||
124 | uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail); | ||
125 | rc->drp_avail.ie_valid = true; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Create an unsigned long from a buffer containing a byte stream. | ||
130 | * | ||
131 | * @array: pointer to buffer | ||
132 | * @itr: index of buffer from where we start | ||
133 | * @len: the buffer's remaining size may not be exact multiple of | ||
134 | * sizeof(unsigned long), @len is the length of buffer that needs | ||
135 | * to be converted. This will be sizeof(unsigned long) or smaller | ||
136 | * (BUG if not). If it is smaller then we will pad the remaining | ||
137 | * space of the result with zeroes. | ||
138 | */ | ||
139 | static | ||
140 | unsigned long get_val(u8 *array, size_t itr, size_t len) | ||
141 | { | ||
142 | unsigned long val = 0; | ||
143 | size_t top = itr + len; | ||
144 | |||
145 | BUG_ON(len > sizeof(val)); | ||
146 | |||
147 | while (itr < top) { | ||
148 | val <<= 8; | ||
149 | val |= array[top - 1]; | ||
150 | top--; | ||
151 | } | ||
152 | val <<= 8 * (sizeof(val) - len); /* padding */ | ||
153 | return val; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * Initialize bitmap from data buffer. | ||
158 | * | ||
159 | * The bitmap to be converted could come from a IE, for example a | ||
160 | * DRP Availability IE. | ||
161 | * From ECMA-368 1.0 [16.8.7]: " | ||
162 | * octets: 1 1 N * (0 to 32) | ||
163 | * Element ID Length (=N) DRP Availability Bitmap | ||
164 | * | ||
165 | * The DRP Availability Bitmap field is up to 256 bits long, one | ||
166 | * bit for each MAS in the superframe, where the least-significant | ||
167 | * bit of the field corresponds to the first MAS in the superframe | ||
168 | * and successive bits correspond to successive MASs." | ||
169 | * | ||
170 | * The DRP Availability bitmap is in octets from 0 to 32, so octet | ||
171 | * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32 | ||
172 | * octets, the bits in octets not included at the end of the bitmap are | ||
173 | * treated as zero. In this case (when the bitmap is smaller than 32 | ||
174 | * octets) the MAS represented range from MAS 1 to MAS (size of bitmap) | ||
175 | * with the last octet still containing bits for MAS 1-8, etc. | ||
176 | * | ||
177 | * For example: | ||
178 | * F00F0102 03040506 0708090A 0B0C0D0E 0F010203 | ||
179 | * ^^^^ | ||
180 | * |||| | ||
181 | * |||| | ||
182 | * |||\LSB of byte is MAS 9 | ||
183 | * ||\MSB of byte is MAS 16 | ||
184 | * |\LSB of first byte is MAS 1 | ||
185 | * \ MSB of byte is MAS 8 | ||
186 | * | ||
187 | * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11] | ||
188 | * | ||
189 | * The resulting bitmap will have the following mapping: | ||
190 | * bit position 0 == MAS 1 | ||
191 | * bit position 1 == MAS 2 | ||
192 | * ... | ||
193 | * bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS | ||
194 | * | ||
195 | * @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP) | ||
196 | * @buffer: pointer to buffer containing bitmap data in big endian | ||
197 | * format (MSB first) | ||
198 | * @buffer_size:number of bytes with which bitmap should be initialized | ||
199 | */ | ||
200 | static | ||
201 | void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer, | ||
202 | size_t buffer_size) | ||
203 | { | ||
204 | u8 *buffer = _buffer; | ||
205 | size_t itr, len; | ||
206 | unsigned long val; | ||
207 | |||
208 | itr = 0; | ||
209 | while (itr < buffer_size) { | ||
210 | len = buffer_size - itr >= sizeof(val) ? | ||
211 | sizeof(val) : buffer_size - itr; | ||
212 | val = get_val(buffer, itr, len); | ||
213 | bmp_itr[itr / sizeof(val)] = val; | ||
214 | itr += sizeof(val); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Extract DRP Availability bitmap from the notification. | ||
221 | * | ||
222 | * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes | ||
223 | * We convert that to our internal representation. | ||
224 | */ | ||
225 | static | ||
226 | int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp) | ||
227 | { | ||
228 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
229 | struct uwb_rc_evt_drp_avail *drp_evt; | ||
230 | int result = -EINVAL; | ||
231 | |||
232 | /* Is there enough data to decode the event? */ | ||
233 | if (evt->notif.size < sizeof(*drp_evt)) { | ||
234 | dev_err(dev, "DRP Availability Change: Not enough " | ||
235 | "data to decode event [%zu bytes, %zu " | ||
236 | "needed]\n", evt->notif.size, sizeof(*drp_evt)); | ||
237 | goto error; | ||
238 | } | ||
239 | drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb); | ||
240 | buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8); | ||
241 | result = 0; | ||
242 | error: | ||
243 | return result; | ||
244 | } | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Process an incoming DRP Availability notification. | ||
249 | * | ||
250 | * @evt: Event information (packs the actual event data, which | ||
251 | * radio controller it came to, etc). | ||
252 | * | ||
253 | * @returns: 0 on success (so uwbd() frees the event buffer), < 0 | ||
254 | * on error. | ||
255 | * | ||
256 | * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that | ||
257 | * the MAS slot is available, bits set to ZERO indicate that the slot | ||
258 | * is busy. | ||
259 | * | ||
260 | * So we clear available slots, we set used slots :) | ||
261 | * | ||
262 | * The notification only marks non-availability based on the BP and | ||
263 | * received DRP IEs that are not for this radio controller. A copy of | ||
264 | * this bitmap is needed to generate the real availability (which | ||
265 | * includes local and pending reservations). | ||
266 | * | ||
267 | * The DRP Availability IE that this radio controller emits will need | ||
268 | * to be updated. | ||
269 | */ | ||
270 | int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt) | ||
271 | { | ||
272 | int result; | ||
273 | struct uwb_rc *rc = evt->rc; | ||
274 | DECLARE_BITMAP(bmp, UWB_NUM_MAS); | ||
275 | |||
276 | result = uwbd_evt_get_drp_avail(evt, bmp); | ||
277 | if (result < 0) | ||
278 | return result; | ||
279 | |||
280 | mutex_lock(&rc->rsvs_mutex); | ||
281 | bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS); | ||
282 | rc->drp_avail.ie_valid = false; | ||
283 | mutex_unlock(&rc->rsvs_mutex); | ||
284 | |||
285 | uwb_rsv_sched_update(rc); | ||
286 | |||
287 | return 0; | ||
288 | } | ||