aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/mthca/mthca_memfree.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@mellanox.co.il>2007-02-10 16:15:08 -0500
committerRoland Dreier <rolandd@cisco.com>2007-02-12 19:16:29 -0500
commit391e4dea7189eef32b0c2d121e7e047110c1b83c (patch)
tree99cfb7f912837fb6f37ae290c9f1345d218eab06 /drivers/infiniband/hw/mthca/mthca_memfree.c
parent1d1f19cfce7687b557cebdc41bf8a5eeba8a9882 (diff)
IB/mthca: Fix access to MTT and MPT tables on non-cache-coherent CPUs
We allocate the MTT table with alloc_pages() and then do pci_map_sg(), so we must call pci_dma_sync_sg() after the CPU writes to the MTT table. This works since the device will never write MTTs on mem-free HCAs, once we get rid of the use of the WRITE_MTT firmware command. This change is needed to make that work, and is an improvement for now, since it gives FMRs a chance at working. For MPTs, both the device and CPU might write there, so we must allocate DMA coherent memory for these. Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_memfree.c')
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c127
1 files changed, 98 insertions, 29 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 6b19645d946..0b9d053a599 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -35,6 +35,9 @@
35 */ 35 */
36 36
37#include <linux/mm.h> 37#include <linux/mm.h>
38#include <linux/scatterlist.h>
39
40#include <asm/page.h>
38 41
39#include "mthca_memfree.h" 42#include "mthca_memfree.h"
40#include "mthca_dev.h" 43#include "mthca_dev.h"
@@ -58,22 +61,42 @@ struct mthca_user_db_table {
58 } page[0]; 61 } page[0];
59}; 62};
60 63
61void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) 64static void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *chunk)
65{
66 int i;
67
68 if (chunk->nsg > 0)
69 pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
70 PCI_DMA_BIDIRECTIONAL);
71
72 for (i = 0; i < chunk->npages; ++i)
73 __free_pages(chunk->mem[i].page,
74 get_order(chunk->mem[i].length));
75}
76
77static void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chunk *chunk)
62{ 78{
63 struct mthca_icm_chunk *chunk, *tmp;
64 int i; 79 int i;
65 80
81 for (i = 0; i < chunk->npages; ++i) {
82 dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
83 lowmem_page_address(chunk->mem[i].page),
84 sg_dma_address(&chunk->mem[i]));
85 }
86}
87
88void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent)
89{
90 struct mthca_icm_chunk *chunk, *tmp;
91
66 if (!icm) 92 if (!icm)
67 return; 93 return;
68 94
69 list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { 95 list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
70 if (chunk->nsg > 0) 96 if (coherent)
71 pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, 97 mthca_free_icm_coherent(dev, chunk);
72 PCI_DMA_BIDIRECTIONAL); 98 else
73 99 mthca_free_icm_pages(dev, chunk);
74 for (i = 0; i < chunk->npages; ++i)
75 __free_pages(chunk->mem[i].page,
76 get_order(chunk->mem[i].length));
77 100
78 kfree(chunk); 101 kfree(chunk);
79 } 102 }
@@ -81,12 +104,41 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
81 kfree(icm); 104 kfree(icm);
82} 105}
83 106
107static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
108{
109 mem->page = alloc_pages(gfp_mask, order);
110 if (!mem->page)
111 return -ENOMEM;
112
113 mem->length = PAGE_SIZE << order;
114 mem->offset = 0;
115 return 0;
116}
117
118static int mthca_alloc_icm_coherent(struct device *dev, struct scatterlist *mem,
119 int order, gfp_t gfp_mask)
120{
121 void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, &sg_dma_address(mem),
122 gfp_mask);
123 if (!buf)
124 return -ENOMEM;
125
126 sg_set_buf(mem, buf, PAGE_SIZE << order);
127 BUG_ON(mem->offset);
128 sg_dma_len(mem) = PAGE_SIZE << order;
129 return 0;
130}
131
84struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, 132struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
85 gfp_t gfp_mask) 133 gfp_t gfp_mask, int coherent)
86{ 134{
87 struct mthca_icm *icm; 135 struct mthca_icm *icm;
88 struct mthca_icm_chunk *chunk = NULL; 136 struct mthca_icm_chunk *chunk = NULL;
89 int cur_order; 137 int cur_order;
138 int ret;
139
140 /* We use sg_set_buf for coherent allocs, which assumes low memory */
141 BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
90 142
91 icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); 143 icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
92 if (!icm) 144 if (!icm)
@@ -112,21 +164,28 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
112 while (1 << cur_order > npages) 164 while (1 << cur_order > npages)
113 --cur_order; 165 --cur_order;
114 166
115 chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order); 167 if (coherent)
116 if (chunk->mem[chunk->npages].page) { 168 ret = mthca_alloc_icm_coherent(&dev->pdev->dev,
117 chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order; 169 &chunk->mem[chunk->npages],
118 chunk->mem[chunk->npages].offset = 0; 170 cur_order, gfp_mask);
171 else
172 ret = mthca_alloc_icm_pages(&chunk->mem[chunk->npages],
173 cur_order, gfp_mask);
119 174
120 if (++chunk->npages == MTHCA_ICM_CHUNK_LEN) { 175 if (!ret) {
176 ++chunk->npages;
177
178 if (!coherent && chunk->npages == MTHCA_ICM_CHUNK_LEN) {
121 chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, 179 chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
122 chunk->npages, 180 chunk->npages,
123 PCI_DMA_BIDIRECTIONAL); 181 PCI_DMA_BIDIRECTIONAL);
124 182
125 if (chunk->nsg <= 0) 183 if (chunk->nsg <= 0)
126 goto fail; 184 goto fail;
185 }
127 186
187 if (chunk->npages == MTHCA_ICM_CHUNK_LEN)
128 chunk = NULL; 188 chunk = NULL;
129 }
130 189
131 npages -= 1 << cur_order; 190 npages -= 1 << cur_order;
132 } else { 191 } else {
@@ -136,7 +195,7 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
136 } 195 }
137 } 196 }
138 197
139 if (chunk) { 198 if (!coherent && chunk) {
140 chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, 199 chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
141 chunk->npages, 200 chunk->npages,
142 PCI_DMA_BIDIRECTIONAL); 201 PCI_DMA_BIDIRECTIONAL);
@@ -148,7 +207,7 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
148 return icm; 207 return icm;
149 208
150fail: 209fail:
151 mthca_free_icm(dev, icm); 210 mthca_free_icm(dev, icm, coherent);
152 return NULL; 211 return NULL;
153} 212}
154 213
@@ -167,7 +226,7 @@ int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int ob
167 226
168 table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT, 227 table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
169 (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | 228 (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
170 __GFP_NOWARN); 229 __GFP_NOWARN, table->coherent);
171 if (!table->icm[i]) { 230 if (!table->icm[i]) {
172 ret = -ENOMEM; 231 ret = -ENOMEM;
173 goto out; 232 goto out;
@@ -175,7 +234,7 @@ int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int ob
175 234
176 if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE, 235 if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
177 &status) || status) { 236 &status) || status) {
178 mthca_free_icm(dev, table->icm[i]); 237 mthca_free_icm(dev, table->icm[i], table->coherent);
179 table->icm[i] = NULL; 238 table->icm[i] = NULL;
180 ret = -ENOMEM; 239 ret = -ENOMEM;
181 goto out; 240 goto out;
@@ -204,16 +263,16 @@ void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int o
204 mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, 263 mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
205 MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, 264 MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
206 &status); 265 &status);
207 mthca_free_icm(dev, table->icm[i]); 266 mthca_free_icm(dev, table->icm[i], table->coherent);
208 table->icm[i] = NULL; 267 table->icm[i] = NULL;
209 } 268 }
210 269
211 mutex_unlock(&table->mutex); 270 mutex_unlock(&table->mutex);
212} 271}
213 272
214void *mthca_table_find(struct mthca_icm_table *table, int obj) 273void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle)
215{ 274{
216 int idx, offset, i; 275 int idx, offset, dma_offset, i;
217 struct mthca_icm_chunk *chunk; 276 struct mthca_icm_chunk *chunk;
218 struct mthca_icm *icm; 277 struct mthca_icm *icm;
219 struct page *page = NULL; 278 struct page *page = NULL;
@@ -225,13 +284,22 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj)
225 284
226 idx = (obj & (table->num_obj - 1)) * table->obj_size; 285 idx = (obj & (table->num_obj - 1)) * table->obj_size;
227 icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE]; 286 icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE];
228 offset = idx % MTHCA_TABLE_CHUNK_SIZE; 287 dma_offset = offset = idx % MTHCA_TABLE_CHUNK_SIZE;
229 288
230 if (!icm) 289 if (!icm)
231 goto out; 290 goto out;
232 291
233 list_for_each_entry(chunk, &icm->chunk_list, list) { 292 list_for_each_entry(chunk, &icm->chunk_list, list) {
234 for (i = 0; i < chunk->npages; ++i) { 293 for (i = 0; i < chunk->npages; ++i) {
294 if (dma_handle && dma_offset >= 0) {
295 if (sg_dma_len(&chunk->mem[i]) > dma_offset)
296 *dma_handle = sg_dma_address(&chunk->mem[i]) +
297 dma_offset;
298 dma_offset -= sg_dma_len(&chunk->mem[i]);
299 }
300 /* DMA mapping can merge pages but not split them,
301 * so if we found the page, dma_handle has already
302 * been assigned to. */
235 if (chunk->mem[i].length > offset) { 303 if (chunk->mem[i].length > offset) {
236 page = chunk->mem[i].page; 304 page = chunk->mem[i].page;
237 goto out; 305 goto out;
@@ -283,7 +351,7 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
283struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, 351struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
284 u64 virt, int obj_size, 352 u64 virt, int obj_size,
285 int nobj, int reserved, 353 int nobj, int reserved,
286 int use_lowmem) 354 int use_lowmem, int use_coherent)
287{ 355{
288 struct mthca_icm_table *table; 356 struct mthca_icm_table *table;
289 int num_icm; 357 int num_icm;
@@ -302,6 +370,7 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
302 table->num_obj = nobj; 370 table->num_obj = nobj;
303 table->obj_size = obj_size; 371 table->obj_size = obj_size;
304 table->lowmem = use_lowmem; 372 table->lowmem = use_lowmem;
373 table->coherent = use_coherent;
305 mutex_init(&table->mutex); 374 mutex_init(&table->mutex);
306 375
307 for (i = 0; i < num_icm; ++i) 376 for (i = 0; i < num_icm; ++i)
@@ -314,12 +383,12 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
314 383
315 table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT, 384 table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
316 (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | 385 (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
317 __GFP_NOWARN); 386 __GFP_NOWARN, use_coherent);
318 if (!table->icm[i]) 387 if (!table->icm[i])
319 goto err; 388 goto err;
320 if (mthca_MAP_ICM(dev, table->icm[i], virt + i * MTHCA_TABLE_CHUNK_SIZE, 389 if (mthca_MAP_ICM(dev, table->icm[i], virt + i * MTHCA_TABLE_CHUNK_SIZE,
321 &status) || status) { 390 &status) || status) {
322 mthca_free_icm(dev, table->icm[i]); 391 mthca_free_icm(dev, table->icm[i], table->coherent);
323 table->icm[i] = NULL; 392 table->icm[i] = NULL;
324 goto err; 393 goto err;
325 } 394 }
@@ -339,7 +408,7 @@ err:
339 mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE, 408 mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE,
340 MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, 409 MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
341 &status); 410 &status);
342 mthca_free_icm(dev, table->icm[i]); 411 mthca_free_icm(dev, table->icm[i], table->coherent);
343 } 412 }
344 413
345 kfree(table); 414 kfree(table);
@@ -357,7 +426,7 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
357 mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, 426 mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
358 MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, 427 MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
359 &status); 428 &status);
360 mthca_free_icm(dev, table->icm[i]); 429 mthca_free_icm(dev, table->icm[i], table->coherent);
361 } 430 }
362 431
363 kfree(table); 432 kfree(table);