1f931551bSRalph Campbell /* 2f931551bSRalph Campbell * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. 3f931551bSRalph Campbell * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. 4f931551bSRalph Campbell * 5f931551bSRalph Campbell * This software is available to you under a choice of one of two 6f931551bSRalph Campbell * licenses. You may choose to be licensed under the terms of the GNU 7f931551bSRalph Campbell * General Public License (GPL) Version 2, available from the file 8f931551bSRalph Campbell * COPYING in the main directory of this source tree, or the 9f931551bSRalph Campbell * OpenIB.org BSD license below: 10f931551bSRalph Campbell * 11f931551bSRalph Campbell * Redistribution and use in source and binary forms, with or 12f931551bSRalph Campbell * without modification, are permitted provided that the following 13f931551bSRalph Campbell * conditions are met: 14f931551bSRalph Campbell * 15f931551bSRalph Campbell * - Redistributions of source code must retain the above 16f931551bSRalph Campbell * copyright notice, this list of conditions and the following 17f931551bSRalph Campbell * disclaimer. 18f931551bSRalph Campbell * 19f931551bSRalph Campbell * - Redistributions in binary form must reproduce the above 20f931551bSRalph Campbell * copyright notice, this list of conditions and the following 21f931551bSRalph Campbell * disclaimer in the documentation and/or other materials 22f931551bSRalph Campbell * provided with the distribution. 23f931551bSRalph Campbell * 24f931551bSRalph Campbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25f931551bSRalph Campbell * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26f931551bSRalph Campbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27f931551bSRalph Campbell * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28f931551bSRalph Campbell * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29f931551bSRalph Campbell * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30f931551bSRalph Campbell * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31f931551bSRalph Campbell * SOFTWARE. 32f931551bSRalph Campbell */ 33f931551bSRalph Campbell 34f931551bSRalph Campbell /* 35f931551bSRalph Campbell * This file is conditionally built on x86_64 only. Otherwise weak symbol 36f931551bSRalph Campbell * versions of the functions exported from here are used. 37f931551bSRalph Campbell */ 38f931551bSRalph Campbell 39f931551bSRalph Campbell #include <linux/pci.h> 40f931551bSRalph Campbell #include <asm/mtrr.h> 41f931551bSRalph Campbell #include <asm/processor.h> 42f931551bSRalph Campbell 43f931551bSRalph Campbell #include "qib.h" 44f931551bSRalph Campbell 45f931551bSRalph Campbell /** 46f931551bSRalph Campbell * qib_enable_wc - enable write combining for MMIO writes to the device 47f931551bSRalph Campbell * @dd: qlogic_ib device 48f931551bSRalph Campbell * 49f931551bSRalph Campbell * This routine is x86_64-specific; it twiddles the CPU's MTRRs to enable 50f931551bSRalph Campbell * write combining. 51f931551bSRalph Campbell */ 52f931551bSRalph Campbell int qib_enable_wc(struct qib_devdata *dd) 53f931551bSRalph Campbell { 54f931551bSRalph Campbell int ret = 0; 55f931551bSRalph Campbell u64 pioaddr, piolen; 56f931551bSRalph Campbell unsigned bits; 57f931551bSRalph Campbell const unsigned long addr = pci_resource_start(dd->pcidev, 0); 58f931551bSRalph Campbell const size_t len = pci_resource_len(dd->pcidev, 0); 59f931551bSRalph Campbell 60f931551bSRalph Campbell /* 61f931551bSRalph Campbell * Set the PIO buffers to be WCCOMB, so we get HT bursts to the 62f931551bSRalph Campbell * chip. Linux (possibly the hardware) requires it to be on a power 63f931551bSRalph Campbell * of 2 address matching the length (which has to be a power of 2). 64f931551bSRalph Campbell * For rev1, that means the base address, for rev2, it will be just 65f931551bSRalph Campbell * the PIO buffers themselves. 66f931551bSRalph Campbell * For chips with two sets of buffers, the calculations are 67f931551bSRalph Campbell * somewhat more complicated; we need to sum, and the piobufbase 68f931551bSRalph Campbell * register has both offsets, 2K in low 32 bits, 4K in high 32 bits. 69f931551bSRalph Campbell * The buffers are still packed, so a single range covers both. 70f931551bSRalph Campbell */ 71f931551bSRalph Campbell if (dd->piobcnt2k && dd->piobcnt4k) { 72f931551bSRalph Campbell /* 2 sizes for chip */ 73f931551bSRalph Campbell unsigned long pio2kbase, pio4kbase; 74f931551bSRalph Campbell pio2kbase = dd->piobufbase & 0xffffffffUL; 75f931551bSRalph Campbell pio4kbase = (dd->piobufbase >> 32) & 0xffffffffUL; 76f931551bSRalph Campbell if (pio2kbase < pio4kbase) { 77f931551bSRalph Campbell /* all current chips */ 78f931551bSRalph Campbell pioaddr = addr + pio2kbase; 79f931551bSRalph Campbell piolen = pio4kbase - pio2kbase + 80f931551bSRalph Campbell dd->piobcnt4k * dd->align4k; 81f931551bSRalph Campbell } else { 82f931551bSRalph Campbell pioaddr = addr + pio4kbase; 83f931551bSRalph Campbell piolen = pio2kbase - pio4kbase + 84f931551bSRalph Campbell dd->piobcnt2k * dd->palign; 85f931551bSRalph Campbell } 86f931551bSRalph Campbell } else { /* single buffer size (2K, currently) */ 87f931551bSRalph Campbell pioaddr = addr + dd->piobufbase; 88f931551bSRalph Campbell piolen = dd->piobcnt2k * dd->palign + 89f931551bSRalph Campbell dd->piobcnt4k * dd->align4k; 90f931551bSRalph Campbell } 91f931551bSRalph Campbell 92f931551bSRalph Campbell for (bits = 0; !(piolen & (1ULL << bits)); bits++) 93f931551bSRalph Campbell /* do nothing */ ; 94f931551bSRalph Campbell 95f931551bSRalph Campbell if (piolen != (1ULL << bits)) { 96f931551bSRalph Campbell piolen >>= bits; 97f931551bSRalph Campbell while (piolen >>= 1) 98f931551bSRalph Campbell bits++; 99f931551bSRalph Campbell piolen = 1ULL << (bits + 1); 100f931551bSRalph Campbell } 101f931551bSRalph Campbell if (pioaddr & (piolen - 1)) { 102f931551bSRalph Campbell u64 atmp; 103f931551bSRalph Campbell atmp = pioaddr & ~(piolen - 1); 104f931551bSRalph Campbell if (atmp < addr || (atmp + piolen) > (addr + len)) { 105f931551bSRalph Campbell qib_dev_err(dd, "No way to align address/size " 106f931551bSRalph Campbell "(%llx/%llx), no WC mtrr\n", 107f931551bSRalph Campbell (unsigned long long) atmp, 108f931551bSRalph Campbell (unsigned long long) piolen << 1); 109f931551bSRalph Campbell ret = -ENODEV; 110f931551bSRalph Campbell } else { 111f931551bSRalph Campbell pioaddr = atmp; 112f931551bSRalph Campbell piolen <<= 1; 113f931551bSRalph Campbell } 114f931551bSRalph Campbell } 115f931551bSRalph Campbell 116f931551bSRalph Campbell if (!ret) { 117f931551bSRalph Campbell int cookie; 118f931551bSRalph Campbell 119f931551bSRalph Campbell cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0); 120f931551bSRalph Campbell if (cookie < 0) { 121f931551bSRalph Campbell { 122f931551bSRalph Campbell qib_devinfo(dd->pcidev, 123f931551bSRalph Campbell "mtrr_add() WC for PIO bufs " 124f931551bSRalph Campbell "failed (%d)\n", 125f931551bSRalph Campbell cookie); 126f931551bSRalph Campbell ret = -EINVAL; 127f931551bSRalph Campbell } 128f931551bSRalph Campbell } else { 129f931551bSRalph Campbell dd->wc_cookie = cookie; 130f931551bSRalph Campbell dd->wc_base = (unsigned long) pioaddr; 131f931551bSRalph Campbell dd->wc_len = (unsigned long) piolen; 132f931551bSRalph Campbell } 133f931551bSRalph Campbell } 134f931551bSRalph Campbell 135f931551bSRalph Campbell return ret; 136f931551bSRalph Campbell } 137f931551bSRalph Campbell 138f931551bSRalph Campbell /** 139f931551bSRalph Campbell * qib_disable_wc - disable write combining for MMIO writes to the device 140f931551bSRalph Campbell * @dd: qlogic_ib device 141f931551bSRalph Campbell */ 142f931551bSRalph Campbell void qib_disable_wc(struct qib_devdata *dd) 143f931551bSRalph Campbell { 144f931551bSRalph Campbell if (dd->wc_cookie) { 145f931551bSRalph Campbell int r; 146f931551bSRalph Campbell 147f931551bSRalph Campbell r = mtrr_del(dd->wc_cookie, dd->wc_base, 148f931551bSRalph Campbell dd->wc_len); 149f931551bSRalph Campbell if (r < 0) 150f931551bSRalph Campbell qib_devinfo(dd->pcidev, 151f931551bSRalph Campbell "mtrr_del(%lx, %lx, %lx) failed: %d\n", 152f931551bSRalph Campbell dd->wc_cookie, dd->wc_base, 153f931551bSRalph Campbell dd->wc_len, r); 154f931551bSRalph Campbell dd->wc_cookie = 0; /* even on failure */ 155f931551bSRalph Campbell } 156f931551bSRalph Campbell } 157f931551bSRalph Campbell 158f931551bSRalph Campbell /** 159f931551bSRalph Campbell * qib_unordered_wc - indicate whether write combining is ordered 160f931551bSRalph Campbell * 161f931551bSRalph Campbell * Because our performance depends on our ability to do write combining mmio 162f931551bSRalph Campbell * writes in the most efficient way, we need to know if we are on an Intel 163f931551bSRalph Campbell * or AMD x86_64 processor. AMD x86_64 processors flush WC buffers out in 164f931551bSRalph Campbell * the order completed, and so no special flushing is required to get 165f931551bSRalph Campbell * correct ordering. Intel processors, however, will flush write buffers 166f931551bSRalph Campbell * out in "random" orders, and so explicit ordering is needed at times. 167f931551bSRalph Campbell */ 168f931551bSRalph Campbell int qib_unordered_wc(void) 169f931551bSRalph Campbell { 170f931551bSRalph Campbell return boot_cpu_data.x86_vendor != X86_VENDOR_AMD; 171f931551bSRalph Campbell } 172