linux/drivers/uwb/drp-avail.c
<<
>>
Prefs
   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 */
  49void 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 */
  61void 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 */
  74int 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 */
  91void 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 */
 103void 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        uwb_rsv_handle_drp_avail_change(rc);
 109}
 110
 111/**
 112 * uwb_drp_avail_ie_update - update the DRP Availability IE
 113 * @rc: the radio controller
 114 *
 115 * avail = global & local
 116 */
 117void uwb_drp_avail_ie_update(struct uwb_rc *rc)
 118{
 119        struct uwb_mas_bm avail;
 120
 121        bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
 122
 123        rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY;
 124        rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8;
 125        uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail);
 126        rc->drp_avail.ie_valid = true;
 127}
 128
 129/**
 130 * Create an unsigned long from a buffer containing a byte stream.
 131 *
 132 * @array: pointer to buffer
 133 * @itr:   index of buffer from where we start
 134 * @len:   the buffer's remaining size may not be exact multiple of
 135 *         sizeof(unsigned long), @len is the length of buffer that needs
 136 *         to be converted. This will be sizeof(unsigned long) or smaller
 137 *         (BUG if not). If it is smaller then we will pad the remaining
 138 *         space of the result with zeroes.
 139 */
 140static
 141unsigned long get_val(u8 *array, size_t itr, size_t len)
 142{
 143        unsigned long val = 0;
 144        size_t top = itr + len;
 145
 146        BUG_ON(len > sizeof(val));
 147
 148        while (itr < top) {
 149                val <<= 8;
 150                val |= array[top - 1];
 151                top--;
 152        }
 153        val <<= 8 * (sizeof(val) - len); /* padding */
 154        return val;
 155}
 156
 157/**
 158 * Initialize bitmap from data buffer.
 159 *
 160 * The bitmap to be converted could come from a IE, for example a
 161 * DRP Availability IE.
 162 * From ECMA-368 1.0 [16.8.7]: "
 163 * octets: 1            1               N * (0 to 32)
 164 *         Element ID   Length (=N)     DRP Availability Bitmap
 165 *
 166 * The DRP Availability Bitmap field is up to 256 bits long, one
 167 * bit for each MAS in the superframe, where the least-significant
 168 * bit of the field corresponds to the first MAS in the superframe
 169 * and successive bits correspond to successive MASs."
 170 *
 171 * The DRP Availability bitmap is in octets from 0 to 32, so octet
 172 * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32
 173 * octets, the bits in octets not included at the end of the bitmap are
 174 * treated as zero. In this case (when the bitmap is smaller than 32
 175 * octets) the MAS represented range from MAS 1 to MAS (size of bitmap)
 176 * with the last octet still containing bits for MAS 1-8, etc.
 177 *
 178 * For example:
 179 * F00F0102 03040506 0708090A 0B0C0D0E 0F010203
 180 * ^^^^
 181 * ||||
 182 * ||||
 183 * |||\LSB of byte is MAS 9
 184 * ||\MSB of byte is MAS 16
 185 * |\LSB of first byte is MAS 1
 186 * \ MSB of byte is MAS 8
 187 *
 188 * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11]
 189 *
 190 * The resulting bitmap will have the following mapping:
 191 *      bit position 0 == MAS 1
 192 *      bit position 1 == MAS 2
 193 *      ...
 194 *      bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS
 195 *
 196 * @bmp_itr:    pointer to bitmap (can be declared with DECLARE_BITMAP)
 197 * @buffer:     pointer to buffer containing bitmap data in big endian
 198 *              format (MSB first)
 199 * @buffer_size:number of bytes with which bitmap should be initialized
 200 */
 201static
 202void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer,
 203                   size_t buffer_size)
 204{
 205        u8 *buffer = _buffer;
 206        size_t itr, len;
 207        unsigned long val;
 208
 209        itr = 0;
 210        while (itr < buffer_size) {
 211                len = buffer_size - itr >= sizeof(val) ?
 212                        sizeof(val) : buffer_size - itr;
 213                val = get_val(buffer, itr, len);
 214                bmp_itr[itr / sizeof(val)] = val;
 215                itr += sizeof(val);
 216        }
 217}
 218
 219
 220/**
 221 * Extract DRP Availability bitmap from the notification.
 222 *
 223 * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes
 224 * We convert that to our internal representation.
 225 */
 226static
 227int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp)
 228{
 229        struct device *dev = &evt->rc->uwb_dev.dev;
 230        struct uwb_rc_evt_drp_avail *drp_evt;
 231        int result = -EINVAL;
 232
 233        /* Is there enough data to decode the event? */
 234        if (evt->notif.size < sizeof(*drp_evt)) {
 235                dev_err(dev, "DRP Availability Change: Not enough "
 236                        "data to decode event [%zu bytes, %zu "
 237                        "needed]\n", evt->notif.size, sizeof(*drp_evt));
 238                goto error;
 239        }
 240        drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb);
 241        buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8);
 242        result = 0;
 243error:
 244        return result;
 245}
 246
 247
 248/**
 249 * Process an incoming DRP Availability notification.
 250 *
 251 * @evt:        Event information (packs the actual event data, which
 252 *              radio controller it came to, etc).
 253 *
 254 * @returns:    0 on success (so uwbd() frees the event buffer), < 0
 255 *              on error.
 256 *
 257 * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that
 258 * the MAS slot is available, bits set to ZERO indicate that the slot
 259 * is busy.
 260 *
 261 * So we clear available slots, we set used slots :)
 262 *
 263 * The notification only marks non-availability based on the BP and
 264 * received DRP IEs that are not for this radio controller.  A copy of
 265 * this bitmap is needed to generate the real availability (which
 266 * includes local and pending reservations).
 267 *
 268 * The DRP Availability IE that this radio controller emits will need
 269 * to be updated.
 270 */
 271int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt)
 272{
 273        int result;
 274        struct uwb_rc *rc = evt->rc;
 275        DECLARE_BITMAP(bmp, UWB_NUM_MAS);
 276
 277        result = uwbd_evt_get_drp_avail(evt, bmp);
 278        if (result < 0)
 279                return result;
 280
 281        mutex_lock(&rc->rsvs_mutex);
 282        bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS);
 283        rc->drp_avail.ie_valid = false;
 284        uwb_rsv_handle_drp_avail_change(rc);
 285        mutex_unlock(&rc->rsvs_mutex);
 286
 287        uwb_rsv_sched_update(rc);
 288
 289        return 0;
 290}
 291