[ofa-general] [PATCH 2/3] RDMA/cxgb3: fix page shift calculation in build_phys_page_list()
Roland Dreier
rdreier at cisco.com
Sun Jan 27 13:33:33 PST 2008
>Roland, you're quite right that the non-obvious page list is not
>necessarily a problem. It causes a failure only if the virtual address
>that is eventually mapped to this region has an alignment with respect to
>large-page boundaries that is different from the alignment of the physical
>address. To be concrete, the page list works as you expect if and only if
>
> ((*iova_start) & ((1ULL << shift) - 1)) ==
> (buffer_list[0].addr & ((1ULL << shift) - 1)).
got it... I was tricking myself that the check for alignment at the
start of the function was sufficient, but it's not once we start using
a bigger value of shift.
I think the patch below should be a fix for the problem, although I've
only compile tested it. The idea is to stop increasing shift once it
reaches a bit position where the first buffer and the iova differ.
What do you think? If this works for you, I will merge it for 2.6.25.
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 6bcde1c..1a15129 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -948,7 +948,9 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
return ERR_PTR(-EINVAL);
/* Find largest page shift we can use to cover buffers */
- for (shift = PAGE_SHIFT; shift < 31; ++shift)
+ for (shift = PAGE_SHIFT; shift < 31; ++shift) {
+ if ((buffer_list[0].addr ^ *iova_start) & (1ULL << shift))
+ break;
if (num_phys_buf > 1) {
if ((1ULL << shift) & mask)
break;
@@ -958,6 +960,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
(buffer_list[0].addr & ((1ULL << shift) - 1)))
break;
}
+ }
buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1);
buffer_list[0].addr &= ~0ull << shift;
More information about the general
mailing list