Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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