From 1f75663ca6601b1960c4e91b7e586e7d7bc27dd6 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 16 Oct 2011 20:48:54 +0000 Subject: [PATCH] Remove the interrupt register block. These aren't actually identitiy mapped (they are actually reversed), so introduce a find_reg() inline function to map such regs individually instead. Should fix interrupt storms on SandyBridge. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42870 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../graphics/intel_extreme/intel_extreme.h | 30 ++++++++++--------- .../graphics/intel_extreme/intel_extreme.cpp | 19 +++++------- .../intel_extreme/intel_extreme_private.h | 28 +++++++++++++++++ 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 5b9609ef70..5dc744d1f8 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -61,7 +61,7 @@ // We encode the register block into the value and extract/translate it when // actually accessing. -#define REGISTER_BLOCK_COUNT 7 +#define REGISTER_BLOCK_COUNT 6 #define REGISTER_BLOCK_SHIFT 24 #define REGISTER_BLOCK_MASK 0xff000000 #define REGISTER_REGISTER_MASK 0x00ffffff @@ -69,15 +69,13 @@ #define REGISTER_REGISTER(x) (x & REGISTER_REGISTER_MASK) #define REGS_FLAT (0 << REGISTER_BLOCK_SHIFT) -#define REGS_INTERRUPT (1 << REGISTER_BLOCK_SHIFT) -#define REGS_NORTH_SHARED (2 << REGISTER_BLOCK_SHIFT) -#define REGS_NORTH_PIPE_AND_PORT (3 << REGISTER_BLOCK_SHIFT) -#define REGS_NORTH_PLANE_CONTROL (4 << REGISTER_BLOCK_SHIFT) -#define REGS_SOUTH_SHARED (5 << REGISTER_BLOCK_SHIFT) -#define REGS_SOUTH_TRANSCODER_PORT (6 << REGISTER_BLOCK_SHIFT) +#define REGS_NORTH_SHARED (1 << REGISTER_BLOCK_SHIFT) +#define REGS_NORTH_PIPE_AND_PORT (2 << REGISTER_BLOCK_SHIFT) +#define REGS_NORTH_PLANE_CONTROL (3 << REGISTER_BLOCK_SHIFT) +#define REGS_SOUTH_SHARED (4 << REGISTER_BLOCK_SHIFT) +#define REGS_SOUTH_TRANSCODER_PORT (5 << REGISTER_BLOCK_SHIFT) // register blocks for (G)MCH/ICH based platforms -#define MCH_INTERRUPT_REGISTER_BASE 0x020a0 #define MCH_SHARED_REGISTER_BASE 0x00000 #define MCH_PIPE_AND_PORT_REGISTER_BASE 0x60000 #define MCH_PLANE_CONTROL_REGISTER_BASE 0x70000 @@ -88,7 +86,6 @@ // to a PCH based one, that means anything that used to communicate via (G)MCH // registers needs to use different ones on PCH based platforms (Ironlake and // up, SandyBridge, etc.). -#define PCH_DE_INTERRUPT_REGISTER_BASE 0x44000 #define PCH_NORTH_SHARED_REGISTER_BASE 0x40000 #define PCH_NORTH_PIPE_AND_PORT_REGISTER_BASE 0x60000 #define PCH_NORTH_PLANE_CONTROL_REGISTER_BASE 0x70000 @@ -338,13 +335,18 @@ struct intel_free_graphics_memory { #define INTEL_RING_BUFFER_ENABLED 1 // interrupts -#define INTEL_INTERRUPT_ENABLED (0x0000 | REGS_INTERRUPT) -#define INTEL_INTERRUPT_IDENTITY (0x0004 | REGS_INTERRUPT) -#define INTEL_INTERRUPT_MASK (0x0008 | REGS_INTERRUPT) -#define INTEL_INTERRUPT_STATUS (0x000c | REGS_INTERRUPT) +#define INTEL_INTERRUPT_ENABLED 0x02a0 +#define INTEL_INTERRUPT_IDENTITY 0x02a4 +#define INTEL_INTERRUPT_MASK 0x02a8 +#define INTEL_INTERRUPT_STATUS 0x02ac #define INTERRUPT_VBLANK_PIPEA (1 << 7) #define INTERRUPT_VBLANK_PIPEB (1 << 5) -// TODO: verify that these are actually different on older versions + +// PCH interrupts +#define PCH_INTERRUPT_STATUS 0x44000 +#define PCH_INTERRUPT_MASK 0x44004 +#define PCH_INTERRUPT_IDENTITY 0x44008 +#define PCH_INTERRUPT_ENABLED 0x4400c #define PCH_INTERRUPT_VBLANK_PIPEA (1 << 7) #define PCH_INTERRUPT_VBLANK_PIPEB (1 << 15) diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index b8a268c3d9..850184288f 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -76,7 +76,7 @@ intel_interrupt_handler(void* data) { intel_info &info = *(intel_info*)data; - uint16 identity = read16(info, INTEL_INTERRUPT_IDENTITY); + uint16 identity = read16(info, find_reg(info, INTEL_INTERRUPT_IDENTITY)); if (identity == 0) return B_UNHANDLED_INTERRUPT; @@ -103,7 +103,7 @@ intel_interrupt_handler(void* data) } // setting the bit clears it! - write16(info, INTEL_INTERRUPT_IDENTITY, identity); + write16(info, find_reg(info, INTEL_INTERRUPT_IDENTITY), identity); return handled; } @@ -142,7 +142,7 @@ init_interrupt_handler(intel_info &info) write32(info, INTEL_DISPLAY_B_PIPE_STATUS, DISPLAY_PIPE_VBLANK_STATUS | DISPLAY_PIPE_VBLANK_ENABLED); - write16(info, INTEL_INTERRUPT_IDENTITY, ~0); + write16(info, find_reg(info, INTEL_INTERRUPT_IDENTITY), ~0); // enable interrupts - we only want VBLANK interrupts bool hasPCH = info.device_type.HasPlatformControlHub(); @@ -150,9 +150,8 @@ init_interrupt_handler(intel_info &info) ? (PCH_INTERRUPT_VBLANK_PIPEA | PCH_INTERRUPT_VBLANK_PIPEB) : (INTERRUPT_VBLANK_PIPEA | INTERRUPT_VBLANK_PIPEB); - write16(info, INTEL_INTERRUPT_ENABLED, - read16(info, INTEL_INTERRUPT_ENABLED) | enable); - write16(info, INTEL_INTERRUPT_MASK, ~enable); + write16(info, find_reg(info, INTEL_INTERRUPT_ENABLED), enable); + write16(info, find_reg(info, INTEL_INTERRUPT_MASK), ~enable); } } if (status < B_OK) { @@ -250,8 +249,6 @@ intel_extreme_init(intel_info &info) // setup the register blocks for the different architectures if (info.device_type.HasPlatformControlHub()) { // PCH based platforms (IronLake and up) - blocks[REGISTER_BLOCK(REGS_INTERRUPT)] - = PCH_DE_INTERRUPT_REGISTER_BASE; blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)] = PCH_NORTH_SHARED_REGISTER_BASE; blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)] @@ -264,8 +261,6 @@ intel_extreme_init(intel_info &info) = PCH_SOUTH_TRANSCODER_AND_PORT_REGISTER_BASE; } else { // (G)MCH/ICH based platforms - blocks[REGISTER_BLOCK(REGS_INTERRUPT)] - = MCH_INTERRUPT_REGISTER_BASE; blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)] = MCH_SHARED_REGISTER_BASE; blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)] @@ -401,8 +396,8 @@ intel_extreme_uninit(intel_info &info) if (!info.fake_interrupts && info.shared_info->vblank_sem > 0) { // disable interrupt generation - write16(info, INTEL_INTERRUPT_ENABLED, 0); - write16(info, INTEL_INTERRUPT_MASK, ~0); + write16(info, find_reg(info, INTEL_INTERRUPT_ENABLED), 0); + write16(info, find_reg(info, INTEL_INTERRUPT_MASK), ~0); remove_io_interrupt_handler(info.pci->u.h0.interrupt_line, intel_interrupt_handler, &info); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h index 906395d4de..15e3efc966 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h @@ -39,6 +39,34 @@ struct intel_info { DeviceType device_type; }; + +static inline uint32 +find_reg(const intel_info& info, uint32 target) +{ + if (REGISTER_BLOCK(target) != REGS_FLAT) { + panic("find_reg is only supposed to be used for unrouped registers\n"); + return target; + } + + if (!info.device_type.HasPlatformControlHub()) + return target; + + #define RETURN_REG(x) case INTEL_##x: return PCH_##x; + + switch (target) { + RETURN_REG(INTERRUPT_ENABLED) + RETURN_REG(INTERRUPT_IDENTITY) + RETURN_REG(INTERRUPT_MASK) + RETURN_REG(INTERRUPT_STATUS) + } + + #undef RETURN_REG; + + panic("find_reg didn't have any matching register\n"); + return target; +} + + extern status_t intel_free_memory(intel_info& info, addr_t offset); extern status_t intel_allocate_memory(intel_info& info, size_t size, size_t alignment, uint32 flags, addr_t* _offset,