ipath_wc_x86_64.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 158 行

C
158
字号
/* * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *        copyright notice, this list of conditions and the following *        disclaimer. * *      - Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the following *        disclaimer in the documentation and/or other materials *        provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *//* * This file is conditionally built on x86_64 only.  Otherwise weak symbol * versions of the functions exported from here are used. */#include <linux/pci.h>#include <asm/mtrr.h>#include <asm/processor.h>#include "ipath_kernel.h"/** * ipath_enable_wc - enable write combining for MMIO writes to the device * @dd: infinipath device * * This routine is x86_64-specific; it twiddles the CPU's MTRRs to enable * write combining. */int ipath_enable_wc(struct ipath_devdata *dd){	int ret = 0;	u64 pioaddr, piolen;	unsigned bits;	const unsigned long addr = pci_resource_start(dd->pcidev, 0);	const size_t len = pci_resource_len(dd->pcidev, 0);	/*	 * Set the PIO buffers to be WCCOMB, so we get HT bursts to the	 * chip.  Linux (possibly the hardware) requires it to be on a power	 * 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.	 */	pioaddr = addr + dd->ipath_piobufbase;	piolen = (dd->ipath_piobcnt2k +		  dd->ipath_piobcnt4k) *		ALIGN(dd->ipath_piobcnt2k +		      dd->ipath_piobcnt4k, dd->ipath_palign);	for (bits = 0; !(piolen & (1ULL << bits)); bits++)		/* do nothing */ ;	if (piolen != (1ULL << bits)) {		piolen >>= bits;		while (piolen >>= 1)			bits++;		piolen = 1ULL << (bits + 1);	}	if (pioaddr & (piolen - 1)) {		u64 atmp;		ipath_dbg("pioaddr %llx not on right boundary for size "			  "%llx, fixing\n",			  (unsigned long long) pioaddr,			  (unsigned long long) piolen);		atmp = pioaddr & ~(piolen - 1);		if (atmp < addr || (atmp + piolen) > (addr + len)) {			ipath_dev_err(dd, "No way to align address/size "				      "(%llx/%llx), no WC mtrr\n",				      (unsigned long long) atmp,				      (unsigned long long) piolen << 1);			ret = -ENODEV;		} else {			ipath_dbg("changing WC base from %llx to %llx, "				  "len from %llx to %llx\n",				  (unsigned long long) pioaddr,				  (unsigned long long) atmp,				  (unsigned long long) piolen,				  (unsigned long long) piolen << 1);			pioaddr = atmp;			piolen <<= 1;		}	}	if (!ret) {		int cookie;		ipath_cdbg(VERBOSE, "Setting mtrr for chip to WC "			   "(addr %llx, len=0x%llx)\n",			   (unsigned long long) pioaddr,			   (unsigned long long) piolen);		cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0);		if (cookie < 0) {			{				dev_info(&dd->pcidev->dev,					 "mtrr_add()  WC for PIO bufs "					 "failed (%d)\n",					 cookie);				ret = -EINVAL;			}		} else {			ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, "				   "cookie is %d\n", cookie);			dd->ipath_wc_cookie = cookie;		}	}	return ret;}/** * ipath_disable_wc - disable write combining for MMIO writes to the device * @dd: infinipath device */void ipath_disable_wc(struct ipath_devdata *dd){	if (dd->ipath_wc_cookie) {		ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n");		mtrr_del(dd->ipath_wc_cookie, 0, 0);		dd->ipath_wc_cookie = 0;	}}/** * ipath_unordered_wc - indicate whether write combining is ordered * * Because our performance depends on our ability to do write combining mmio * writes in the most efficient way, we need to know if we are on an Intel * or AMD x86_64 processor.  AMD x86_64 processors flush WC buffers out in * the order completed, and so no special flushing is required to get * correct ordering.  Intel processors, however, will flush write buffers * out in "random" orders, and so explicit ordering is needed at times. */int ipath_unordered_wc(void){	return boot_cpu_data.x86_vendor != X86_VENDOR_AMD;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?