/* Must be called only after all slaves have been released */ static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); _lock_tx_hashtbl(bond); if (bond_info->tx_hashtbl == NULL) { _unlock_tx_hashtbl(bond); return; } kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; _unlock_tx_hashtbl(bond); }
/* Caller must hold bond lock for read */ struct slave* tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct tlb_client_info *hash_table = NULL; struct slave *assigned_slave = NULL; _lock_tx_hashtbl(bond); hash_table = bond_info->tx_hashtbl; if (hash_table == NULL) { printk (KERN_ERR "%s: TLB hash table is NULL\n", bond->device->name); _unlock_tx_hashtbl(bond); return NULL; } assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { assigned_slave = tlb_get_least_loaded_slave(bond); if (assigned_slave) { struct tlb_slave_info *slave_info = &(SLAVE_TLB_INFO(assigned_slave)); u32 next_index = slave_info->head; hash_table[hash_index].tx_slave = assigned_slave; hash_table[hash_index].next = next_index; hash_table[hash_index].prev = TLB_NULL_INDEX; if (next_index != TLB_NULL_INDEX) { hash_table[next_index].prev = hash_index; } slave_info->head = hash_index; slave_info->load += hash_table[hash_index].load_history; } } if (assigned_slave) { hash_table[hash_index].tx_bytes += skb_len; } _unlock_tx_hashtbl(bond); return assigned_slave; }
/* Must be called before starting the monitor timer */ static int tlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); struct tlb_client_info *new_hashtbl; int i; spin_lock_init(&(bond_info->tx_hashtbl_lock)); new_hashtbl = kzalloc(size, GFP_KERNEL); if (!new_hashtbl) { pr_err("%s: Error: Failed to allocate TLB hash table\n", bond->dev->name); return -1; } _lock_tx_hashtbl(bond); bond_info->tx_hashtbl = new_hashtbl; for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); } _unlock_tx_hashtbl(bond); return 0; }
/* Must be called before starting the monitor timer */ static int tlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); int i; size_t size; #if(TLB_HASH_TABLE_SIZE != 256) /* Key to the hash table is byte wide. Check the size! */ #error Hash Table size is wrong. #endif spin_lock_init(&(bond_info->tx_hashtbl_lock)); _lock_tx_hashtbl(bond); if (bond_info->tx_hashtbl != NULL) { printk (KERN_ERR "%s: TLB hash table is not NULL\n", bond->device->name); _unlock_tx_hashtbl(bond); return -1; } size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL); if (bond_info->tx_hashtbl == NULL) { printk (KERN_ERR "%s: Failed to allocate TLB hash table\n", bond->device->name); _unlock_tx_hashtbl(bond); return -1; } memset(bond_info->tx_hashtbl, 0, size); for (i=0; i<TLB_HASH_TABLE_SIZE; i++) { tlb_init_table_entry(bond, i, 1); } _unlock_tx_hashtbl(bond); return 0; }
/* Caller must hold bond lock for read */ static inline void tlb_clear_slave(struct bonding *bond, struct slave *slave, u8 save_load) { struct tlb_client_info *tx_hash_table = NULL; u32 index, next_index; /* clear slave from tx_hashtbl */ _lock_tx_hashtbl(bond); tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; if (tx_hash_table) { index = SLAVE_TLB_INFO(slave).head; while (index != TLB_NULL_INDEX) { next_index = tx_hash_table[index].next; tlb_init_table_entry(bond, index, save_load); index = next_index; } } _unlock_tx_hashtbl(bond); tlb_init_slave(slave); }
/* Caller must hold bond lock for read */ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) { struct tlb_client_info *tx_hash_table; u32 index; _lock_tx_hashtbl(bond); /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; /* skip this if we've already freed the tx hash table */ if (tx_hash_table) { index = SLAVE_TLB_INFO(slave).head; while (index != TLB_NULL_INDEX) { u32 next_index = tx_hash_table[index].next; tlb_init_table_entry(&tx_hash_table[index], save_load); index = next_index; } } tlb_init_slave(slave); _unlock_tx_hashtbl(bond); }