os/kernelhwsrv/kernel/eka/nkernsmp/x86/ncirq.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32\nkernsmp\x86\ncirq.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
/**
sl@0
    19
 @file
sl@0
    20
 @internalTechnology
sl@0
    21
*/
sl@0
    22
sl@0
    23
#include "nk_priv.h"
sl@0
    24
#include "nk_plat.h"
sl@0
    25
#include <nk_irq.h>
sl@0
    26
#include <apic.h>
sl@0
    27
sl@0
    28
#ifdef _DEBUG
sl@0
    29
#define DMEMDUMP(base,size)	DbgMemDump((TLinAddr)base,size)
sl@0
    30
void DbgMemDump(TLinAddr aBase, TInt aSize)
sl@0
    31
	{
sl@0
    32
	TInt off;
sl@0
    33
	const TUint8* p=(const TUint8*)aBase;
sl@0
    34
	NKern::Lock();
sl@0
    35
	for (off=0; off<aSize; off+=16, p+=16)
sl@0
    36
		{
sl@0
    37
		DEBUGPRINT("%08x: %02x %02x %02x %02x  %02x %02x %02x %02x | %02x %02x %02x %02x  %02x %02x %02x %02x",
sl@0
    38
			p,		p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
sl@0
    39
					p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
sl@0
    40
		}
sl@0
    41
	NKern::Unlock();
sl@0
    42
	}
sl@0
    43
#else
sl@0
    44
#define DMEMDUMP(base,size)
sl@0
    45
#endif
sl@0
    46
sl@0
    47
#define	IO_APIC_BASE			0xFEC00000
sl@0
    48
#define	IO_APIC_REGSEL_OFFSET	0x00
sl@0
    49
#define	IO_APIC_IOWIN_OFFSET	0x10
sl@0
    50
sl@0
    51
#define	IO_APIC_REG_ID			0x00
sl@0
    52
#define	IO_APIC_REG_VER			0x01
sl@0
    53
#define	IO_APIC_REG_ARB			0x02
sl@0
    54
sl@0
    55
#define IO_APIC_CTRL_IMASK			0x10000		// 1 = masked
sl@0
    56
#define	IO_APIC_CTRL_LEVEL			0x08000		// 1 = level triggered, 0 = edge
sl@0
    57
#define	IO_APIC_CTRL_REMOTE_IRR		0x04000		//
sl@0
    58
#define	IO_APIC_CTRL_INTPOL_LOW		0x02000		// 1 = active low
sl@0
    59
#define	IO_APIC_CTRL_DELIVS			0x01000		//
sl@0
    60
#define	IO_APIC_CTRL_DESTMOD		0x00800		// 1 = logical, 0 = physical
sl@0
    61
#define	IO_APIC_CTRL_DELMOD_MASK	0x00700
sl@0
    62
#define	IO_APIC_CTRL_DELMOD_FIXED	0x00000
sl@0
    63
#define	IO_APIC_CTRL_DELMOD_LOWP	0x00100
sl@0
    64
#define	IO_APIC_CTRL_DELMOD_SMI		0x00200
sl@0
    65
#define	IO_APIC_CTRL_DELMOD_NMI		0x00400
sl@0
    66
#define	IO_APIC_CTRL_DELMOD_INIT	0x00500
sl@0
    67
#define	IO_APIC_CTRL_DELMOD_EXTINT	0x00700
sl@0
    68
#define	IO_APIC_CTRL_INTVEC_MASK	0x000FF
sl@0
    69
sl@0
    70
sl@0
    71
/******************************************************************************
sl@0
    72
 * IO APIC
sl@0
    73
 ******************************************************************************/
sl@0
    74
sl@0
    75
#define IO_APIC_SELECT(x)		((void)(*(volatile TUint32*)(iAddr + IO_APIC_REGSEL_OFFSET) = (x)))
sl@0
    76
#define	IO_APIC_REG				(*(volatile TUint32*)(iAddr + IO_APIC_IOWIN_OFFSET))
sl@0
    77
sl@0
    78
class TIoApic
sl@0
    79
	{
sl@0
    80
public:
sl@0
    81
	TIoApic(TLinAddr aAddr);
sl@0
    82
	TUint32 Id();
sl@0
    83
	TUint32 Ver();
sl@0
    84
	TUint32 Arb();
sl@0
    85
	TUint32 Dest(TInt aIndex);
sl@0
    86
	TUint32 Control(TInt aIndex);
sl@0
    87
	TUint32 ModifyDest(TInt aIndex, TUint32 aNewDest);
sl@0
    88
	TUint32 ModifyControl(TInt aIndex, TUint32 aClear, TUint32 aSet);
sl@0
    89
sl@0
    90
	void Dump();
sl@0
    91
public:
sl@0
    92
	TSpinLock iLock;
sl@0
    93
	TLinAddr iAddr;
sl@0
    94
	};
sl@0
    95
sl@0
    96
TIoApic TheIoApic(IO_APIC_BASE);
sl@0
    97
sl@0
    98
TIoApic::TIoApic(TLinAddr aAddr)
sl@0
    99
	: iLock(TSpinLock::EOrderBTrace)
sl@0
   100
	{
sl@0
   101
	iAddr = aAddr;
sl@0
   102
	}
sl@0
   103
sl@0
   104
TUint32 TIoApic::Id()
sl@0
   105
	{
sl@0
   106
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   107
	IO_APIC_SELECT(IO_APIC_REG_ID);
sl@0
   108
	TUint32 x = IO_APIC_REG;
sl@0
   109
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   110
	return x;
sl@0
   111
	}
sl@0
   112
sl@0
   113
TUint32 TIoApic::Ver()
sl@0
   114
	{
sl@0
   115
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   116
	IO_APIC_SELECT(IO_APIC_REG_VER);
sl@0
   117
	TUint32 x = IO_APIC_REG;
sl@0
   118
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   119
	return x;
sl@0
   120
	}
sl@0
   121
sl@0
   122
TUint32 TIoApic::Arb()
sl@0
   123
	{
sl@0
   124
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   125
	IO_APIC_SELECT(IO_APIC_REG_ARB);
sl@0
   126
	TUint32 x = IO_APIC_REG;
sl@0
   127
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   128
	return x;
sl@0
   129
	}
sl@0
   130
sl@0
   131
TUint32 TIoApic::Dest(TInt aIndex)
sl@0
   132
	{
sl@0
   133
	TUint32 reg = 2*aIndex + 0x11;
sl@0
   134
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   135
	IO_APIC_SELECT(reg);
sl@0
   136
	TUint32 x = IO_APIC_REG;
sl@0
   137
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   138
	return x>>24;
sl@0
   139
	}
sl@0
   140
sl@0
   141
TUint32 TIoApic::Control(TInt aIndex)
sl@0
   142
	{
sl@0
   143
	TUint32 reg = 2*aIndex + 0x10;
sl@0
   144
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   145
	IO_APIC_SELECT(reg);
sl@0
   146
	TUint32 x = IO_APIC_REG;
sl@0
   147
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   148
	return x;
sl@0
   149
	}
sl@0
   150
sl@0
   151
TUint32 TIoApic::ModifyDest(TInt aIndex, TUint32 aNewDest)
sl@0
   152
	{
sl@0
   153
	TUint32 reg = 2*aIndex + 0x11;
sl@0
   154
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   155
	IO_APIC_SELECT(reg);
sl@0
   156
	TUint32 x = IO_APIC_REG;
sl@0
   157
	IO_APIC_REG = (x&0x00ffffffu) | (aNewDest<<24);
sl@0
   158
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   159
	return x>>24;
sl@0
   160
	}
sl@0
   161
sl@0
   162
TUint32 TIoApic::ModifyControl(TInt aIndex, TUint32 aClear, TUint32 aSet)
sl@0
   163
	{
sl@0
   164
	TUint32 reg = 2*aIndex + 0x10;
sl@0
   165
	TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
sl@0
   166
	IO_APIC_SELECT(reg);
sl@0
   167
	TUint32 x = IO_APIC_REG;
sl@0
   168
	x &= ~aClear;
sl@0
   169
	x |= aSet;
sl@0
   170
	IO_APIC_SELECT(reg);
sl@0
   171
	IO_APIC_REG = x;
sl@0
   172
	__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
sl@0
   173
	return x;
sl@0
   174
	}
sl@0
   175
sl@0
   176
void TIoApic::Dump()
sl@0
   177
	{
sl@0
   178
	TUint32 id = Id();
sl@0
   179
	TUint32 ver = Ver();
sl@0
   180
	TUint32 arb = Arb();
sl@0
   181
	__KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC ID=%08x VER=%08x ARB=%08x", id, ver, arb));
sl@0
   182
sl@0
   183
	TInt max = (ver>>16)&0xff;
sl@0
   184
	TInt i;
sl@0
   185
	for (i=0; i<=max; ++i)
sl@0
   186
		{
sl@0
   187
		TUint32 dest = Dest(i);
sl@0
   188
		TUint32 ctrl = Control(i);
sl@0
   189
		__KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC[%02x] DEST=%02x CTRL=%08x", i, dest, ctrl));
sl@0
   190
		}
sl@0
   191
	}
sl@0
   192
sl@0
   193
sl@0
   194
void NIrq::HwEoi()
sl@0
   195
	{
sl@0
   196
	if (iX && iX->iEoiFn)
sl@0
   197
		(*iX->iEoiFn)(this);
sl@0
   198
	else
sl@0
   199
		{
sl@0
   200
		volatile TUint32* const apic_eoi = (volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_EOI);
sl@0
   201
		*apic_eoi = 0;
sl@0
   202
		}
sl@0
   203
	}
sl@0
   204
sl@0
   205
void NIrq::HwEnable()
sl@0
   206
	{
sl@0
   207
	if (iX && iX->iEnableFn)
sl@0
   208
		(*iX->iEnableFn)(this);
sl@0
   209
	else
sl@0
   210
		{
sl@0
   211
//		if ((iStaticFlags & ELevel) || (iIState & ERaw))
sl@0
   212
			TheIoApic.ModifyControl(iIndex, IO_APIC_CTRL_IMASK, 0);
sl@0
   213
		}
sl@0
   214
	}
sl@0
   215
sl@0
   216
void NIrq::HwDisable()
sl@0
   217
	{
sl@0
   218
	if (iX && iX->iDisableFn)
sl@0
   219
		(*iX->iDisableFn)(this);
sl@0
   220
	else
sl@0
   221
		{
sl@0
   222
		if ((iStaticFlags & ELevel) || (iIState & ERaw))
sl@0
   223
			TheIoApic.ModifyControl(iIndex, 0, IO_APIC_CTRL_IMASK);
sl@0
   224
		}
sl@0
   225
	}
sl@0
   226
sl@0
   227
void NIrq::HwSetCpu(TInt aCpu)
sl@0
   228
	{
sl@0
   229
	if (iX && iX->iSetCpuFn)
sl@0
   230
		(*iX->iSetCpuFn)(this, 1u<<aCpu);
sl@0
   231
	else
sl@0
   232
		{
sl@0
   233
		TheIoApic.ModifyDest(iIndex, 1u<<aCpu);
sl@0
   234
		}
sl@0
   235
	}
sl@0
   236
sl@0
   237
void NIrq::HwSetCpuMask(TUint32 aMask)
sl@0
   238
	{
sl@0
   239
	if (iX && iX->iSetCpuFn)
sl@0
   240
		(*iX->iSetCpuFn)(this, aMask);
sl@0
   241
	else
sl@0
   242
		{
sl@0
   243
		TheIoApic.ModifyDest(iIndex, aMask);
sl@0
   244
		}
sl@0
   245
	}
sl@0
   246
sl@0
   247
void NIrq::HwInit()
sl@0
   248
	{
sl@0
   249
	if (iX && iX->iInitFn)
sl@0
   250
		(*iX->iInitFn)(this);
sl@0
   251
	else
sl@0
   252
		{
sl@0
   253
		__KTRACE_OPT(KBOOT,DEBUGPRINT("NIrq %02x HwInit", iIndex));
sl@0
   254
		TUint32 clear = IO_APIC_CTRL_INTVEC_MASK;
sl@0
   255
		TUint32 set = iVector & IO_APIC_CTRL_INTVEC_MASK;
sl@0
   256
		set |= IO_APIC_CTRL_IMASK;
sl@0
   257
		if (iStaticFlags & ELevel)
sl@0
   258
			set |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/);
sl@0
   259
		else
sl@0
   260
			clear |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/);
sl@0
   261
		if (iStaticFlags & EPolarity)
sl@0
   262
			clear |= IO_APIC_CTRL_INTPOL_LOW;
sl@0
   263
		else
sl@0
   264
			set |= IO_APIC_CTRL_INTPOL_LOW;
sl@0
   265
		TheIoApic.ModifyControl(iIndex, clear, set);
sl@0
   266
		TheIoApic.Dump();
sl@0
   267
		}
