Commit 8c3076d4 authored by Anton Blanchard's avatar Anton Blanchard

ppc64: iSeries updates from iSeries team

ppc64: time updates from Mike Corrigan
ppc64: add flush_hash_range for pSeries LPAR
ppc64: align syscall tables to 8 bytes
parent 0eef6190
......@@ -53,6 +53,8 @@ struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue )
struct HvLpEvent * nextLpEvent =
(struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
if ( nextLpEvent->xFlags.xValid ) {
/* rmb() needed only for weakly consistent machines (regatta) */
rmb();
/* Set pointer to next potential event */
lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
LpEventAlign ) /
......
......@@ -144,7 +144,9 @@ struct ItLpNaca itLpNaca = {
struct ItIplParmsReal xItIplParmsReal = {};
struct IoHriProcessorVpd xIoHriProcessorVpd[maxProcessors] = {
#define maxPhysicalProcessors 32
struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
{
xInstCacheOperandSize: 32,
xDataCacheOperandSize: 32,
......@@ -172,7 +174,7 @@ struct ItVpdAreas itVpdAreas = {
0, 0,
26, /* # VPD array entries */
10, /* # DMA array entries */
maxProcessors*2, maxProcessors, /* Max logical, physical procs */
maxProcessors*2, maxPhysicalProcessors, /* Max logical, physical procs */
offsetof(struct ItVpdAreas,xPlicDmaToks),/* offset to DMA toks */
offsetof(struct ItVpdAreas,xSlicVpdAdrs),/* offset to VPD addrs */
offsetof(struct ItVpdAreas,xPlicDmaLens),/* offset to DMA lens */
......
......@@ -342,12 +342,15 @@ chrp_progress(char *s, unsigned short hex)
extern void setup_default_decr(void);
extern unsigned long ppc_proc_freq;
extern unsigned long ppc_tb_freq;
void __init pSeries_calibrate_decr(void)
{
struct device_node *cpu;
struct div_result divres;
int *fp;
unsigned long freq;
unsigned long freq, processor_freq;
/*
* The cpu node should have a timebase-frequency property
......@@ -360,8 +363,19 @@ void __init pSeries_calibrate_decr(void)
if (fp != 0)
freq = *fp;
}
ppc_tb_freq = freq;
processor_freq = freq;
if (cpu != 0) {
fp = (int *) get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
processor_freq = *fp;
}
ppc_proc_freq = processor_freq;
printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
freq/1000000, freq%1000000 );
printk("time_init: processor frequency = %lu.%.6lu MHz\n",
processor_freq/1000000, processor_freq%1000000 );
tb_ticks_per_jiffy = freq / HZ;
tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
......
......@@ -106,7 +106,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber busNumber, HvSubBusNumber subBusNumb
{
u8 idsel = (deviceId >> 4);
u8 function = deviceId & 0x0F;
int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 254) + 1;
int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 253) + 2;
return irq;
}
......
......@@ -21,6 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
......@@ -36,12 +37,12 @@
#include <asm/ppcdebug.h>
#include <asm/Naca.h>
#include <asm/flight_recorder.h>
#include <asm/pci_dma.h>
#include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/HvCallSm.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/LparData.h>
#include <asm/iSeries/iSeries_dma.h>
#include <asm/iSeries/iSeries_irq.h>
#include <asm/iSeries/iSeries_pci.h>
#include <asm/iSeries/mf.h>
......@@ -92,12 +93,12 @@ struct pci_controller* alloc_phb(struct device_node *dev, char *model, un
void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb);
void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgents);
int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* Info);
void list_device_nodes(void);
struct pci_dev;
LIST_HEAD(Global_Device_List);
extern struct list_head iSeries_Global_Device_List;
int DeviceCount = 0;
......@@ -138,6 +139,9 @@ void dumpDevice_Node(struct iSeries_Device_Node* DevNode)
ISERIES_SUBBUS(DevNode),
DevNode->AgentId,
DevNode->DevFn);
udbg_printf(" - LSlot = 0x%02X\n",DevNode->LogicalSlot);
udbg_printf(" - TceTable = 0x%p\n ",DevNode->DevTceTable);
udbg_printf(" - DSA = 0x%04X\n",ISERIES_DSA(DevNode)>>32 );
udbg_printf(" = Irq:0x%02X Vendor:0x%04X Flags:0x%02X\n",
......@@ -145,14 +149,16 @@ void dumpDevice_Node(struct iSeries_Device_Node* DevNode)
DevNode->Vendor,
DevNode->Flags );
udbg_printf(" - Location = %s\n",DevNode->CardLocation);
}
/**********************************************************************************
* Walk down the device node chain
**********************************************************************************/
void list_device_nodes(void)
{
struct list_head* Device_Node_Ptr = Global_Device_List.next;
while(Device_Node_Ptr != &Global_Device_List) {
struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next;
while(Device_Node_Ptr != &iSeries_Global_Device_List) {
dumpDevice_Node( (struct iSeries_Device_Node*)Device_Node_Ptr );
Device_Node_Ptr = Device_Node_Ptr->next;
}
......@@ -167,13 +173,13 @@ struct iSeries_Device_Node* build_device_node(HvBusNumber Bus, HvSubBusNumber S
{
struct iSeries_Device_Node* DeviceNode;
PPCDBG(PPCDBG_BUSWALK,"- "__FUNCTION__" 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function);
PPCDBG(PPCDBG_BUSWALK,"-build_device_node 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function);
DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL);
if(DeviceNode == NULL) return NULL;
memset(DeviceNode,0,sizeof(struct iSeries_Device_Node) );
list_add_tail(&DeviceNode->Device_List,&Global_Device_List);
list_add_tail(&DeviceNode->Device_List,&iSeries_Global_Device_List);
/*DeviceNode->DsaAddr = ((u64)Bus<<48)+((u64)SubBus<<40)+((u64)0x10<<32); */
ISERIES_BUS(DeviceNode) = Bus;
ISERIES_SUBBUS(DeviceNode) = SubBus;
......@@ -224,7 +230,7 @@ unsigned long __init find_and_init_phbs(void)
struct pci_controller* phb;
HvBusNumber BusNumber;
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
PPCDBG(PPCDBG_BUSWALK,"find_and_init_phbs Entry\n");
/* Check all possible buses. */
for (BusNumber = 0; BusNumber < 256; BusNumber++) {
......@@ -239,7 +245,7 @@ unsigned long __init find_and_init_phbs(void)
phb->pci_mem_offset = phb->local_number = BusNumber;
phb->first_busno = BusNumber;
phb->last_busno = BusNumber;
phb->ops = &iSeries_pci_ops;
phb->ops = &iSeries_pci_ops;
PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",phb,BusNumber);
PCIFR("Create iSeries PHB controller: %04X",BusNumber);
......@@ -276,26 +282,15 @@ unsigned long __init find_and_init_phbs(void)
***********************************************************************/
void iSeries_pcibios_init(void)
{
struct pci_controller *phb;
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n");
PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Entry.\n");
iSeries_IoMmTable_Initialize();
find_and_init_phbs();
/* Create the TCE Tables */
phb = hose_head;
while(phb != NULL) {
create_pci_bus_tce_table(phb->local_number);
PCIFR("Bus 0x%04X TCE Table %p",phb->local_number,tceTables[phb->local_number] );
phb = phb->next;
}
pci_assign_all_busses = 0;
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Exit.\n");
PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n");
}
/***********************************************************************
* iSeries_pcibios_fixup(void)
***********************************************************************/
......@@ -306,11 +301,12 @@ void __init iSeries_pcibios_fixup(void)
char Buffer[256];
int DeviceCount = 0;
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n");
PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup Entry.\n");
/******************************************************/
/* Fix up at the device node and pci_dev relationship */
/******************************************************/
mf_displaySrc(0xC9000100);
pci_for_each_dev(PciDev) {
DeviceNode = find_Device_Node(PciDev);
if(DeviceNode != NULL) {
......@@ -327,6 +323,7 @@ void __init iSeries_pcibios_fixup(void)
iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) );
printk("%d. %s\n",DeviceCount,Buffer);
create_pci_bus_tce_table((unsigned long)DeviceNode);
} else {
printk("PCI: Device Tree not found for 0x%016lX\n",(unsigned long)PciDev);
}
......@@ -335,21 +332,16 @@ void __init iSeries_pcibios_fixup(void)
iSeries_activate_IRQs();
// This is test code.
//mf_displaySrc(0xC9000100);
//Pci_IoTest();
// Pci_CfgIoTest();
// mf_displaySrc(0xC9000500);
// Pci_MMIoTest();
//mf_displaySrc(0xC9000999);
}
mf_displaySrc(0xC9000200);
}
/***********************************************************************
* iSeries_pcibios_fixup_bus(int Bus)
*
***********************************************************************/
void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus)
{
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__"(0x%04X) Entry.\n",PciBus->number);
PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number);
}
......@@ -360,7 +352,7 @@ void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus)
***********************************************************************/
void fixup_resources(struct pci_dev *PciDev)
{
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" PciDev %p\n",PciDev);
PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev);
}
......@@ -395,7 +387,6 @@ void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb)
kfree(DevInfo);
}
/********************************************************************************
*
*********************************************************************************/
......@@ -418,18 +409,26 @@ void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel
if (HvRc == 0) {
/* Connect EADs: 0x18.00.12 = 0x00 */
PPCDBG(PPCDBG_BUSWALK,"PCI:Connect EADs: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId);
PCIFR( "Connect EADs: 0x%02X.%02X.%02X", Bus, SubBus, AgentId);
PCIFR( "Connect EADs: 0x%02X.%02X.%02X", Bus, SubBus, AgentId);
HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId,
REALADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo));
if (HvRc == 0) {
PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type: 0x%02X, SubBus 0x%02X, MaxAgents 0x%02X\n",
BridgeInfo->busUnitInfo.deviceType,
BridgeInfo->subBusNumber,
BridgeInfo->maxAgents);
PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
BridgeInfo->busUnitInfo.deviceType,
BridgeInfo->subBusNumber,
BridgeInfo->maxAgents,
BridgeInfo->maxSubBusNumber,
BridgeInfo->logicalSlotNumber);
PCIFR( "BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X",
BridgeInfo->busUnitInfo.deviceType,
BridgeInfo->subBusNumber,
BridgeInfo->maxAgents,
BridgeInfo->maxSubBusNumber,
BridgeInfo->logicalSlotNumber);
if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice) {
/* Scan_Bridge_Slot...: 0x18.00.12 */
iSeries_Scan_Bridge_Slot(Bus,BridgeInfo->subBusNumber,BridgeInfo->maxAgents);
iSeries_Scan_Bridge_Slot(Bus,BridgeInfo);
}
else printk("PCI: Invalid Bridge Configuration(0x%02X)",BridgeInfo->busUnitInfo.deviceType);
}
......@@ -444,17 +443,18 @@ void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel
* This assumes that the node slot is always on the primary bus!
*
*********************************************************************************/
int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgents)
{
struct iSeries_Device_Node* DeviceNode;
u16 VendorId = 0;
int HvRc = 0;
int Irq = 0;
int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
int FirstSlotId= 0;
int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* BridgeInfo)
{
struct iSeries_Device_Node* DeviceNode;
HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
u16 VendorId = 0;
int HvRc = 0;
int Irq = 0;
int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
int FirstSlotId = 0;
/**********************************************************/
/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
......@@ -466,7 +466,7 @@ int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgen
/****************************************************************************
* Connect all functions of any device found.
****************************************************************************/
for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) {
for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
for (Function = 0; Function < 8; ++Function) {
AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq);
......@@ -480,10 +480,13 @@ int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgen
PPCDBG(PPCDBG_BUSWALK,"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
Bus, SubBus, AgentId, VendorId);
++DeviceCount;
PCIFR("Device(%4d): 0x%02X.%02X.%02X",DeviceCount,Bus, SubBus, AgentId);
DeviceNode = build_device_node(Bus, SubBus, EADsIdSel, Function);
DeviceNode->Vendor = VendorId;
DeviceNode->Irq = Irq;
DeviceNode->Vendor = VendorId;
DeviceNode->Irq = Irq;
DeviceNode->LogicalSlot = BridgeInfo->logicalSlotNumber;
PCIFR("Device(%4d): 0x%02X.%02X.%02X 0x%02X 0x%04X",
DeviceCount,Bus, SubBus, AgentId,
DeviceNode->LogicalSlot,DeviceNode->Vendor);
/***********************************************************
* On the first device/function, assign irq to slot
......@@ -543,11 +546,11 @@ void* iSeries_memcpy_fromio(void *dest, void *source, size_t count)
**********************************************************************************/
struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev)
{
struct list_head* Device_Node_Ptr = Global_Device_List.next;
struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next;
int Bus = PciDev->bus->number;
int DevFn = PciDev->devfn;
while(Device_Node_Ptr != &Global_Device_List) {
while(Device_Node_Ptr != &iSeries_Global_Device_List) {
struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)Device_Node_Ptr;
if(Bus == ISERIES_BUS(DevNode) && DevFn == DevNode->DevFn) {
return DevNode;
......
......@@ -26,6 +26,7 @@
#include <linux/string.h>
#include <linux/bootmem.h>
#include <linux/blk.h>
#include <linux/seq_file.h>
#include <asm/processor.h>
#include <asm/machdep.h>
......@@ -587,6 +588,7 @@ static void __init build_iSeries_Memory_Map(void)
lmb_init();
lmb_add( 0, naca->physicalMemorySize );
lmb_analyze(); /* ?? */
lmb_reserve( 0, __pa(klimit));
/*
......@@ -603,8 +605,10 @@ static void __init build_iSeries_Memory_Map(void)
static void __init setup_iSeries_cache_sizes(void)
{
unsigned i,n;
naca->iCacheL1LineSize = xIoHriProcessorVpd[0].xInstCacheOperandSize;
naca->dCacheL1LineSize = xIoHriProcessorVpd[0].xDataCacheOperandSize;
unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
i = naca->iCacheL1LineSize;
......@@ -652,6 +656,9 @@ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
}
#endif /* CONFIG_PPC_ISERIES */
extern unsigned long ppc_proc_freq;
extern unsigned long ppc_tb_freq;
/*
* Document me.
*/
......@@ -659,7 +666,8 @@ void __init
iSeries_setup_arch(void)
{
void * eventStack;
unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
/* Setup the Lp Event Queue */
/* Allocate a page for the Event Stack
......@@ -685,15 +693,19 @@ iSeries_setup_arch(void)
xItLpQueue.xIndex = 0;
/* Compute processor frequency */
procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[0].xProcFreq );
procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[procIx].xProcFreq );
procFreqMhz = procFreqHz / 1000000;
procFreqMhzHundreths = (procFreqHz/10000) - (procFreqMhz*100);
ppc_proc_freq = procFreqHz;
/* Compute time base frequency */
tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[0].xTimeBaseFreq );
tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[procIx].xTimeBaseFreq );
tbFreqMhz = tbFreqHz / 1000000;
tbFreqMhzHundreths = (tbFreqHz/10000) - (tbFreqMhz*100);
ppc_tb_freq = tbFreqHz;
printk("Max logical processors = %d\n",
itVpdAreas.xSlicMaxLogicalProcs );
printk("Max physical processors = %d\n",
......@@ -705,12 +717,12 @@ iSeries_setup_arch(void)
tbFreqMhz,
tbFreqMhzHundreths );
printk("Processor version = %x\n",
xIoHriProcessorVpd[0].xPVR );
xIoHriProcessorVpd[procIx].xPVR );
}
/*
* int iSeries_setup_residual()
* int as400_setup_residual()
*
* Description:
* This routine pretty-prints CPU information gathered from the VPD
......@@ -726,20 +738,25 @@ iSeries_setup_arch(void)
* The number of bytes copied into 'buffer' if OK, otherwise zero or less
* on error.
*/
void
iSeries_setup_residual(struct seq_file *m, unsigned long cpu_id)
void iSeries_setup_residual(struct seq_file *m)
{
seq_printf(m, "clock\t\t: %lu.%02luMhz\n", procFreqMhz,
procFreqMhzHundreths);
seq_printf(m, "time base\t: %lu.%02luMHz\n", tbFreqMhz,
tbFreqMhzHundreths);
seq_printf(m, "i-cache\t\t: %d\n", naca->iCacheL1LineSize);
seq_printf(m, "d-cache\t\t: %d\n", naca->dCacheL1LineSize);
seq_printf(m,"clock\t\t: %lu.%02luMhz\n",
procFreqMhz, procFreqMhzHundreths );
seq_printf(m,"time base\t: %lu.%02luMHz\n",
tbFreqMhz, tbFreqMhzHundreths );
seq_printf(m,"i-cache\t\t: %d\n",
naca->iCacheL1LineSize);
seq_printf(m,"d-cache\t\t: %d\n",
naca->dCacheL1LineSize);
}
void iSeries_get_cpuinfo(struct seq_file *m)
{
seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
seq_printf(m,"machine\t\t: 64-bit iSeries Logical Partition\n");
}
/*
......@@ -805,29 +822,29 @@ extern void setup_default_decr(void);
void __init
iSeries_calibrate_decr(void)
{
unsigned long freq;
unsigned long cyclesPerUsec;
unsigned long tbf;
struct div_result divres;
/* Compute decrementer (and TB) frequency
* in cycles/sec
*/
tbf = xIoHriProcessorVpd[0].xTimeBaseFreq;
freq = 0x0100000000;
freq *= 1000000; /* 2^32 * 10^6 */
freq = freq / tbf; /* cycles / sec */
cyclesPerUsec = freq / 1000000; /* cycles / usec */
cyclesPerUsec = ppc_tb_freq / 1000000; /* cycles / usec */
/* Set the amount to refresh the decrementer by. This
* is the number of decrementer ticks it takes for
* 1/HZ seconds.
*/
tb_ticks_per_jiffy = freq / HZ;
tb_ticks_per_jiffy = ppc_tb_freq / HZ;
#if 0
/* TEST CODE FOR ADJTIME */
tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000;
/* END OF TEST CODE */
#endif
/*
* tb_ticks_per_sec = freq; would give better accuracy
* but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures
......@@ -836,7 +853,7 @@ iSeries_calibrate_decr(void)
*/
tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
tb_ticks_per_usec = cyclesPerUsec;
tb_to_us = mulhwu_scale_factor(freq, 1000000);
tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
tb_to_xs = divres.result_low;
setup_default_decr();
......
......@@ -19,8 +19,6 @@
#ifndef __ISERIES_SETUP_H__
#define __ISERIES_SETUP_H__
#include <linux/seq_file.h>
extern void iSeries_init_early(void);
extern void iSeries_init(unsigned long r3,
unsigned long ird_start,
......@@ -28,8 +26,7 @@ extern void iSeries_init(unsigned long r3,
unsigned long cline_start,
unsigned long cline_end);
extern void iSeries_setup_arch(void);
extern void iSeries_setup_residual(struct seq_file *m,
unsigned long cpu_id);
extern void iSeries_setup_residual(struct seq_file *m);
extern void iSeries_get_cpuinfo(struct seq_file *m);
extern void iSeries_init_IRQ(void);
extern int iSeries_get_irq(struct pt_regs *regs);
......
......@@ -516,8 +516,7 @@ _GLOBAL(kernel_thread)
#ifdef CONFIG_BINFMT_ELF32
/* Why isn't this a) automatic, b) written in 'C'? */
.data
.align 8
.balign 8
_GLOBAL(sys_call_table32)
.llong .sys_ni_syscall /* 0 - old "setup()" system call */
.llong .sys32_exit
......@@ -544,7 +543,7 @@ _GLOBAL(sys_call_table32)
.llong .sys_oldumount
.llong .sys_setuid
.llong .sys_getuid
.llong .ppc64_sys_stime /* 25 */
.llong .ppc64_sys32_stime /* 25 */
.llong .sys32_ptrace
.llong .sys_alarm
.llong .sys32_fstat
......@@ -745,8 +744,8 @@ _GLOBAL(sys_call_table32)
.llong .sys_ni_syscall
.endr
#endif
.data
.align 8
.balign 8
_GLOBAL(sys_call_table)
.llong .sys_ni_syscall /* 0 - old "setup()" system call */
.llong .sys_exit
......
......@@ -782,10 +782,6 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
}
}
/*
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
* lock.
*/
static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
int large, int local)
{
......@@ -801,10 +797,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
avpn = vpn >> 11;
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
lpar_rc = plpar_pte_remove(H_AVPN, slot, (vpn >> 4) & ~0x7fUL, &dummy1,
&dummy2);
spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
if (lpar_rc == H_Not_Found) {
udbg_printf("invalidate missed\n");
......@@ -846,4 +840,5 @@ void pSeries_lpar_mm_init(void)
ppc_md.insert_hpte = pSeries_lpar_insert_hpte;
ppc_md.remove_hpte = pSeries_lpar_remove_hpte;
ppc_md.make_pte = pSeries_lpar_make_pte;
ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range;
}
......@@ -277,6 +277,9 @@ void machine_halt(void)
ppc_md.halt();
}
unsigned long ppc_proc_freq;
unsigned long ppc_tb_freq;
static int show_cpuinfo(struct seq_file *m, void *v)
{
unsigned long cpu_id = (unsigned long)v - 1;
......@@ -286,10 +289,6 @@ static int show_cpuinfo(struct seq_file *m, void *v)
#ifdef CONFIG_SMP
if (cpu_id == NR_CPUS) {
unsigned long bogosum = smp_num_cpus * loops_per_jiffy;
seq_printf(m, "total bogomips\t: %lu.%02lu\n",
bogosum/(500000/HZ),
bogosum/(5000/HZ) % 100);
if (ppc_md.get_cpuinfo != NULL)
ppc_md.get_cpuinfo(m);
......@@ -357,10 +356,6 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "revision\t: %hd.%hd\n", maj, min);
seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
loops_per_jiffy/(500000/HZ),
loops_per_jiffy/(5000/HZ) % 100);
return 0;
}
......
......@@ -53,6 +53,7 @@
#include <asm/nvram.h>
#include <asm/cache.h>
#include <asm/machdep.h>
#include <asm/init.h>
#ifdef CONFIG_PPC_ISERIES
#include <asm/iSeries/HvCallXm.h>
#endif
......@@ -83,6 +84,7 @@ unsigned long next_xtime_sync_tb;
unsigned long xtime_sync_interval;
unsigned long tb_to_xs;
unsigned tb_to_us;
unsigned long processor_freq;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
struct gettimeofday_struct do_gtod;
......@@ -97,6 +99,10 @@ extern unsigned long prof_len;
extern unsigned long prof_shift;
extern char _stext;
void ppc_adjtimex(void);
static unsigned adjusting_time = 0;
static inline void ppc_do_profile (unsigned long nip)
{
if (!prof_buffer)
......@@ -269,6 +275,8 @@ int timer_interrupt(struct pt_regs * regs)
timer_sync_xtime( cur_tb );
timer_check_rtc();
write_unlock(&xtime_lock);
if ( adjusting_time && (time_adjust == 0) )
ppc_adjtimex();
}
paca->next_jiffy_update_tb += tb_ticks_per_jiffy;
}
......@@ -386,13 +394,35 @@ void do_settimeofday(struct timeval *tv)
* fields itself. This way, the fields which are used for
* do_settimeofday get updated too.
*/
long ppc64_sys_stime(int * tptr)
long ppc64_sys32_stime(int* tptr)
{
int value;
struct timeval myTimeval;
PPCDBG(PPCDBG_SYS32, "ppc64_sys_stime - entered - tptr=%p, *tptr=0x%x \n", tptr, *tptr);
if (!capable(CAP_SYS_TIME))
return -EPERM;
if (get_user(value, tptr))
return -EFAULT;
myTimeval.tv_sec = value;
myTimeval.tv_usec = 0;
do_settimeofday(&myTimeval);
return 0;
}
/*
* This function is a copy of the architecture independent function
* but which calls do_settimeofday rather than setting the xtime
* fields itself. This way, the fields which are used for
* do_settimeofday get updated too.
*/
long ppc64_sys_stime(long* tptr)
{
long value;
struct timeval myTimeval;
if (!capable(CAP_SYS_TIME))
return -EPERM;
......@@ -405,7 +435,6 @@ long ppc64_sys_stime(int * tptr)
do_settimeofday(&myTimeval);
PPCDBG(PPCDBG_SYS32, "ppc64_sys_stime - exiting w/ 0 \n");
return 0;
}
......@@ -426,6 +455,7 @@ void __init time_init(void)
tb_last_stamp = get_tb();
do_gtod.tb_orig_stamp = tb_last_stamp;
do_gtod.varp = &do_gtod.vars[0];
do_gtod.var_idx = 0;
do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
do_gtod.varp->tb_to_xs = tb_to_xs;
......@@ -434,6 +464,8 @@ void __init time_init(void)
xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
time_freq = 0;
xtime.tv_usec = 0;
last_rtc_update = xtime.tv_sec;
write_unlock_irqrestore(&xtime_lock, flags);
......@@ -452,10 +484,12 @@ void __init time_init(void)
* to microseconds to keep do_gettimeofday synchronized
* with ntpd.
* Use the time_freq and time_offset computed by adjtimex to
* Use the time_adjust, time_freq and time_offset computed by adjtimex to
* adjust the frequency.
*/
/* #define DEBUG_PPC_ADJTIMEX 1 */
void ppc_adjtimex(void)
{
unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, new_tb_to_xs, new_xsec, new_stamp_xsec;
......@@ -464,7 +498,12 @@ void ppc_adjtimex(void)
struct div_result divres;
unsigned long flags;
struct gettimeofday_vars * temp_varp;
unsigned temp_idx;
long singleshot_ppm = 0;
/* Compute parts per million frequency adjustment to accomplish the time adjustment
implied by time_offset to be applied over the elapsed time indicated by time_constant.
Use SHIFT_USEC to get it into the same units as time_freq. */
if ( time_offset < 0 ) {
ltemp = -time_offset;
ltemp <<= SHIFT_USEC - SHIFT_UPDATE;
......@@ -476,8 +515,40 @@ void ppc_adjtimex(void)
ltemp <<= SHIFT_USEC - SHIFT_UPDATE;
ltemp >>= SHIFT_KG + time_constant;
}
delta_freq = time_freq + ltemp;
/* If there is a single shot time adjustment in progress */
if ( time_adjust ) {
#ifdef DEBUG_PPC_ADJTIMEX
printk("ppc_adjtimex: ");
if ( adjusting_time == 0 )
printk("starting ");
printk("single shot time_adjust = %ld\n", time_adjust);
#endif
adjusting_time = 1;
/* Compute parts per million frequency adjustment to match time_adjust */
singleshot_ppm = tickadj * HZ;
/* The adjustment should be tickadj*HZ to match the code in linux/kernel/timer.c, but
experiments show that this is too large. 3/4 of tickadj*HZ seems about right */
singleshot_ppm -= singleshot_ppm / 4;
/* Use SHIFT_USEC to get it into the same units as time_freq */
singleshot_ppm <<= SHIFT_USEC;
if ( time_adjust < 0 )
singleshot_ppm = -singleshot_ppm;
}
else {
#ifdef DEBUG_PPC_ADJTIMEX
if ( adjusting_time )
printk("ppc_adjtimex: ending single shot time_adjust\n");
#endif
adjusting_time = 0;
}
/* Add up all of the frequency adjustments */
delta_freq = time_freq + ltemp + singleshot_ppm;
/* Compute a new value for tb_ticks_per_sec based on the frequency adjustment */
den = 1000000 * (1 << (SHIFT_USEC - 8));
if ( delta_freq < 0 ) {
tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( (-delta_freq) >> (SHIFT_USEC - 8))) / den;
......@@ -487,6 +558,16 @@ void ppc_adjtimex(void)
tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( delta_freq >> (SHIFT_USEC - 8))) / den;
new_tb_ticks_per_sec = tb_ticks_per_sec - tb_ticks_per_sec_delta;
}
#ifdef DEBUG_PPC_ADJTIMEX
printk("ppc_adjtimex: ltemp = %ld, time_freq = %ld, singleshot_ppm = %ld\n", ltemp, time_freq, singleshot_ppm);
printk("ppc_adjtimex: tb_ticks_per_sec - base = %ld new = %ld\n", tb_ticks_per_sec, new_tb_ticks_per_sec);
#endif
/* Compute a new value of tb_to_xs (used to convert tb to microseconds and a new value of
stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp. This
new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs)
which guarantees that the current time remains the same */
tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
new_tb_to_xs = divres.result_low;
......@@ -496,14 +577,23 @@ void ppc_adjtimex(void)
old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs );
new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec;
if (do_gtod.varp == &do_gtod.vars[0])
/* There are two copies of tb_to_xs and stamp_xsec so that no lock is needed to access and use these
values in do_gettimeofday. We alternate the copies and as long as a reasonable time elapses between
changes, there will never be inconsistent values. ntpd has a minimum of one minute between updates */
if (do_gtod.var_idx == 0) {
temp_varp = &do_gtod.vars[1];
else
temp_idx = 1;
}
else {
temp_varp = &do_gtod.vars[0];
temp_idx = 0;
}
temp_varp->tb_to_xs = new_tb_to_xs;
temp_varp->stamp_xsec = new_stamp_xsec;
mb();
do_gtod.varp = temp_varp;
do_gtod.var_idx = temp_idx;
write_unlock_irqrestore( &xtime_lock, flags );
......
......@@ -262,8 +262,10 @@ static int find_tb_table(unsigned long codeaddr, struct tbtable *tab);
static inline void disable_surveillance(void)
{
#ifndef CONFIG_PPC_ISERIES
rtas_call(rtas_token("set-indicator"), 3, 1, NULL, SURVEILLANCE_TOKEN,
0, 0);
#endif
}
void
......
......@@ -97,6 +97,8 @@ struct HvCallPci_BridgeInfo {
struct HvCallPci_BusUnitInfo busUnitInfo; // Generic bus unit info
u8 subBusNumber; // Bus number of secondary bus
u8 maxAgents; // Max idsels on secondary bus
u8 maxSubBusNumber; // Max Sub Bus
u8 logicalSlotNumber; // Logical Slot Number for IOA
};
......
......@@ -17,7 +17,7 @@
extern unsigned long reloc_offset(void);
#define MAX_LMB_REGIONS 32
#define MAX_LMB_REGIONS 64
union lmb_reg_property {
struct reg_property32 addr32[MAX_LMB_REGIONS];
......
......@@ -50,6 +50,7 @@ struct gettimeofday_struct {
unsigned long tb_ticks_per_sec;
struct gettimeofday_vars vars[2];
struct gettimeofday_vars * volatile varp;
unsigned var_idx;
unsigned tb_to_us;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment