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 + -
显示快捷键?