2008-09-17 19:34:09 +04:00
/*
* Ultra Wide Band
* DRP availability management
*
* Copyright ( C ) 2005 - 2006 Intel Corporation
* Reinette Chatre < reinette . chatre @ intel . com >
* Copyright ( C ) 2008 Cambridge Silicon Radio Ltd .
*
* 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 . If not , see < http : //www.gnu.org/licenses/>.
*
*
* Manage DRP Availability ( the MAS available for DRP
* reservations ) . Thus :
*
* - Handle DRP Availability Change notifications
*
* - Allow the reservation manager to indicate MAS reserved / released
* by local ( owned by / targeted at the radio controller )
* reservations .
*
* - Based on the two sources above , generate a DRP Availability IE to
* be included in the beacon .
*
* See also the documentation for struct uwb_drp_avail .
*/
# include <linux/errno.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/bitmap.h>
# include "uwb-internal.h"
/**
* uwb_drp_avail_init - initialize an RC ' s MAS availability
*
* All MAS are available initially . The RC will inform use which
* slots are used for the BP ( it may change in size ) .
*/
void uwb_drp_avail_init ( struct uwb_rc * rc )
{
bitmap_fill ( rc - > drp_avail . global , UWB_NUM_MAS ) ;
bitmap_fill ( rc - > drp_avail . local , UWB_NUM_MAS ) ;
bitmap_fill ( rc - > drp_avail . pending , UWB_NUM_MAS ) ;
}
/*
* Determine MAS available for new local reservations .
*
* avail = global & local & pending
*/
2008-12-12 16:00:06 +03:00
void uwb_drp_available ( struct uwb_rc * rc , struct uwb_mas_bm * avail )
2008-09-17 19:34:09 +04:00
{
bitmap_and ( avail - > bm , rc - > drp_avail . global , rc - > drp_avail . local , UWB_NUM_MAS ) ;
bitmap_and ( avail - > bm , avail - > bm , rc - > drp_avail . pending , UWB_NUM_MAS ) ;
}
/**
* uwb_drp_avail_reserve_pending - reserve MAS for a new reservation
* @ rc : the radio controller
* @ mas : the MAS to reserve
*
* Returns 0 on success , or - EBUSY if the MAS requested aren ' t available .
*/
int uwb_drp_avail_reserve_pending ( struct uwb_rc * rc , struct uwb_mas_bm * mas )
{
struct uwb_mas_bm avail ;
uwb_drp_available ( rc , & avail ) ;
if ( ! bitmap_subset ( mas - > bm , avail . bm , UWB_NUM_MAS ) )
return - EBUSY ;
bitmap_andnot ( rc - > drp_avail . pending , rc - > drp_avail . pending , mas - > bm , UWB_NUM_MAS ) ;
return 0 ;
}
/**
* uwb_drp_avail_reserve - reserve MAS for an established reservation
* @ rc : the radio controller
* @ mas : the MAS to reserve
*/
void uwb_drp_avail_reserve ( struct uwb_rc * rc , struct uwb_mas_bm * mas )
{
bitmap_or ( rc - > drp_avail . pending , rc - > drp_avail . pending , mas - > bm , UWB_NUM_MAS ) ;
bitmap_andnot ( rc - > drp_avail . local , rc - > drp_avail . local , mas - > bm , UWB_NUM_MAS ) ;
rc - > drp_avail . ie_valid = false ;
}
/**
* uwb_drp_avail_release - release MAS from a pending or established reservation
* @ rc : the radio controller
* @ mas : the MAS to release
*/
void uwb_drp_avail_release ( struct uwb_rc * rc , struct uwb_mas_bm * mas )
{
bitmap_or ( rc - > drp_avail . local , rc - > drp_avail . local , mas - > bm , UWB_NUM_MAS ) ;
bitmap_or ( rc - > drp_avail . pending , rc - > drp_avail . pending , mas - > bm , UWB_NUM_MAS ) ;
rc - > drp_avail . ie_valid = false ;
2008-12-12 16:00:06 +03:00
uwb_rsv_handle_drp_avail_change ( rc ) ;
2008-09-17 19:34:09 +04:00
}
/**
* uwb_drp_avail_ie_update - update the DRP Availability IE
* @ rc : the radio controller
*
* avail = global & local
*/
void uwb_drp_avail_ie_update ( struct uwb_rc * rc )
{
struct uwb_mas_bm avail ;
bitmap_and ( avail . bm , rc - > drp_avail . global , rc - > drp_avail . local , UWB_NUM_MAS ) ;
rc - > drp_avail . ie . hdr . element_id = UWB_IE_DRP_AVAILABILITY ;
rc - > drp_avail . ie . hdr . length = UWB_NUM_MAS / 8 ;
uwb_mas_bm_copy_le ( rc - > drp_avail . ie . bmp , & avail ) ;
rc - > drp_avail . ie_valid = true ;
}
/**
* Create an unsigned long from a buffer containing a byte stream .
*
* @ array : pointer to buffer
* @ itr : index of buffer from where we start
* @ len : the buffer ' s remaining size may not be exact multiple of
* sizeof ( unsigned long ) , @ len is the length of buffer that needs
* to be converted . This will be sizeof ( unsigned long ) or smaller
* ( BUG if not ) . If it is smaller then we will pad the remaining
* space of the result with zeroes .
*/
static
unsigned long get_val ( u8 * array , size_t itr , size_t len )
{
unsigned long val = 0 ;
size_t top = itr + len ;
BUG_ON ( len > sizeof ( val ) ) ;
while ( itr < top ) {
val < < = 8 ;
val | = array [ top - 1 ] ;
top - - ;
}
val < < = 8 * ( sizeof ( val ) - len ) ; /* padding */
return val ;
}
/**
* Initialize bitmap from data buffer .
*
* The bitmap to be converted could come from a IE , for example a
* DRP Availability IE .
* From ECMA - 368 1.0 [ 16.8 .7 ] : "
* octets : 1 1 N * ( 0 to 32 )
* Element ID Length ( = N ) DRP Availability Bitmap
*
* The DRP Availability Bitmap field is up to 256 bits long , one
* bit for each MAS in the superframe , where the least - significant
* bit of the field corresponds to the first MAS in the superframe
* and successive bits correspond to successive MASs . "
*
* The DRP Availability bitmap is in octets from 0 to 32 , so octet
* 32 contains bits for MAS 1 - 8 , etc . If the bitmap is smaller than 32
* octets , the bits in octets not included at the end of the bitmap are
* treated as zero . In this case ( when the bitmap is smaller than 32
* octets ) the MAS represented range from MAS 1 to MAS ( size of bitmap )
* with the last octet still containing bits for MAS 1 - 8 , etc .
*
* For example :
* F00F0102 03040506 070 8090 A 0 B0C0D0E 0F 010203
* ^ ^ ^ ^
* | | | |
* | | | |
* | | | \ LSB of byte is MAS 9
* | | \ MSB of byte is MAS 16
* | \ LSB of first byte is MAS 1
* \ MSB of byte is MAS 8
*
* An example of this encoding can be found in ECMA - 368 Annex - D [ Table D .11 ]
*
* The resulting bitmap will have the following mapping :
* bit position 0 = = MAS 1
* bit position 1 = = MAS 2
* . . .
* bit position ( UWB_NUM_MAS - 1 ) = = MAS UWB_NUM_MAS
*
* @ bmp_itr : pointer to bitmap ( can be declared with DECLARE_BITMAP )
* @ buffer : pointer to buffer containing bitmap data in big endian
* format ( MSB first )
* @ buffer_size : number of bytes with which bitmap should be initialized
*/
static
void buffer_to_bmp ( unsigned long * bmp_itr , void * _buffer ,
size_t buffer_size )
{
u8 * buffer = _buffer ;
size_t itr , len ;
unsigned long val ;
itr = 0 ;
while ( itr < buffer_size ) {
len = buffer_size - itr > = sizeof ( val ) ?
sizeof ( val ) : buffer_size - itr ;
val = get_val ( buffer , itr , len ) ;
bmp_itr [ itr / sizeof ( val ) ] = val ;
itr + = sizeof ( val ) ;
}
}
/**
* Extract DRP Availability bitmap from the notification .
*
* The notification that comes in contains a bitmap of ( UWB_NUM_MAS / 8 ) bytes
* We convert that to our internal representation .
*/
static
int uwbd_evt_get_drp_avail ( struct uwb_event * evt , unsigned long * bmp )
{
struct device * dev = & evt - > rc - > uwb_dev . dev ;
struct uwb_rc_evt_drp_avail * drp_evt ;
int result = - EINVAL ;
/* Is there enough data to decode the event? */
if ( evt - > notif . size < sizeof ( * drp_evt ) ) {
dev_err ( dev , " DRP Availability Change: Not enough "
" data to decode event [%zu bytes, %zu "
" needed] \n " , evt - > notif . size , sizeof ( * drp_evt ) ) ;
goto error ;
}
drp_evt = container_of ( evt - > notif . rceb , struct uwb_rc_evt_drp_avail , rceb ) ;
buffer_to_bmp ( bmp , drp_evt - > bmp , UWB_NUM_MAS / 8 ) ;
result = 0 ;
error :
return result ;
}
/**
* Process an incoming DRP Availability notification .
*
* @ evt : Event information ( packs the actual event data , which
* radio controller it came to , etc ) .
*
* @ returns : 0 on success ( so uwbd ( ) frees the event buffer ) , < 0
* on error .
*
* According to ECMA - 368 1.0 [ 16.8 .7 ] , bits set to ONE indicate that
* the MAS slot is available , bits set to ZERO indicate that the slot
* is busy .
*
* So we clear available slots , we set used slots : )
*
* The notification only marks non - availability based on the BP and
* received DRP IEs that are not for this radio controller . A copy of
* this bitmap is needed to generate the real availability ( which
* includes local and pending reservations ) .
*
* The DRP Availability IE that this radio controller emits will need
* to be updated .
*/
int uwbd_evt_handle_rc_drp_avail ( struct uwb_event * evt )
{
int result ;
struct uwb_rc * rc = evt - > rc ;
DECLARE_BITMAP ( bmp , UWB_NUM_MAS ) ;
result = uwbd_evt_get_drp_avail ( evt , bmp ) ;
if ( result < 0 )
return result ;
mutex_lock ( & rc - > rsvs_mutex ) ;
bitmap_copy ( rc - > drp_avail . global , bmp , UWB_NUM_MAS ) ;
rc - > drp_avail . ie_valid = false ;
2008-12-12 16:00:06 +03:00
uwb_rsv_handle_drp_avail_change ( rc ) ;
2008-09-17 19:34:09 +04:00
mutex_unlock ( & rc - > rsvs_mutex ) ;
uwb_rsv_sched_update ( rc ) ;
return 0 ;
}