Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
[pandora-kernel.git] / drivers / infiniband / hw / ipath / ipath_wc_x86_64.c
index 04696e6..3428acb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -63,12 +63,29 @@ int ipath_enable_wc(struct ipath_devdata *dd)
         * of 2 address matching the length (which has to be a power of 2).
         * For rev1, that means the base address, for rev2, it will be just
         * the PIO buffers themselves.
+        * For chips with two sets of buffers, the calculations are
+        * somewhat more complicated; we need to sum, and the piobufbase
+        * register has both offsets, 2K in low 32 bits, 4K in high 32 bits.
+        * The buffers are still packed, so a single range covers both.
         */
-       pioaddr = addr + dd->ipath_piobufbase;
-       piolen = (dd->ipath_piobcnt2k +
-                 dd->ipath_piobcnt4k) *
-               ALIGN(dd->ipath_piobcnt2k +
-                     dd->ipath_piobcnt4k, dd->ipath_palign);
+       if (dd->ipath_piobcnt2k && dd->ipath_piobcnt4k) { /* 2 sizes */
+               unsigned long pio2kbase, pio4kbase;
+               pio2kbase = dd->ipath_piobufbase & 0xffffffffUL;
+               pio4kbase = (dd->ipath_piobufbase >> 32) & 0xffffffffUL;
+               if (pio2kbase < pio4kbase) { /* all, for now */
+                       pioaddr = addr + pio2kbase;
+                       piolen = pio4kbase - pio2kbase +
+                               dd->ipath_piobcnt4k * dd->ipath_4kalign;
+               } else {
+                       pioaddr = addr + pio4kbase;
+                       piolen = pio2kbase - pio4kbase +
+                               dd->ipath_piobcnt2k * dd->ipath_palign;
+               }
+       } else {  /* single buffer size (2K, currently) */
+               pioaddr = addr + dd->ipath_piobufbase;
+               piolen = dd->ipath_piobcnt2k * dd->ipath_palign +
+                       dd->ipath_piobcnt4k * dd->ipath_4kalign;
+       }
 
        for (bits = 0; !(piolen & (1ULL << bits)); bits++)
                /* do nothing */ ;