iseries_pci.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 588 行 · 第 1/2 页

C
588
字号
/************************************************************************//* File iSeries_pci.c created by Allan Trautman on Tue Jan  9 2001.     *//************************************************************************//* This code supports the pci interface on the IBM iSeries systems.     *//* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    *//*                                                                      *//* This program is free software; you can redistribute it and/or modify *//* it under the terms of the GNU General Public License as published by *//* the Free Software Foundation; either version 2 of the License, or    *//* (at your option) any later version.                                  *//*                                                                      *//* This program is distributed in the hope that it will be useful,      */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of       *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *//* GNU General Public License for more details.                         *//*                                                                      *//* You should have received a copy of the GNU General Public License    */ /* along with this program; if not, write to the:                       *//* Free Software Foundation, Inc.,                                      */ /* 59 Temple Place, Suite 330,                                          */ /* Boston, MA  02111-1307  USA                                          *//************************************************************************//* Change Activity:                                                     *//*   Created, Jan 9, 2001                                               *//*   August, 10, 2001  Added PCI Retry code.                            *//* End Change Activity                                                  *//************************************************************************/#include <linux/config.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/pci.h>/************************************************************************//* Arch specific's                                                      *//************************************************************************/#include <asm/io.h>                /* Has Io Instructions.              */#include <asm/iSeries/iSeries_io.h>#include <asm/pci-bridge.h>#include <asm/iSeries/HvCallPci.h>#include <asm/iSeries/HvTypes.h>#include <asm/iSeries/mf.h>#include <asm/iSeries/iSeries_proc.h>#include <asm/iSeries/iSeries_FlightRecorder.h>#include <asm/iSeries/iSeries_VpdInfo.h>#include "iSeries_IoMmTable.h"#include "iSeries_pci.h"extern int panic_timeout;		       /* Panic Timeout reference      *//************************************************************************//* /proc/iSeries/pci initialization.                                    *//************************************************************************/extern void iSeries_pci_proc_init(struct proc_dir_entry *iSeries_proc);       void iSeries_pci_IoError(char* OpCode,iSeries_Device* Device);/************************************************************************//* PCI Config Space Access functions for IBM iSeries Systems            */ /*                                                                      *//* Modeled after the IBM Python                                         *//* int pci_read_config_word(struct pci_dev*, int Offset, u16* ValuePtr) *//************************************************************************//* Note: Normal these routines are defined by a macro and branch        *//* table is created and stuffed in the pci_bus structure.               *//* The following is for reference, if it was done this way.  However for*//* the first time out, the routines are individual coded.               */ /************************************************************************//* This is the low level architecture depend interface routines.        */     /* 1. They must be in specific order, see <linux/pci.h> for base        *//*    structure.                                                        *//* 2. The code in not inline here, it calls specific routines in        *//*    this module and HvCalls                                           *//* 3. The common convention is to put a pointer to the structure in     *//*    pci_bus->sysdata.                                                 *//* 4. Direct call is the same as in <linux/pci.h                        */  /************************************************************************/int iSeries_pci_read_config_byte(  struct pci_dev* PciDev, int Offset, u8* ValuePtr) {    iSeries_Device Device;    build_iSeries_Device(&Device, PciDev);    if(Device.BusNumber == 0xFF) Device.RCode = 0x301;	/* Trap out invalid bus. */    else {	Device.RCode = HvCallPci_configLoad8(Device.BusNumber, Device.SubBus, Device.DevFn, Offset, ValuePtr);	if(Device.RCode != 0 || PciTraceFlag > 0) {	    sprintf(PciFrBuffer,"RCB: %02X,%02X,%02X,%04X Rtn: %04X,%02X",		                 Device.BusNumber, Device.SubBus, Device.DevFn, Offset,		                 Device.RCode, *ValuePtr);	    ISERIES_PCI_FR(PciFrBuffer);	    if(Device.RCode != 0 ) printk("PCI: I/O Error %s",PciFrBuffer);	}    }    return Device.RCode;}                                                                            int iSeries_pci_read_config_word(  struct pci_dev* PciDev, int Offset, u16* ValuePtr) {    iSeries_Device Device;    build_iSeries_Device(&Device, PciDev);    if(Device.BusNumber == 0xFF) Device.RCode = 0x301;	/* Trap out invalid bus. */    else {	Device.RCode = HvCallPci_configLoad16(Device.BusNumber, Device.SubBus, Device.DevFn, Offset, ValuePtr);	if(Device.RCode != 0 || PciTraceFlag > 0) {	    sprintf(PciFrBuffer,"RCW: %02X,%02X,%02X,%04X Rtn: %04X,%04X",		                 Device.BusNumber, Device.SubBus, Device.DevFn, Offset,		                 Device.RCode, *ValuePtr);	    ISERIES_PCI_FR(PciFrBuffer);	    if(Device.RCode != 0 ) printk("PCI: I/O Error %s",PciFrBuffer);	}    }    return Device.RCode;}                                                                            int iSeries_pci_read_config_dword( struct pci_dev* PciDev, int Offset, u32* ValuePtr) {    iSeries_Device Device;    build_iSeries_Device(&Device, PciDev);    if(Device.BusNumber == 0xFF) Device.RCode = 0x301;	/* Trap out invalid bus. */    else {	Device.RCode = HvCallPci_configLoad32(Device.BusNumber, Device.SubBus, Device.DevFn, Offset, ValuePtr);	if(Device.RCode != 0 || PciTraceFlag > 0) {	    sprintf(PciFrBuffer,"RCL: %02X,%02X,%02X,%04X Rtn: %04X,%08X",		                 Device.BusNumber, Device.SubBus, Device.DevFn, Offset,		                 Device.RCode, *ValuePtr);	    ISERIES_PCI_FR(PciFrBuffer);	    if(Device.RCode != 0 ) printk("PCI: I/O Error %s",PciFrBuffer);	}    }    return Device.RCode;}                                                                            int iSeries_pci_write_config_byte( struct pci_dev* PciDev, int Offset,  u8  Value) {    iSeries_Device Device;    build_iSeries_Device(&Device, PciDev);    if(Device.BusNumber == 0xFF) Device.RCode = 0x301;	/* Trap out invalid bus. */    else {	Device.RCode = HvCallPci_configStore8(Device.BusNumber, Device.SubBus, Device.DevFn, Offset, Value);	if(Device.RCode != 0 || PciTraceFlag > 0) {	    sprintf(PciFrBuffer,"WCB: %02X,%02X,%02X,%04X Rtn: %04X,%02X",		                 Device.BusNumber, Device.SubBus, Device.DevFn, Offset,		                 Device.RCode, Value);	    ISERIES_PCI_FR(PciFrBuffer);	    if(Device.RCode != 0 ) printk("PCI: I/O Error %s",PciFrBuffer);	}    }    return Device.RCode;}                                                                            int iSeries_pci_write_config_word( struct pci_dev* PciDev, int Offset, u16  Value) {    iSeries_Device Device;    build_iSeries_Device(&Device, PciDev);    if(Device.BusNumber == 0xFF) Device.RCode = 0x301;	/* Trap out invalid bus. */    else {	Device.RCode = HvCallPci_configStore16(Device.BusNumber, Device.SubBus, Device.DevFn, Offset, Value);	if(Device.RCode != 0 || PciTraceFlag > 0) {	    sprintf(PciFrBuffer,"WCW: %02X,%02X,%02X,%04X Rtn: %04X,%04X",		                 Device.BusNumber, Device.SubBus, Device.DevFn, Offset,		                 Device.RCode, Value);	    ISERIES_PCI_FR(PciFrBuffer);	    if(Device.RCode != 0 ) printk("PCI: I/O Error %s",PciFrBuffer);	}    }    return Device.RCode;}                                                                            int iSeries_pci_write_config_dword(struct pci_dev* PciDev, int Offset, u32  Value) {    iSeries_Device Device;    build_iSeries_Device(&Device, PciDev);    if(Device.BusNumber == 0xFF) Device.RCode = 0x301;	/* Trap out invalid bus. */    else {	Device.RCode = HvCallPci_configStore32(Device.BusNumber, Device.SubBus, Device.DevFn, Offset, Value);	if(Device.RCode != 0 || PciTraceFlag > 0) {	    sprintf(PciFrBuffer,"WCL: %02X,%02X,%02X,%04X Rtn: %04X,%08X",		                 Device.BusNumber, Device.SubBus, Device.DevFn, Offset,		                 Device.RCode, Value);	    ISERIES_PCI_FR(PciFrBuffer);	    if(Device.RCode != 0 ) printk("PCI: I/O Error %s",PciFrBuffer);	}    }    return Device.RCode;}                                                                            /************************************************************************//* Branch Table                                                         *//************************************************************************/struct pci_ops iSeries_pci_ops = {	iSeries_pci_read_config_byte,	iSeries_pci_read_config_word,	iSeries_pci_read_config_dword,	iSeries_pci_write_config_byte,	iSeries_pci_write_config_word,	iSeries_pci_write_config_dword};/************************************************************************//* Dump the device info into the Flight Recorder                        *//* Call should have 3 char text to prefix FR Entry                      *//************************************************************************/void iSeries_DumpDevice(char* Text, iSeries_Device* Device) {	sprintf(PciFrBuffer,"%s:%02X%02X%02X %04X",Text,Device->BusNumber,Device->SubBus,Device->DevFn,Device->RCode);    ISERIES_PCI_FR(PciFrBuffer);    if(Device->BarNumber != 0xFF) {	sprintf(PciFrBuffer,"BAR:%02X %04X    ",Device->BarNumber,Device->BarOffset);	ISERIES_PCI_FR(PciFrBuffer);    }    if(Device->RCode != 0) {	/*****************************************************************/	/* PCI I/O ERROR RDL: Bus: 0x01 Device: 0x06 ReturnCode: 0x000B  */	/*****************************************************************/	printk("PCI: I/O ERROR %s: Bus: 0x%02X Device: 0x%02X ReturnCode: 0x%04X\n",	        Text,Device->PciDevPtr->bus->number,Device->PciDevPtr->devfn,Device->RCode);    }}int IoCounts    = 0;int RetryCounts = 0;int IoRetry     = 0;/************************************************************************ * Check Return Code * -> On Failure, print and log information. *    Increment Retry Count, if exceeds max, panic partition. * -> If in retry, print and log success  ************************************************************************ * PCI: ReadL: I/O Error( 0): 0x1234 * PCI: Device..: 17:38.10  Bar: 0x00  Offset 0018 * PCI: Device..: 17:38.10  Retry( 1) Operation ReadL: * PCI: Retry Successful on Device: 17:38.10 ************************************************************************/int  CheckReturnCode(char* TextHdr, iSeries_Device* Device) {	++IoCounts;	if(Device->RCode != 0)  {		sprintf(PciFrBuffer,"%s: I/O Error(%2d): 0x%04X\n",	TextHdr, IoRetry,Device->RCode);		ISERIES_PCI_FR(PciFrBuffer);		printk("PCI: %s",PciFrBuffer);		sprintf(PciFrBuffer,"Device..: %02X:%02X.%02X  Bar: 0x%02X  Offset %04X\n",			                         Device->BusNumber, Device->SubBus, Device->DevFn,		                              Device->BarNumber, Device->BarOffset); 		ISERIES_PCI_FR(PciFrBuffer);		printk("PCI: %s",PciFrBuffer);		/* Bump the retry and check for max. */		++RetryCounts;		++IoRetry;		/* Retry Count exceeded or RIO Bus went down. */		if(IoRetry > 7 || Device->RCode == 0x206) {			mf_displaySrc(0xB6000103);			panic_timeout = 0; 			panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.");		}		else {			sprintf(PciFrBuffer,"Device..: %02X:%02X.%02X  Retry(%2d) Operation: %s\n",			                         Device->BusNumber, Device->SubBus, Device->DevFn,			                         IoRetry,TextHdr);			ISERIES_PCI_FR(PciFrBuffer);			printk("PCI: %s\n",PciFrBuffer);		}	}	else {		if(IoRetry > 0 ) {			sprintf(PciFrBuffer,"Retry Successful on Device: %02X:%02X.%02X\n",			                         Device->BusNumber, Device->SubBus, Device->DevFn);			ISERIES_PCI_FR(PciFrBuffer);			printk("PCI: %s\n",PciFrBuffer);		}	}	return Device->RCode; }/************************************************************************//* Read MM I/O Instructions for the iSeries                             *//* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal*//* else, data is returned in big Endian format.                         *//************************************************************************//* iSeries_Readb = Read Byte  ( 8 bit)                                  *//* iSeries_Readw = Read Word  (16 bit)                                  *//* iSeries_Readl = Read Long  (32 bit)                                  *//************************************************************************/u8   iSeries_Readb(u32* IoAddress)	{	iSeries_Device Device;	u8             IoData;	u8             Data   = -1;	IoRetry = 0;	if(build_iSeries_Device_From_IoAddress(&Device, IoAddress) == 0) {		do {			Device.RCode = HvCallPci_barLoad8 (Device.BusNumber, Device.SubBus,Device.DevFn,   	     	                                   Device.BarNumber, Device.BarOffset, &IoData);        		Data = IoData;			if(Device.RCode != 0) CheckReturnCode("ReadB",&Device);		} while(Device.RCode != 0);     }	return Data;}u16 iSeries_Readw(u32* IoAddress)	{	iSeries_Device Device;	u16            IoData;    	u16            Data   = -1;	IoRetry = 0;	if(build_iSeries_Device_From_IoAddress(&Device, IoAddress) == 0) {		do {        		Device.RCode = HvCallPci_barLoad16(Device.BusNumber, Device.SubBus,Device.DevFn,    	     	                                   Device.BarNumber, Device.BarOffset, &IoData);

⌨️ 快捷键说明

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