sl@0
   268
	}
sl@0
   269
sl@0
   270
TBool NIrq::HwPending()
sl@0
   271
	{
sl@0
   272
	if (iX && iX->iPendingFn)
sl@0
   273
		return (*iX->iPendingFn)(this);
sl@0
   274
	return FALSE;
sl@0
   275
	}
sl@0
   276
sl@0
   277
void NIrq::HwWaitCpus()
sl@0
   278
	{
sl@0
   279
	if (iX && iX->iWaitFn)
sl@0
   280
		(*iX->iWaitFn)(this);
sl@0
   281
	}
sl@0
   282
sl@0
   283
void NIrq::HwInit0()
sl@0
   284
	{
sl@0
   285
	TheIoApic.Dump();
sl@0
   286
	TInt n = 1 + (TheIoApic.Ver() >> 16);
sl@0
   287
	TInt i;
sl@0
   288
	for (i=0; i<n; ++i)
sl@0
   289
		{
sl@0
   290
		TheIoApic.ModifyControl(i,
sl@0
   291
			IO_APIC_CTRL_DELMOD_MASK | IO_APIC_CTRL_INTVEC_MASK | IO_APIC_CTRL_LEVEL | IO_APIC_CTRL_INTPOL_LOW,
sl@0
   292
			IO_APIC_CTRL_DESTMOD | IO_APIC_CTRL_IMASK | 0xff);
sl@0
   293
		TheIoApic.ModifyDest(i, 0x01);
sl@0
   294
		if (i>15)
sl@0
   295
			{
sl@0
   296
			TheIoApic.ModifyControl(i, 0, IO_APIC_CTRL_LEVEL | IO_APIC_CTRL_INTPOL_LOW);
sl@0
   297
			}
sl@0
   298
		}
sl@0
   299
	TheIoApic.Dump();
sl@0
   300
	}
sl@0
   301
sl@0
   302
void NIrq::HwInit1()
sl@0
   303
	{
sl@0
   304
	write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR);
sl@0
   305
	write_apic_reg(DIVCNF, 10);				// APIC timer clock divide by 128 (bus clock freq / 128)
sl@0
   306
	write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR);
sl@0
   307
	write_apic_reg(DFR, 0xf0000000u);		// set flat logical destination mode
sl@0
   308
	write_apic_reg(LDR, 0x01000000u);		// this CPU will be selected by logical destination with bit 0 set
sl@0
   309
	}
sl@0
   310
sl@0
   311
void NIrq::HwInit2AP()
sl@0
   312
	{
sl@0
   313
	TInt cpu = NKern::CurrentCpu();
sl@0
   314
	write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR);
sl@0
   315
	write_apic_reg(DIVCNF, 10);
sl@0
   316
	write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR);
sl@0
   317
	write_apic_reg(DFR, 0xf0000000u);		// set flat logical destination mode
sl@0
   318
	write_apic_reg(LDR, 0x01000000u<<cpu);	// this CPU will be selected by logical destination with bit n set
sl@0
   319
	}