diff options
author | Bryan O'Sullivan <bos@pathscale.com> | 2007-03-15 17:45:12 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-04-18 23:20:59 -0400 |
commit | 662af5813be9aadf95ca310b7b6d1d37070c9922 (patch) | |
tree | 1ed1454f49c7699e39e840ccfad03af31ba8dee8 | |
parent | 53c1d2c943a67fb129ed2797182305a4633531fb (diff) |
IB/ipath: Don't allow QPs 0 and 1 to be opened multiple times
Signed-off-by: Robert Walsh <robert.walsh@qlogic.com>
Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_qp.c | 91 |
1 files changed, 53 insertions, 38 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index f671fd073253..16db9ac0b402 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c | |||
@@ -81,11 +81,51 @@ static u32 credit_table[31] = { | |||
81 | 32768 /* 1E */ | 81 | 32768 /* 1E */ |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static u32 alloc_qpn(struct ipath_qp_table *qpt) | 84 | |
85 | static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map) | ||
86 | { | ||
87 | unsigned long page = get_zeroed_page(GFP_KERNEL); | ||
88 | unsigned long flags; | ||
89 | |||
90 | /* | ||
91 | * Free the page if someone raced with us installing it. | ||
92 | */ | ||
93 | |||
94 | spin_lock_irqsave(&qpt->lock, flags); | ||
95 | if (map->page) | ||
96 | free_page(page); | ||
97 | else | ||
98 | map->page = (void *)page; | ||
99 | spin_unlock_irqrestore(&qpt->lock, flags); | ||
100 | } | ||
101 | |||
102 | |||
103 | static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type) | ||
85 | { | 104 | { |
86 | u32 i, offset, max_scan, qpn; | 105 | u32 i, offset, max_scan, qpn; |
87 | struct qpn_map *map; | 106 | struct qpn_map *map; |
88 | u32 ret; | 107 | u32 ret = -1; |
108 | |||
109 | if (type == IB_QPT_SMI) | ||
110 | ret = 0; | ||
111 | else if (type == IB_QPT_GSI) | ||
112 | ret = 1; | ||
113 | |||
114 | if (ret != -1) { | ||
115 | map = &qpt->map[0]; | ||
116 | if (unlikely(!map->page)) { | ||
117 | get_map_page(qpt, map); | ||
118 | if (unlikely(!map->page)) { | ||
119 | ret = -ENOMEM; | ||
120 | goto bail; | ||
121 | } | ||
122 | } | ||
123 | if (!test_and_set_bit(ret, map->page)) | ||
124 | atomic_dec(&map->n_free); | ||
125 | else | ||
126 | ret = -EBUSY; | ||
127 | goto bail; | ||
128 | } | ||
89 | 129 | ||
90 | qpn = qpt->last + 1; | 130 | qpn = qpt->last + 1; |
91 | if (qpn >= QPN_MAX) | 131 | if (qpn >= QPN_MAX) |
@@ -95,19 +135,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt) | |||
95 | max_scan = qpt->nmaps - !offset; | 135 | max_scan = qpt->nmaps - !offset; |
96 | for (i = 0;;) { | 136 | for (i = 0;;) { |
97 | if (unlikely(!map->page)) { | 137 | if (unlikely(!map->page)) { |
98 | unsigned long page = get_zeroed_page(GFP_KERNEL); | 138 | get_map_page(qpt, map); |
99 | unsigned long flags; | ||
100 | |||
101 | /* | ||
102 | * Free the page if someone raced with us | ||
103 | * installing it: | ||
104 | */ | ||
105 | spin_lock_irqsave(&qpt->lock, flags); | ||
106 | if (map->page) | ||
107 | free_page(page); | ||
108 | else | ||
109 | map->page = (void *)page; | ||
110 | spin_unlock_irqrestore(&qpt->lock, flags); | ||
111 | if (unlikely(!map->page)) | 139 | if (unlikely(!map->page)) |
112 | break; | 140 | break; |
113 | } | 141 | } |
@@ -151,7 +179,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt) | |||
151 | qpn = mk_qpn(qpt, map, offset); | 179 | qpn = mk_qpn(qpt, map, offset); |
152 | } | 180 | } |
153 | 181 | ||
154 | ret = 0; | 182 | ret = -ENOMEM; |
155 | 183 | ||
156 | bail: | 184 | bail: |
157 | return ret; | 185 | return ret; |
@@ -180,29 +208,19 @@ static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp, | |||
180 | enum ib_qp_type type) | 208 | enum ib_qp_type type) |
181 | { | 209 | { |
182 | unsigned long flags; | 210 | unsigned long flags; |
183 | u32 qpn; | ||
184 | int ret; | 211 | int ret; |
185 | 212 | ||
186 | if (type == IB_QPT_SMI) | 213 | ret = alloc_qpn(qpt, type); |
187 | qpn = 0; | 214 | if (ret < 0) |
188 | else if (type == IB_QPT_GSI) | 215 | goto bail; |
189 | qpn = 1; | 216 | qp->ibqp.qp_num = ret; |
190 | else { | ||
191 | /* Allocate the next available QPN */ | ||
192 | qpn = alloc_qpn(qpt); | ||
193 | if (qpn == 0) { | ||
194 | ret = -ENOMEM; | ||
195 | goto bail; | ||
196 | } | ||
197 | } | ||
198 | qp->ibqp.qp_num = qpn; | ||
199 | 217 | ||
200 | /* Add the QP to the hash table. */ | 218 | /* Add the QP to the hash table. */ |
201 | spin_lock_irqsave(&qpt->lock, flags); | 219 | spin_lock_irqsave(&qpt->lock, flags); |
202 | 220 | ||
203 | qpn %= qpt->max; | 221 | ret %= qpt->max; |
204 | qp->next = qpt->table[qpn]; | 222 | qp->next = qpt->table[ret]; |
205 | qpt->table[qpn] = qp; | 223 | qpt->table[ret] = qp; |
206 | atomic_inc(&qp->refcount); | 224 | atomic_inc(&qp->refcount); |
207 | 225 | ||
208 | spin_unlock_irqrestore(&qpt->lock, flags); | 226 | spin_unlock_irqrestore(&qpt->lock, flags); |
@@ -245,9 +263,7 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp) | |||
245 | if (!fnd) | 263 | if (!fnd) |
246 | return; | 264 | return; |
247 | 265 | ||
248 | /* If QPN is not reserved, mark QPN free in the bitmap. */ | 266 | free_qpn(qpt, qp->ibqp.qp_num); |
249 | if (qp->ibqp.qp_num > 1) | ||
250 | free_qpn(qpt, qp->ibqp.qp_num); | ||
251 | 267 | ||
252 | wait_event(qp->wait, !atomic_read(&qp->refcount)); | 268 | wait_event(qp->wait, !atomic_read(&qp->refcount)); |
253 | } | 269 | } |
@@ -270,8 +286,7 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt) | |||
270 | 286 | ||
271 | while (qp) { | 287 | while (qp) { |
272 | nqp = qp->next; | 288 | nqp = qp->next; |
273 | if (qp->ibqp.qp_num > 1) | 289 | free_qpn(qpt, qp->ibqp.qp_num); |
274 | free_qpn(qpt, qp->ibqp.qp_num); | ||
275 | if (!atomic_dec_and_test(&qp->refcount) || | 290 | if (!atomic_dec_and_test(&qp->refcount) || |
276 | !ipath_destroy_qp(&qp->ibqp)) | 291 | !ipath_destroy_qp(&qp->ibqp)) |
277 | ipath_dbg("QP memory leak!\n"); | 292 | ipath_dbg("QP memory leak!\n"); |