diff options
Diffstat (limited to 'drivers/infiniband/core/cache.c')
| -rw-r--r-- | drivers/infiniband/core/cache.c | 50 | 
1 files changed, 46 insertions, 4 deletions
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 68883565b72..80f6cf2449f 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -167,6 +167,7 @@ int ib_find_cached_pkey(struct ib_device *device,  	unsigned long flags;  	int i;  	int ret = -ENOENT; +	int partial_ix = -1;  	if (port_num < start_port(device) || port_num > end_port(device))  		return -EINVAL; @@ -179,6 +180,46 @@ int ib_find_cached_pkey(struct ib_device *device,  	for (i = 0; i < cache->table_len; ++i)  		if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { +			if (cache->table[i] & 0x8000) { +				*index = i; +				ret = 0; +				break; +			} else +				partial_ix = i; +		} + +	if (ret && partial_ix >= 0) { +		*index = partial_ix; +		ret = 0; +	} + +	read_unlock_irqrestore(&device->cache.lock, flags); + +	return ret; +} +EXPORT_SYMBOL(ib_find_cached_pkey); + +int ib_find_exact_cached_pkey(struct ib_device *device, +			      u8                port_num, +			      u16               pkey, +			      u16              *index) +{ +	struct ib_pkey_cache *cache; +	unsigned long flags; +	int i; +	int ret = -ENOENT; + +	if (port_num < start_port(device) || port_num > end_port(device)) +		return -EINVAL; + +	read_lock_irqsave(&device->cache.lock, flags); + +	cache = device->cache.pkey_cache[port_num - start_port(device)]; + +	*index = -1; + +	for (i = 0; i < cache->table_len; ++i) +		if (cache->table[i] == pkey) {  			*index = i;  			ret = 0;  			break; @@ -188,7 +229,7 @@ int ib_find_cached_pkey(struct ib_device *device,  	return ret;  } -EXPORT_SYMBOL(ib_find_cached_pkey); +EXPORT_SYMBOL(ib_find_exact_cached_pkey);  int ib_get_cached_lmc(struct ib_device *device,  		      u8                port_num, @@ -302,13 +343,14 @@ static void ib_cache_event(struct ib_event_handler *handler,  	    event->event == IB_EVENT_LID_CHANGE  ||  	    event->event == IB_EVENT_PKEY_CHANGE ||  	    event->event == IB_EVENT_SM_CHANGE   || -	    event->event == IB_EVENT_CLIENT_REREGISTER) { +	    event->event == IB_EVENT_CLIENT_REREGISTER || +	    event->event == IB_EVENT_GID_CHANGE) {  		work = kmalloc(sizeof *work, GFP_ATOMIC);  		if (work) {  			INIT_WORK(&work->work, ib_cache_task);  			work->device   = event->device;  			work->port_num = event->element.port_num; -			schedule_work(&work->work); +			queue_work(ib_wq, &work->work);  		}  	}  } @@ -368,7 +410,7 @@ static void ib_cache_cleanup_one(struct ib_device *device)  	int p;  	ib_unregister_event_handler(&device->cache.event_handler); -	flush_scheduled_work(); +	flush_workqueue(ib_wq);  	for (p = 0; p <= end_port(device) - start_port(device); ++p) {  		kfree(device->cache.pkey_cache[p]);  | 
