From 5472c0c23e590ed244f926c50634e5bc52c65057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 24 Nov 2009 15:26:52 +0000 Subject: [PATCH] * The VESA driver now tries to find the PCI card that it is controlling by checking the physical frame buffer location. * This allows us to map the whole frame buffer at once, which means there is no need anymore to remap the memory on mode change. * Also, this will ease the burden of the MTRRs, as the memory size will be properly aligned. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34206 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/frame_buffer_console.h | 1 + .../kernel/drivers/graphics/vesa/vesa.cpp | 155 +++++++++++++----- .../drivers/graphics/vesa/vesa_private.h | 5 + .../kernel/debug/frame_buffer_console.cpp | 3 +- 4 files changed, 120 insertions(+), 44 deletions(-) diff --git a/headers/private/kernel/frame_buffer_console.h b/headers/private/kernel/frame_buffer_console.h index a865a547ce..dc0011a9c4 100644 --- a/headers/private/kernel/frame_buffer_console.h +++ b/headers/private/kernel/frame_buffer_console.h @@ -17,6 +17,7 @@ struct kernel_args; struct frame_buffer_boot_info { area_id area; + addr_t physical_frame_buffer; addr_t frame_buffer; int32 width; int32 height; diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp index 1fbd334515..095290f80b 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp @@ -20,6 +20,40 @@ #include "vesa_info.h" +static status_t +find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size) +{ + // TODO: when we port this over to the new driver API, this mechanism can be + // used to find the right device_node + pci_module_info* pci; + if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK) + return B_ERROR; + + pci_info info; + for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) { + if (info.class_base != PCI_display) + continue; + + // check PCI BARs + for (uint32 i = 0; i < 6; i++) { + if (info.u.h0.base_registers[i] <= frameBuffer + && info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i] + > frameBuffer) { + // found it! + base = info.u.h0.base_registers[i]; + size = info.u.h0.base_register_sizes[i]; + + put_module(B_PCI_MODULE_NAME); + return B_OK; + } + } + } + + put_module(B_PCI_MODULE_NAME); + return B_ENTRY_NOT_FOUND; +} + + static uint32 get_color_space_for_depth(uint32 depth) { @@ -200,6 +234,61 @@ vbe_set_bits_per_gun(vesa_info& info, uint8 bits) } +/*! Remaps the frame buffer if necessary; if we've already mapped the complete + frame buffer, there is no need to map it again. +*/ +static status_t +remap_frame_buffer(vesa_info& info, addr_t physicalBase, + uint32 bytesPerRow, uint32 height, bool initializing) +{ + vesa_shared_info& sharedInfo = *info.shared_info; + addr_t frameBuffer; + + if (!info.complete_frame_buffer_mapped) { + addr_t base = physicalBase; + size_t size = bytesPerRow * height; + bool remap = !initializing; + + if (info.physical_frame_buffer_size != 0) { + // we can map the complete frame buffer + base = info.physical_frame_buffer; + size = info.physical_frame_buffer_size; + remap = true; + } + + if (remap) { + area_id area = map_physical_memory("vesa frame buffer", (void*)base, + size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, + (void**)&frameBuffer); + if (area < 0) + return area; + + delete_area(info.shared_info->frame_buffer_area); + + info.frame_buffer = frameBuffer; + sharedInfo.frame_buffer_area = area; + + // Turn on write combining for the area + vm_set_area_memory_type(area, base, B_MTR_WC); + + if (info.physical_frame_buffer_size != 0) + info.complete_frame_buffer_mapped = true; + } + } else + frameBuffer = info.frame_buffer; + + if (info.complete_frame_buffer_mapped) + frameBuffer += physicalBase - info.physical_frame_buffer; + + // Update shared frame buffer information + sharedInfo.frame_buffer = (uint8*)frameBuffer; + sharedInfo.physical_frame_buffer = (uint8*)physicalBase; + sharedInfo.bytes_per_row = bytesPerRow; + + return B_OK; +} + + // #pragma mark - @@ -212,6 +301,12 @@ vesa_init(vesa_info& info) return B_ERROR; info.vbe_capabilities = bufferInfo->vesa_capabilities; + info.complete_frame_buffer_mapped = false; + + // Find out which PCI device we belong to, so that we know its frame buffer + // size + find_graphics_card(bufferInfo->physical_frame_buffer, + info.physical_frame_buffer, info.physical_frame_buffer_size); size_t modesSize = 0; vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO, @@ -227,7 +322,7 @@ vesa_init(vesa_info& info) if (info.shared_area < 0) return info.shared_area; - vesa_shared_info &sharedInfo = *info.shared_info; + vesa_shared_info& sharedInfo = *info.shared_info; memset(&sharedInfo, 0, sizeof(vesa_shared_info)); @@ -239,13 +334,16 @@ vesa_init(vesa_info& info) } sharedInfo.frame_buffer_area = bufferInfo->area; - sharedInfo.frame_buffer = (uint8*)bufferInfo->frame_buffer; + + remap_frame_buffer(info, bufferInfo->physical_frame_buffer, + bufferInfo->bytes_per_row, bufferInfo->height, true); + // Does not matter if this fails - the frame buffer was already mapped + // before. sharedInfo.current_mode.virtual_width = bufferInfo->width; sharedInfo.current_mode.virtual_height = bufferInfo->height; sharedInfo.current_mode.space = get_color_space_for_depth( bufferInfo->depth); - sharedInfo.bytes_per_row = bufferInfo->bytes_per_row; edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO, NULL); @@ -259,10 +357,6 @@ vesa_init(vesa_info& info) if (bufferInfo->depth <= 8) vbe_set_bits_per_gun(info, 8); - physical_entry mapping; - get_memory_map((void*)sharedInfo.frame_buffer, B_PAGE_SIZE, &mapping, 1); - sharedInfo.physical_frame_buffer = (uint8*)mapping.address; - dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n"); return B_OK; } @@ -292,11 +386,8 @@ vesa_set_display_mode(vesa_info& info, uint32 mode) return status; } - area_id frameBufferArea; - frame_buffer_boot_info* bufferInfo; - struct vbe_mode_info modeInfo; - // Get mode information + struct vbe_mode_info modeInfo; status = vbe_get_mode_info(vmState, info.modes[mode].mode, &modeInfo); if (status != B_OK) { dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot get mode info\n"); @@ -313,39 +404,17 @@ vesa_set_display_mode(vesa_info& info, uint32 mode) if (info.modes[mode].bits_per_pixel <= 8) vbe_set_bits_per_gun(vmState, info, 8); - // Map new frame buffer - void* frameBuffer; - frameBufferArea = map_physical_memory("vesa_fb", - (void*)modeInfo.physical_base, modeInfo.bytes_per_row * modeInfo.height, - B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, &frameBuffer); - if (frameBufferArea < B_OK) { - status = (status_t)frameBufferArea; - goto out; + // Map new frame buffer if necessary + + status = remap_frame_buffer(info, modeInfo.physical_base, + modeInfo.bytes_per_row, modeInfo.height, false); + if (status == B_OK) { + // Update shared frame buffer information + info.shared_info->current_mode.virtual_width = modeInfo.width; + info.shared_info->current_mode.virtual_height = modeInfo.height; + info.shared_info->current_mode.space = get_color_space_for_depth( + modeInfo.bits_per_pixel); } - delete_area(info.shared_info->frame_buffer_area); - - // Turn on write combining for the area - vm_set_area_memory_type(frameBufferArea, modeInfo.physical_base, B_MTR_WC); - - // Update shared frame buffer information - info.shared_info->frame_buffer_area = frameBufferArea; - info.shared_info->frame_buffer = (uint8*)frameBuffer; - info.shared_info->physical_frame_buffer = (uint8*)modeInfo.physical_base; - info.shared_info->bytes_per_row = modeInfo.bytes_per_row; - info.shared_info->current_mode.virtual_width = modeInfo.width; - info.shared_info->current_mode.virtual_height = modeInfo.height; - info.shared_info->current_mode.space = get_color_space_for_depth( - modeInfo.bits_per_pixel); - - // Update boot item as it's used in vesa_init() - bufferInfo - = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); - bufferInfo->area = frameBufferArea; - bufferInfo->frame_buffer = (addr_t)frameBuffer; - bufferInfo->width = modeInfo.width; - bufferInfo->height = modeInfo.height; - bufferInfo->depth = modeInfo.bits_per_pixel; - bufferInfo->bytes_per_row = modeInfo.bytes_per_row; out: vm86_cleanup(&vmState); diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h b/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h index 15e955485d..cb494f2cc2 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h +++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h @@ -29,6 +29,11 @@ struct vesa_info { uint32 vbe_dpms_capabilities; uint8 vbe_capabilities; uint8 bits_per_gun; + + addr_t frame_buffer; + addr_t physical_frame_buffer; + size_t physical_frame_buffer_size; + bool complete_frame_buffer_mapped; }; extern status_t vesa_init(vesa_info& info); diff --git a/src/system/kernel/debug/frame_buffer_console.cpp b/src/system/kernel/debug/frame_buffer_console.cpp index 4f868820ef..12d48c7e20 100644 --- a/src/system/kernel/debug/frame_buffer_console.cpp +++ b/src/system/kernel/debug/frame_buffer_console.cpp @@ -413,7 +413,7 @@ frame_buffer_console_init(kernel_args* args) mutex_init(&sConsole.lock, "console_lock"); void* frameBuffer; - sConsole.area = map_physical_memory("vesa_fb", + sConsole.area = map_physical_memory("vesa frame buffer", (void*)args->frame_buffer.physical_buffer.start, args->frame_buffer.physical_buffer.size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA | B_USER_CLONEABLE_AREA, &frameBuffer); @@ -425,6 +425,7 @@ frame_buffer_console_init(kernel_args* args) args->frame_buffer.bytes_per_row); sBootInfo.area = sConsole.area; + sBootInfo.physical_frame_buffer = args->frame_buffer.physical_buffer.start; sBootInfo.frame_buffer = (addr_t)frameBuffer; sBootInfo.width = args->frame_buffer.width; sBootInfo.height = args->frame_buffer.height;