aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_exch.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r--drivers/scsi/libfc/fc_exch.c89
1 files changed, 86 insertions, 3 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 40c34274bd81..9cbe8d66eb25 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -32,6 +32,9 @@
32#include <scsi/libfc.h> 32#include <scsi/libfc.h>
33#include <scsi/fc_encode.h> 33#include <scsi/fc_encode.h>
34 34
35u16 fc_cpu_mask; /* cpu mask for possible cpus */
36EXPORT_SYMBOL(fc_cpu_mask);
37static u16 fc_cpu_order; /* 2's power to represent total possible cpus */
35static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ 38static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
36 39
37/* 40/*
@@ -48,6 +51,20 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
48 */ 51 */
49 52
50/* 53/*
54 * Per cpu exchange pool
55 *
56 * This structure manages per cpu exchanges in array of exchange pointers.
57 * This array is allocated followed by struct fc_exch_pool memory for
58 * assigned range of exchanges to per cpu pool.
59 */
60struct fc_exch_pool {
61 u16 next_index; /* next possible free exchange index */
62 u16 total_exches; /* total allocated exchanges */
63 spinlock_t lock; /* exch pool lock */
64 struct list_head ex_list; /* allocated exchanges list */
65};
66
67/*
51 * Exchange manager. 68 * Exchange manager.
52 * 69 *
53 * This structure is the center for creating exchanges and sequences. 70 * This structure is the center for creating exchanges and sequences.
@@ -66,6 +83,8 @@ struct fc_exch_mgr {
66 u32 total_exches; /* total allocated exchanges */ 83 u32 total_exches; /* total allocated exchanges */
67 struct list_head ex_list; /* allocated exchanges list */ 84 struct list_head ex_list; /* allocated exchanges list */
68 mempool_t *ep_pool; /* reserve ep's */ 85 mempool_t *ep_pool; /* reserve ep's */
86 u16 pool_max_index; /* max exch array index in exch pool */
87 struct fc_exch_pool *pool; /* per cpu exch pool */
69 88
70 /* 89 /*
71 * currently exchange mgr stats are updated but not used. 90 * currently exchange mgr stats are updated but not used.
@@ -303,6 +322,19 @@ static int fc_exch_done_locked(struct fc_exch *ep)
303 return rc; 322 return rc;
304} 323}
305 324
325static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool,
326 u16 index)
327{
328 struct fc_exch **exches = (struct fc_exch **)(pool + 1);
329 return exches[index];
330}
331
332static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index,
333 struct fc_exch *ep)
334{
335 ((struct fc_exch **)(pool + 1))[index] = ep;
336}
337
306static void fc_exch_mgr_delete_ep(struct fc_exch *ep) 338static void fc_exch_mgr_delete_ep(struct fc_exch *ep)
307{ 339{
308 struct fc_exch_mgr *mp; 340 struct fc_exch_mgr *mp;
@@ -1751,6 +1783,7 @@ static void fc_exch_mgr_destroy(struct kref *kref)
1751 */ 1783 */
1752 WARN_ON(mp->total_exches != 0); 1784 WARN_ON(mp->total_exches != 0);
1753 mempool_destroy(mp->ep_pool); 1785 mempool_destroy(mp->ep_pool);
1786 free_percpu(mp->pool);
1754 kfree(mp); 1787 kfree(mp);
1755} 1788}
1756 1789
@@ -1770,8 +1803,13 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1770{ 1803{
1771 struct fc_exch_mgr *mp; 1804 struct fc_exch_mgr *mp;
1772 size_t len; 1805 size_t len;
1806 u16 pool_exch_range;
1807 size_t pool_size;
1808 unsigned int cpu;
1809 struct fc_exch_pool *pool;
1773 1810
1774 if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { 1811 if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN ||
1812 (min_xid & fc_cpu_mask) != 0) {
1775 FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", 1813 FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n",
1776 min_xid, max_xid); 1814 min_xid, max_xid);
1777 return NULL; 1815 return NULL;
@@ -1802,10 +1840,31 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1802 if (!mp->ep_pool) 1840 if (!mp->ep_pool)
1803 goto free_mp; 1841 goto free_mp;
1804 1842
1843 /*
1844 * Setup per cpu exch pool with entire exchange id range equally
1845 * divided across all cpus. The exch pointers array memory is
1846 * allocated for exch range per pool.
1847 */
1848 pool_exch_range = (mp->max_xid - mp->min_xid + 1) / (fc_cpu_mask + 1);
1849 mp->pool_max_index = pool_exch_range - 1;
1850
1851 /*
1852 * Allocate and initialize per cpu exch pool
1853 */
1854 pool_size = sizeof(*pool) + pool_exch_range * sizeof(struct fc_exch *);
1855 mp->pool = __alloc_percpu(pool_size, __alignof__(struct fc_exch_pool));
1856 if (!mp->pool)
1857 goto free_mempool;
1858 for_each_possible_cpu(cpu) {
1859 pool = per_cpu_ptr(mp->pool, cpu);
1860 spin_lock_init(&pool->lock);
1861 INIT_LIST_HEAD(&pool->ex_list);
1862 }
1863
1805 kref_init(&mp->kref); 1864 kref_init(&mp->kref);
1806 if (!fc_exch_mgr_add(lp, mp, match)) { 1865 if (!fc_exch_mgr_add(lp, mp, match)) {
1807 mempool_destroy(mp->ep_pool); 1866 free_percpu(mp->pool);
1808 goto free_mp; 1867 goto free_mempool;
1809 } 1868 }
1810 1869
1811 /* 1870 /*
@@ -1816,6 +1875,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1816 kref_put(&mp->kref, fc_exch_mgr_destroy); 1875 kref_put(&mp->kref, fc_exch_mgr_destroy);
1817 return mp; 1876 return mp;
1818 1877
1878free_mempool:
1879 mempool_destroy(mp->ep_pool);
1819free_mp: 1880free_mp:
1820 kfree(mp); 1881 kfree(mp);
1821 return NULL; 1882 return NULL;
@@ -1975,6 +2036,28 @@ int fc_exch_init(struct fc_lport *lp)
1975 if (!lp->tt.seq_exch_abort) 2036 if (!lp->tt.seq_exch_abort)
1976 lp->tt.seq_exch_abort = fc_seq_exch_abort; 2037 lp->tt.seq_exch_abort = fc_seq_exch_abort;
1977 2038
2039 /*
2040 * Initialize fc_cpu_mask and fc_cpu_order. The
2041 * fc_cpu_mask is set for nr_cpu_ids rounded up
2042 * to order of 2's * power and order is stored
2043 * in fc_cpu_order as this is later required in
2044 * mapping between an exch id and exch array index
2045 * in per cpu exch pool.
2046 *
2047 * This round up is required to align fc_cpu_mask
2048 * to exchange id's lower bits such that all incoming
2049 * frames of an exchange gets delivered to the same
2050 * cpu on which exchange originated by simple bitwise
2051 * AND operation between fc_cpu_mask and exchange id.
2052 */
2053 fc_cpu_mask = 1;
2054 fc_cpu_order = 0;
2055 while (fc_cpu_mask < nr_cpu_ids) {
2056 fc_cpu_mask <<= 1;
2057 fc_cpu_order++;
2058 }
2059 fc_cpu_mask--;
2060
1978 return 0; 2061 return 0;
1979} 2062}
1980EXPORT_SYMBOL(fc_exch_init); 2063EXPORT_SYMBOL(fc_exch_init);