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