/** * If the buddy block is on the free list then coalesce and insert into the next * list until we reach an allocated or split buddy block, or the max list size. */ static inline uint32_t __gnix_buddy_coalesce(gnix_buddy_alloc_handle_t *alloc_handle , void **ptr, uint32_t block_size) { void *buddy; for (buddy = __gnix_buddy_address(*ptr, block_size, alloc_handle->base); block_size < alloc_handle->max && !_gnix_test_bit(&alloc_handle->bitmap, __gnix_buddy_bitmap_index(buddy, block_size, alloc_handle->base, alloc_handle->len, MIN_BLOCK_SIZE)); buddy = __gnix_buddy_address(*ptr, block_size, alloc_handle->base)) { dlist_remove(buddy); /* Ensure ptr is the beginning of the new block */ if (*ptr > buddy) *ptr = buddy; block_size *= 2; _gnix_clear_bit(&alloc_handle->bitmap, __gnix_buddy_bitmap_index(*ptr, block_size, alloc_handle->base, alloc_handle->len, MIN_BLOCK_SIZE)); } return block_size; }
static struct gnix_vc *__gnix_nic_next_pending_rx_vc(struct gnix_nic *nic) { struct gnix_vc *vc = NULL; fastlock_acquire(&nic->rx_vc_lock); vc = dlist_first_entry(&nic->rx_vcs, struct gnix_vc, rx_list); if (vc) dlist_remove_init(&vc->rx_list); fastlock_release(&nic->rx_vc_lock); if (vc) { GNIX_INFO(FI_LOG_EP_CTRL, "Dequeued RX VC (%p)\n", vc); _gnix_clear_bit(&vc->flags, GNIX_VC_FLAG_RX_SCHEDULED); } return vc; }
int _gnix_buddy_free(gnix_buddy_alloc_handle_t *alloc_handle, void *ptr, uint32_t len) { uint32_t block_size; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); if (unlikely(!alloc_handle || !len || len > alloc_handle->max || ptr >= (void *) ((uint8_t *) alloc_handle->base + alloc_handle->len) || ptr < alloc_handle->base)) { GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to _gnix_buddy_free.\n"); return -FI_EINVAL; } block_size = BLOCK_SIZE(len, MIN_BLOCK_SIZE); _gnix_clear_bit(&alloc_handle->bitmap, __gnix_buddy_bitmap_index(ptr, block_size, alloc_handle->base, alloc_handle->len, MIN_BLOCK_SIZE)); fastlock_acquire(&alloc_handle->lock); block_size = __gnix_buddy_coalesce(alloc_handle, &ptr, block_size); dlist_insert_tail(ptr, alloc_handle->lists + LIST_INDEX(block_size, MIN_BLOCK_SIZE)); fastlock_release(&alloc_handle->lock); return FI_SUCCESS; }