diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 89 |
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 | ||
35 | u16 fc_cpu_mask; /* cpu mask for possible cpus */ | ||
36 | EXPORT_SYMBOL(fc_cpu_mask); | ||
37 | static u16 fc_cpu_order; /* 2's power to represent total possible cpus */ | ||
35 | static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ | 38 | static 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 | */ | ||
60 | struct 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 | ||
325 | static 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 | |||
332 | static 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 | |||
306 | static void fc_exch_mgr_delete_ep(struct fc_exch *ep) | 338 | static 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 | ||
1878 | free_mempool: | ||
1879 | mempool_destroy(mp->ep_pool); | ||
1819 | free_mp: | 1880 | free_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 | } |
1980 | EXPORT_SYMBOL(fc_exch_init); | 2063 | EXPORT_SYMBOL(fc_exch_init); |