dde_linux: KMS-based Intel framebuffer driver (II)

* enable i915 driver from Linux 3.14.5
* tested for generation 5 till 8 GPUs

The driver can be configured at run-time via the config ROM. Every
connector of the graphic card can be configured separately using the
following syntax

  <config>
    <connector name="LVDS-11" width="1280" height="800" enabled="true"/>
  </config>

Also, when enabled within the intel framebuffer driver configuration like
the following

  <config buffered="yes"/>

a simple ram dataspace is propagated to the client and the driver
itselfs copies from that buffer to the framebuffer triggered via refresh
calls. This option is useful to alleviate tearing effects.

The  driver distributes all available connectors of the graphic card and
their supported resolutions via a report. It looks like follows

  <connectors>
    <connector name="LVDS-11" connected="1">
      <mode width="1280" height="800" hz="60"/>
      ...
    </connector>
    ...
  </connectors>

The driver distributes the report only if this is stated within its
configuration, like the following

  <config>
    <report connectors="yes"/>
  </config>

Fix #1764
This commit is contained in:
Stefan Kalkowski 2015-09-18 16:34:19 +02:00 committed by Christian Helmuth
parent 520c36d77f
commit d65beb970d
43 changed files with 2299 additions and 1060 deletions

View File

@ -38,7 +38,12 @@ proc platform_drv_policy {} {
<policy label="wifi_drv"> <pci class="WIFI"/> </policy>
<policy label="usb_drv"> <pci class="USB"/> </policy>
<policy label="ahci_drv"> <pci class="AHCI"/> </policy>
<policy label="audio_drv"> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>}
<policy label="audio_drv"> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>
<policy label="intel_fb_drv" irq_mode="nomsi">
<pci class="VGA"/>
<pci bus="0" device="0" function="0"/>
<pci class="ISABRIDGE"/>
</policy>}
} else {
return {}
}

View File

@ -6,9 +6,14 @@ linux-3.14.5/drivers/char/agp/backend.c
linux-3.14.5/drivers/i2c/i2c-core.c
linux-3.14.5/drivers/i2c/i2c-core.h
linux-3.14.5/drivers/i2c/i2c-boardinfo.c
linux-3.14.5/drivers/i2c/algos/i2c-algo-bit.c
linux-3.14.5/drivers/gpu/drm/drm_mm.c
linux-3.14.5/drivers/gpu/drm/drm_crtc.c
linux-3.14.5/drivers/gpu/drm/drm_crtc_helper.c
linux-3.14.5/drivers/gpu/drm/drm_edid.c
linux-3.14.5/drivers/gpu/drm/drm_modes.c
linux-3.14.5/drivers/gpu/drm/drm_dp_helper.c
linux-3.14.5/drivers/gpu/drm/drm_fb_helper.c
linux-3.14.5/drivers/gpu/drm/i915/i915_dma.c
linux-3.14.5/drivers/gpu/drm/i915/i915_drv.c
linux-3.14.5/drivers/gpu/drm/i915/i915_drv.h
@ -18,15 +23,26 @@ linux-3.14.5/drivers/gpu/drm/i915/i915_reg.h
linux-3.14.5/drivers/gpu/drm/i915/i915_gem_gtt.c
linux-3.14.5/drivers/gpu/drm/i915/i915_irq.c
linux-3.14.5/drivers/gpu/drm/i915/intel_bios.h
linux-3.14.5/drivers/gpu/drm/i915/intel_bios.c
linux-3.14.5/drivers/gpu/drm/i915/intel_crt.c
linux-3.14.5/drivers/gpu/drm/i915/intel_ddi.c
linux-3.14.5/drivers/gpu/drm/i915/intel_dp.c
linux-3.14.5/drivers/gpu/drm/i915/intel_drv.h
linux-3.14.5/drivers/gpu/drm/i915/intel_fbdev.c
linux-3.14.5/drivers/gpu/drm/i915/intel_hdmi.c
linux-3.14.5/drivers/gpu/drm/i915/intel_ringbuffer.h
linux-3.14.5/drivers/gpu/drm/i915/intel_display.c
linux-3.14.5/drivers/gpu/drm/i915/intel_panel.c
linux-3.14.5/drivers/gpu/drm/i915/intel_uncore.c
linux-3.14.5/drivers/gpu/drm/i915/intel_lvds.c
linux-3.14.5/drivers/gpu/drm/i915/intel_i2c.c
linux-3.14.5/drivers/gpu/drm/i915/intel_overlay.c
linux-3.14.5/drivers/gpu/drm/i915/intel_pm.c
linux-3.14.5/drivers/gpu/drm/i915/intel_modes.c
linux-3.14.5/drivers/gpu/drm/i915/intel_sideband.c
linux-3.14.5/drivers/gpu/drm/i915/intel_sdvo.c
linux-3.14.5/drivers/gpu/drm/i915/intel_sdvo_regs.h
linux-3.14.5/drivers/video/fbcmap.c
linux-3.14.5/include/asm-generic/atomic64.h
linux-3.14.5/include/asm-generic/ioctl.h
linux-3.14.5/include/asm-generic/getorder.h
@ -38,14 +54,18 @@ linux-3.14.5/include/asm-generic/bitops/fls64.h
linux-3.14.5/include/asm-generic/bitops/non-atomic.h
linux-3.14.5/include/linux/agp_backend.h
linux-3.14.5/include/linux/list.h
linux-3.14.5/include/linux/list_sort.h
linux-3.14.5/include/linux/log2.h
linux-3.14.5/include/linux/pci_ids.h
linux-3.14.5/include/linux/hdmi.h
linux-3.14.5/include/linux/i2c-algo-bit.h
linux-3.14.5/include/linux/i2c.h
linux-3.14.5/include/linux/pm_runtime.h
linux-3.14.5/include/drm/intel-gtt.h
linux-3.14.5/include/drm/i915_pciids.h
linux-3.14.5/include/drm/i915_drm.h
linux-3.14.5/include/drm/drm_dp_helper.h
linux-3.14.5/include/drm/drm_fb_helper.h
linux-3.14.5/include/drm/drm_mm.h
linux-3.14.5/include/drm/drm_crtc.h
linux-3.14.5/include/drm/drm_crtc_helper.h
@ -59,5 +79,6 @@ linux-3.14.5/include/uapi/drm/drm_fourcc.h
linux-3.14.5/include/uapi/drm/drm_mode.h
linux-3.14.5/include/uapi/linux/byteorder/little_endian.h
linux-3.14.5/include/uapi/linux/swab.h
linux-3.14.5/include/uapi/linux/fb.h
linux-3.14.5/arch/x86/include/asm/agp.h
linux-3.14.5/lib/list_sort.c

View File

@ -6,20 +6,24 @@ LIBS += intel_fb_include
SRC_C :=
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/char/agp/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/i2c/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/i2c/algos/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/gpu/drm/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/gpu/drm/i915/*.c))
#SRC_C := $(filter-out intel_dp.c,$(SRC_C))
#SRC_C := intel_panel.c
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/video/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/lib/*.c))
#
# Reduce build noise of compiling contrib code
#
CC_WARN = -Wall -Wno-uninitialized -Wno-unused-but-set-variable \
-Wno-unused-variable -Wno-unused-function
-Wno-unused-variable -Wno-unused-function \
-Wno-pointer-arith -Wno-pointer-sign
vpath %.c $(LX_CONTRIB_DIR)/drivers/char/agp
vpath %.c $(LX_CONTRIB_DIR)/drivers/i2c
vpath %.c $(LX_CONTRIB_DIR)/drivers/i2c/algos
vpath %.c $(LX_CONTRIB_DIR)/drivers/gpu/drm/i915
vpath %.c $(LX_CONTRIB_DIR)/drivers/gpu/drm
vpath %.c $(LX_CONTRIB_DIR)/drivers/video
vpath %.c $(LX_CONTRIB_DIR)/lib

View File

@ -0,0 +1,13 @@
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 39eac99..3e67601 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -293,7 +293,7 @@ void intel_fbdev_initial_config(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
/* Due to peculiar init order wrt to hpd handling this is separate. */
- drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
+ drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 16);
}
void intel_fbdev_fini(struct drm_device *dev)

View File

@ -0,0 +1,55 @@
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 2688f6d..ca178a2 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -811,7 +811,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc *intel_crtc = encoder->new_crtc;
struct intel_connector *intel_connector = intel_dp->attached_connector;
int lane_count, clock;
+ int min_lane_count = 1;
int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
+ int min_clock = 0;
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
int bpp, mode_rate;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
@@ -844,19 +846,33 @@ intel_dp_compute_config(struct intel_encoder *encoder,
/* Walk through all bpp values. Luckily they're all nicely spaced with 2
* bpc in between. */
bpp = pipe_config->pipe_bpp;
- if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp &&
- dev_priv->vbt.edp_bpp < bpp) {
- DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
- dev_priv->vbt.edp_bpp);
- bpp = dev_priv->vbt.edp_bpp;
+ if (is_edp(intel_dp)) {
+ if (dev_priv->vbt.edp_bpp && dev_priv->vbt.edp_bpp < bpp) {
+ DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
+ dev_priv->vbt.edp_bpp);
+ bpp = dev_priv->vbt.edp_bpp;
+ }
+
+ if (dev_priv->vbt.edp_lanes) {
+ min_lane_count = min(dev_priv->vbt.edp_lanes,
+ max_lane_count);
+ DRM_DEBUG_KMS("using min %u lanes per VBT\n",
+ min_lane_count);
+ }
+
+ if (dev_priv->vbt.edp_rate) {
+ min_clock = min(dev_priv->vbt.edp_rate >> 3, max_clock);
+ DRM_DEBUG_KMS("using min %02x link bw per VBT\n",
+ bws[min_clock]);
+ }
}
for (; bpp >= 6*3; bpp -= 2*3) {
mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
bpp);
- for (clock = 0; clock <= max_clock; clock++) {
- for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+ for (lane_count = min_lane_count; lane_count <= max_lane_count; lane_count <<= 1) {
+ for (clock = min_clock; clock <= max_clock; clock++) {
link_clock = drm_dp_bw_code_to_link_rate(bws[clock]);
link_avail = intel_dp_max_data_rate(link_clock,
lane_count);

View File

@ -0,0 +1,12 @@
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 98a0363..b00c6b7 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1505,6 +1505,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
modeset->mode = NULL;
}
}
+ update_genode_report();
out:
kfree(crtcs);
kfree(modes);

View File

@ -0,0 +1,29 @@
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 963639d..f926f21 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9867,6 +9867,11 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
config->mode_changed = true;
}
+ /**
+ * Adaption made for Genode context: ensure connector always uses a new fb
+ */
+ config->fb_changed = true;
+
DRM_DEBUG_KMS("computed changes for [CRTC:%d], mode_changed=%d, fb_changed=%d\n",
set->crtc->base.id, config->mode_changed, config->fb_changed);
}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3b7d32d..637f713 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -487,7 +487,7 @@ static void drm_framebuffer_free_bug(struct kref *kref)
static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
{
DRM_DEBUG("FB ID: %d\n", fb->base.id);
- kref_put(&fb->refcount, drm_framebuffer_free_bug);
+ /*kref_put(&fb->refcount, drm_framebuffer_free_bug);*/
}
/* dev->mode_config.fb_lock must be held! */

View File

@ -0,0 +1,15 @@
+++ a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -1034,7 +1034,11 @@
unsigned int num_entries,
bool unused)
{
- intel_gtt_clear_range(first_entry, num_entries);
+ if (!unused)
+ intel_gtt_clear_range(first_entry, num_entries);
+ else
+ /* Fixes DMA issues on Lenovo X201 */
+ printk("Disable %s for Genode\n", __func__);
}

View File

@ -1 +1 @@
630e489f7f95892f1f70144ab363024e01dd7851
e98972035a5cb6cb8651d9ec0f7a30de50713a69

View File

@ -4,9 +4,6 @@ DOWNLOADS := dwc_otg.git usb.archive lxip.archive intel_fb.archive wifi.archiv
libnl.archive wpa_supplicant.archive \
fw_6000.archive fw_6205a.archive fw_6205b.archive fw_7260.archive fw_7265.archive
# XXX disable all parts except for intel_fb
DOWNLOADS := intel_fb.archive
#
# Tools
#
@ -175,7 +172,11 @@ PATCH_OPT(patches/libnl.patch) := -p1 -d ${DIR(libnl)}
# WPA supplicant
PATCH_OPT(patches/wpa_supplicant.patch) := -p1 -d ${DIR(wpa_supplicant)}
# XXX disable all patches of non-intel_fb subsystems
PATCHES :=
# Intel fb
PATCH_OPT(patches/intel_fb_16bit.patch) := -p1 -d ${DIR(intel_fb)}
PATCH_OPT(patches/intel_fb_edp.patch) := -p1 -d ${DIR(intel_fb)}
PATCH_OPT(patches/intel_fb_update.patch) := -p1 -d ${DIR(intel_fb)}
PATCH_OPT(patches/intel_fb_x201.patch) := -p1 -d ${DIR(intel_fb)}
PATCH_OPT(patches/intel_fb_report.patch) := -p1 -d ${DIR(intel_fb)}
# vi: set ft=make :

View File

@ -6,6 +6,8 @@ set build_components {
core init
drivers/timer
drivers/framebuffer/intel
test/framebuffer
server/report_rom
}
source ${genode_dir}/repos/base/run/platform_drv.inc
@ -15,22 +17,12 @@ build $build_components
create_boot_directory
proc platform_drv_policy {} {
return {
<policy label="intel_fb_drv">
<pci class="VGA"/>
<pci bus="0" device="0" function="0"/>
<pci class="ISABRIDGE"/>
</policy>
}
}
#
# Generate config
#
append config {
<config>
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
@ -55,9 +47,21 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="report_rom">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Report" /> <service name="ROM" /> </provides>
<config verbose="yes"> <rom/> </config>
</start>
<start name="intel_fb_drv">
<resource name="RAM" quantum="20M"/>
<provides><service name="Framebuffer"/></provides>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child /> </any-service>
</route>
</start>
<start name="test-framebuffer">
<resource name="RAM" quantum="10M"/>
<provides><service name="Input"/></provides>
</start>
</config>}
@ -70,6 +74,7 @@ install_config $config
# generic modules
set boot_modules {
core init timer intel_fb_drv
test-framebuffer report_rom
}
append_platform_drv_boot_modules

View File

@ -0,0 +1,55 @@
This driver is for Intel i915 compatible graphic cards.
Default behaviour
~~~~~~~~~~~~~~~~~
When no configuration is provided to the driver, it will switch on all devices
the graphic card is initially connected to. It will use the best resolution as
provided by the BIOS or EDID information from the display devices for each
connector. The virtual resolution delivered to the client is the maximum in
width and height of the different connectors. The framebuffer memory is
directly exported to the client of the driver. When newly connected devices are
detected by the hardware, the new connectors are enabled, probed, and again the
'best' resolution will be chosen for the device. Nevertheless, it won't have an
effect on the virtual resolution.
Configuration
~~~~~~~~~~~~~
Each of the connector can be configured explicitly in terms of resolution and
whether it should be enabled or not. This looks like the following:
! <config>
! <connector name="LVDS-11" width="1280" height="800" enabled="true"/>
! </config>
When the configuration changes during run-time, the driver will adapt to it. In
this case it will also change the current virtual resolution to the maximum of
the configured resolutions in width and height, and it will inform its client
about the change in resolution.
It is possible to run the driver in 'buffered' mode, which means it does not
export the framebuffer memory directly to the client, but provides a simple RAM
dataspace instead. The copying from the RAM dataspace to the framebuffer memory
is done by the framebuffer driver when triggered by a refresh operation. This
option can alleviate tearing effects, and has to be enabled via the
configuration like this:
! <config buffered="yes"/>
To present all available connectors and their possible resolutions to the user
the driver is able to export a corresponding report ROM. This has to be
configured too, like in the following:
! <config>
! <report connectors="yes"/>
! </config>
The exported report has the following format:
! <connectors>
! <connector name="LVDS-11" connected="1">
! <mode width="1280" height="800" hz="60"/>
! ...
! </connector>
! ...
! </connectors>

View File

@ -42,41 +42,12 @@ struct timespec ns_to_timespec(const s64 nsec)
return { 0, 0 };
}
void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, char *linebuf, size_t linebuflen, bool ascii)
{
TRACE_AND_STOP;
}
bool mod_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long)
{
TRACE_AND_STOP;
return false;
}
bool capable(int cap)
{
TRACE_AND_STOP;
return false;
}
int drm_dp_bw_code_to_link_rate(u8 link_bw)
{
TRACE_AND_STOP;
return -1;
}
bool intel_fbc_enabled(struct drm_device *dev)
{
TRACE_AND_STOP;
return false;
}
int i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
{
TRACE_AND_STOP;
return -1;
}
int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
@ -101,18 +72,6 @@ int i915_gem_get_tiling(struct drm_device *dev, void *data, struct drm_file *fil
return -1;
}
int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
return -1;
}
int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
return -1;
}
bool flush_delayed_work(struct delayed_work *dwork)
{
TRACE_AND_STOP;
@ -135,5 +94,49 @@ void device_unregister(struct device *dev)
TRACE_AND_STOP;
}
int i2c_algo_bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
TRACE_AND_STOP;
return -1;
}
u32 i2c_algo_bit_func(struct i2c_adapter *adap)
{
TRACE_AND_STOP;
return 0;
}
void i915_setup_sysfs(struct drm_device *dev_priv)
{
TRACE;
}
int acpi_video_register(void)
{
TRACE;
return 0;
}
void ips_link_to_i915_driver(void)
{
TRACE;
}
void spin_lock(spinlock_t *lock)
{
TRACE;
}
void drm_sysfs_hotplug_event(struct drm_device *dev)
{
TRACE;
}
const char *acpi_dev_name(struct acpi_device *)
{
TRACE_AND_STOP;
return 0;
}
} /* extern "C" */

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +0,0 @@
/*
* \brief Definition of the global 'i2c_bit_algo' struct
* \author Norman Feske
* \date 2015-09-11
*
* The 'i2c_bit_algo' struct must be defined in a C file because we cannot
* use C-style struct initializers in C++ code.
*/
#include <lx_emul.h>
int i2c_algo_bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
lx_printf("i2c_algo_bit_xfer called - not implemented\n");
for (;;);
return -1;
}
u32 i2c_algo_bit_func(struct i2c_adapter *adap)
{
lx_printf("i2c_algo_bit_func called - not implemented\n");
return 0;
}
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = i2c_algo_bit_xfer,
.functionality = i2c_algo_bit_func,
};

View File

@ -0,0 +1,157 @@
/*
* \brief Intel framebuffer driver session component
* \author Stefan Kalkowski
* \date 2015-10-16
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef __COMPONENT_H__
#define __COMPONENT_H__
/* Genode includes */
#include <base/rpc_server.h>
#include <root/component.h>
#include <dataspace/capability.h>
#include <framebuffer_session/framebuffer_session.h>
#include <timer_session/connection.h>
#include <util/volatile_object.h>
#include <os/attached_dataspace.h>
#include <os/attached_ram_dataspace.h>
#include <blit/blit.h>
namespace Framebuffer {
class Session_component;
class Root;
extern Root * root;
Genode::Dataspace_capability framebuffer_dataspace();
}
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
private:
template <typename T> using Lazy = Genode::Lazy_volatile_object<T>;
int _height;
int _width;
Genode::Signal_context_capability _mode_sigh;
Timer::Connection _timer;
bool const _buffered;
Lazy<Genode::Attached_dataspace> _fb_ds;
Lazy<Genode::Attached_ram_dataspace> _bb_ds;
bool _in_update = false;
static constexpr unsigned _bytes_per_pixel = 2;
void _refresh_buffered(int x, int y, int w, int h)
{
using namespace Genode;
/* clip specified coordinates against screen boundaries */
int x2 = min(x + w - 1, (int)_width - 1),
y2 = min(y + h - 1, (int)_height - 1);
int x1 = max(x, 0),
y1 = max(y, 0);
if (x1 > x2 || y1 > y2) return;
int const bpp = _bytes_per_pixel;
/* copy pixels from back buffer to physical frame buffer */
char *src = _bb_ds->local_addr<char>() + bpp*(_width*y1 + x1),
*dst = _fb_ds->local_addr<char>() + bpp*(_width*y1 + x1);
blit(src, bpp*_width, dst, bpp*_width,
bpp*(x2 - x1 + 1), y2 - y1 + 1);
}
public:
Session_component(bool buffered)
: _height(0), _width(0), _buffered(buffered) {}
void update(int height, int width)
{
_in_update = true;
_height = height;
_width = width;
if (_mode_sigh.valid())
Genode::Signal_transmitter(_mode_sigh).submit();
}
/***********************************
** Framebuffer session interface **
***********************************/
Genode::Dataspace_capability dataspace() override
{
_in_update = false;
if (_fb_ds.is_constructed())
_fb_ds.destruct();
_fb_ds.construct(framebuffer_dataspace());
if (!_fb_ds.is_constructed())
PERR("framebuffer dataspace not initialized");
if (_buffered) {
_bb_ds.construct(Genode::env()->ram_session(),
_width * _height * _bytes_per_pixel);
if (!_bb_ds.is_constructed()) {
PERR("buffered mode enabled, but buffer not initialized");
return Genode::Dataspace_capability();
}
return _bb_ds->cap();
}
return _fb_ds->cap();
}
Mode mode() const override {
return Mode(_width, _height, Mode::RGB565); }
void mode_sigh(Genode::Signal_context_capability sigh) override {
_mode_sigh = sigh; }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_timer.sigh(sigh);
_timer.trigger_periodic(10*1000);
}
void refresh(int x, int y, int w, int h) override {
if (_buffered && !_in_update) _refresh_buffered(x, y, w, h); }
};
class Framebuffer::Root
: public Genode::Root_component<Framebuffer::Session_component,
Genode::Single_client>
{
private:
Session_component _single_session;
Session_component *_create_session(const char *args) override {
return &_single_session; }
public:
Root(Genode::Rpc_entrypoint *session_ep, Genode::Allocator *md_alloc,
bool buffered)
: Genode::Root_component<Session_component,
Genode::Single_client>(session_ep, md_alloc),
_single_session(buffered) { }
void update(int height, int width) {
_single_session.update(height, width); }
};
#endif /* __COMPONENT_H__ */

View File

@ -111,7 +111,7 @@ enum { DRM_CALLED_FROM_VBLIRQ = 1 };
///*
// * Debug macros
// */
#define DRM_VERBOSE 1
#define DRM_VERBOSE 0
#if DRM_VERBOSE
#define DRM_INFO(fmt, arg...) do { \
@ -158,6 +158,7 @@ struct drm_display_mode;
struct drm_connector;
struct drm_mode_create_dumb;
struct drm_mode_fb_cmd2;
struct drm_cmdline_mode;
/**
@ -286,6 +287,10 @@ struct drm_driver {
struct drm_i915_private;
struct drm_vblank_crtc {
u32 last;
};
struct drm_device {
// int pci_device;
struct pci_dev *pdev;
@ -316,6 +321,9 @@ struct drm_device {
int switch_power_state;
spinlock_t event_lock;
struct device *dev; /* i915_gem_stolen.c */
struct drm_vblank_crtc *vblank; /* needed by intel_pm.c */
spinlock_t vbl_lock; /* needed by intel_pm.c */
struct timer_list vblank_disable_timer;
};
//
@ -424,6 +432,9 @@ struct drm_file {
int event_space;
};
//
#define DRM_MINOR_LEGACY 1
///*
// * needed for drm_agpsupport.c
// */
@ -467,9 +478,6 @@ struct drm_minor {
struct drm_pending_vblank_event;
struct drm_fb_helper { int dummy; };
#include <drm/drm_dp_helper.h>
@ -494,6 +502,26 @@ struct drm_pending_vblank_event {
};
/***************************
** drm/drm_crtc_helper.h **
***************************/
struct drm_cmdline_mode
{
bool specified;
bool refresh_specified;
bool bpp_specified;
int xres, yres;
int bpp;
int refresh;
bool rb;
bool interlace;
bool cvt;
bool margins;
enum drm_connector_force force;
};
/******************
** Misc helpers **
******************/
@ -674,8 +702,9 @@ extern const char *drm_get_connector_status_name(enum drm_connector_status statu
extern void drm_kms_helper_hotplug_event(struct drm_device *dev);
extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
extern void drm_gem_private_object_init(struct drm_device *dev, struct drm_gem_object *obj, size_t size);
extern void drm_sysfs_hotplug_event(struct drm_device *dev);
extern bool drm_mode_parse_command_line_for_connector(const char *mode_option, struct drm_connector *connector, struct drm_cmdline_mode *mode);
extern struct drm_display_mode * drm_mode_create_from_cmdline_mode(struct drm_device *dev, struct drm_cmdline_mode *cmd);
#ifdef __cplusplus
}

View File

@ -22,6 +22,7 @@
enum { HZ = 100UL };
#define DEBUG_LINUX_PRINTK 1
#include <lx_emul/compiler.h>
#include <lx_emul/printf.h>
@ -36,6 +37,7 @@ void atomic_set_mask(unsigned int mask, atomic_t *v);
#include <lx_emul/types.h>
typedef unsigned long kernel_ulong_t;
typedef unsigned int u_int;
/************************
@ -61,6 +63,8 @@ void print_hex_dump(const char *level, const char *prefix_str,
int prefix_type, int rowsize, int groupsize,
const void *buf, size_t len, bool ascii);
#define printk_once(fmt, ...) ({})
/*********************
** uapi/linux/fb.h **
@ -89,7 +93,6 @@ void print_hex_dump(const char *level, const char *prefix_str,
#define PAGE_SIZE 4096UL
#define PAGE_MASK (~(PAGE_SIZE-1))
dma_addr_t page_to_phys(void *page);
enum {
PAGE_SHIFT = 12,
@ -100,19 +103,31 @@ struct page
// unsigned long flags;
// int pfmemalloc;
// int mapping;
atomic_t _count;
void *addr;
unsigned long private;
atomic_t _count;
void *addr;
dma_addr_t paddr;
} __attribute((packed));
/* needed for agp/generic.c */
struct page *virt_to_page(void *addr);
dma_addr_t page_to_phys(struct page *page);
#include <lx_emul/bitops.h>
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size);
#define __const_hweight8(w) \
( (!!((w) & (1ULL << 0))) + \
(!!((w) & (1ULL << 1))) + \
(!!((w) & (1ULL << 2))) + \
(!!((w) & (1ULL << 3))) + \
(!!((w) & (1ULL << 4))) + \
(!!((w) & (1ULL << 5))) + \
(!!((w) & (1ULL << 6))) + \
(!!((w) & (1ULL << 7))) )
#define hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8 ))
#include <asm-generic/getorder.h>
@ -128,14 +143,15 @@ void *memchr_inv(const void *s, int c, size_t n);
#include <lx_emul/list.h>
#include <lx_emul/kernel.h>
extern long simple_strtol(const char *,char **,unsigned int);
typedef __kernel_time_t time_t;
extern int oops_in_progress;
#define pr_debug(fmt, ...) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn(fmt, ...) printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
#define pr_info(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
#define pr_err(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__)
#define pr_warn(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__)
#define pr_info_once(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
int sprintf(char *buf, const char *fmt, ...);
@ -151,6 +167,18 @@ enum { SPRINTF_STR_LEN = 64 };
buf; \
})
#define DIV_ROUND_UP_ULL(ll,d) \
({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; })
#define mult_frac(x, numer, denom) ({ \
typeof(x) quot = (x) / (denom); \
typeof(x) rem = (x) % (denom); \
(quot * (numer)) + ((rem * (numer)) / (denom)); \
})
extern int panic_timeout;
extern struct atomic_notifier_head panic_notifier_list;
/* linux/i2c.h */
#define __deprecated
@ -182,6 +210,9 @@ extern void hex_dump_to_buffer(const void *buf, size_t len,
/* i2c-core.c */
#define postcore_initcall(fn) void postcore_##fn(void) { fn(); }
#define symbol_get(x) ({ extern typeof(x) x __attribute__((weak)); &(x); })
#define symbol_put(x) do { } while (0)
/**************************
** linux/preempt_mask.h **
@ -231,13 +262,11 @@ void mutex_lock_nest_lock(struct mutex *, struct mutex *);
** linux/rtmutex.h **
*********************/
struct rt_mutex { int dummy; };
void rt_mutex_lock(struct rt_mutex *lock);
int rt_mutex_trylock(struct rt_mutex *lock);
void rt_mutex_unlock(struct rt_mutex *lock);
#define rt_mutex_init(mutex)
#define rt_mutex mutex
#define rt_mutex_init(m) mutex_init(m)
#define rt_mutex_lock(m) mutex_lock(m)
#define rt_mutex_trylock(m) mutex_trylock(m)
#define rt_mutex_unlock(m) mutex_unlock(m)
/******************
@ -305,6 +334,8 @@ int on_each_cpu(void (*func) (void *info), void *info, int wait);
/* normally defined in asm/current.h, included by sched.h */
extern struct task_struct *current;
void yield(void);
/************************
** linux/completion.h **
@ -315,6 +346,7 @@ struct completion { unsigned done; };
void __wait_completion(struct completion *work);
void complete(struct completion *); /* i2c-core.c */
void init_completion(struct completion *x);
void wait_for_completion(struct completion *);
/*********************
@ -744,6 +776,13 @@ enum {
#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
enum rpm_status {
RPM_ACTIVE = 0,
RPM_RESUMING,
RPM_SUSPENDED,
RPM_SUSPENDING,
};
/********************
** linux/device.h **
@ -885,6 +924,8 @@ void iounmap(volatile void *addr);
void __iomem *ioremap(phys_addr_t offset, unsigned long size);
#define mmiowb() barrier()
/**
* Map I/O memory write combined
*/
@ -892,13 +933,15 @@ void *ioremap_wc(resource_size_t phys_addr, unsigned long size);
#define ioremap_nocache ioremap_wc
void *memset_io(void *s, int c, size_t n);
int arch_phys_wc_add(unsigned long base, unsigned long size);
static inline void arch_phys_wc_del(int handle) { }
phys_addr_t virt_to_phys(volatile void *address);
void memset_io(void *s, int c, size_t n);
void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count);
void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count);
/*********************
** linux/uaccess.h **
@ -942,6 +985,9 @@ void io_mapping_unmap_atomic(void *vaddr);
struct io_mapping *io_mapping_create_wc(resource_size_t base, unsigned long size);
void io_mapping_free(struct io_mapping *mapping);
void __iomem * io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset);
void io_mapping_unmap(void __iomem *vaddr);
#include <lx_emul/mmio.h>
@ -958,14 +1004,6 @@ int request_resource(struct resource *root, struct resource *); /* intel-gtt.c *
int release_resource(struct resource *r); /* i915_dma.c */
/************************
** linux/pm_runtime.h **
************************/
int pm_generic_runtime_suspend(struct device *dev);
int pm_generic_runtime_resume(struct device *dev);
/*****************
** linux/pci.h **
*****************/
@ -1045,6 +1083,9 @@ static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
struct pci_dev *pci_dev_get(struct pci_dev *dev);
void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
/**********************************
** asm-generic/pci-dma-compat.h **
@ -1081,63 +1122,6 @@ bool capable(int cap);
#define CAP_SYS_ADMIN 21
/******************
** linux/hdmi.h **
******************/
#define HDMI_IEEE_OUI 0x000c03
enum hdmi_infoframe_type { HDMI_INFOFRAME_TYPE_DUMMY };
enum hdmi_picture_aspect {
HDMI_PICTURE_ASPECT_NONE,
HDMI_PICTURE_ASPECT_4_3,
HDMI_PICTURE_ASPECT_16_9,
};
enum hdmi_active_aspect {
HDMI_ACTIVE_ASPECT_16_9_TOP = 2,
HDMI_ACTIVE_ASPECT_14_9_TOP = 3,
HDMI_ACTIVE_ASPECT_16_9_CENTER = 4,
HDMI_ACTIVE_ASPECT_PICTURE = 8,
HDMI_ACTIVE_ASPECT_4_3 = 9,
HDMI_ACTIVE_ASPECT_16_9 = 10,
HDMI_ACTIVE_ASPECT_14_9 = 11,
HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13,
HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14,
HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15,
};
enum hdmi_3d_structure {
HDMI_3D_STRUCTURE_INVALID = -1,
HDMI_3D_STRUCTURE_FRAME_PACKING = 0,
HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE,
HDMI_3D_STRUCTURE_LINE_ALTERNATIVE,
HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL,
HDMI_3D_STRUCTURE_L_DEPTH,
HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH,
HDMI_3D_STRUCTURE_TOP_AND_BOTTOM,
HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8,
};
struct hdmi_avi_infoframe {
int dummy;
enum hdmi_picture_aspect picture_aspect;
enum hdmi_active_aspect active_aspect;
unsigned char video_code;
unsigned char pixel_repeat;
};
struct hdmi_vendor_infoframe {
enum hdmi_infoframe_type type;
u8 vic;
enum hdmi_3d_structure s3d_struct;
};
int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
/*************************
** linux/agp_backend.h **
*************************/
@ -1183,6 +1167,11 @@ struct notifier_block { notifier_fn_t notifier_call; };
enum { NOTIFY_OK = 0x0001 };
struct atomic_notifier_head { unsigned dummy; };
extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *nb);
extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *nb);
/*******************
** acpi/button.h **
@ -1242,11 +1231,6 @@ void console_unlock(void);
int console_trylock(void);
/****************
** linux/fb.h **
****************/
enum { FBINFO_STATE_RUNNING = 0, FBINFO_STATE_SUSPENDED = 1 };
/****************
@ -1452,6 +1436,165 @@ void gpio_free(unsigned gpio);
bool gpio_is_valid(int number);
/* needed by drivers/gpu/drm/drm_modes.c */
#include <linux/list_sort.h>
/*********************
** linux/cpufreq.h **
*********************/
struct cpufreq_cpuinfo {
unsigned int max_freq;
unsigned int min_freq;
};
struct cpufreq_policy {
struct cpufreq_cpuinfo cpuinfo;
};
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
void cpufreq_cpu_put(struct cpufreq_policy *policy);
/********************************
** arch/x86/include/asm/tsc.h **
********************************/
extern unsigned int tsc_khz;
/**************************************
** drivers/platform/x86/intel_ips.h **
**************************************/
void ips_link_to_i915_driver(void);
/******************
** linux/kgdb.h **
******************/
#define in_dbg_master() (0)
/*************************
** asm-generic/div64.h **
*************************/
#define do_div(n,base) ({ \
unsigned long __base = (base); \
unsigned long __rem; \
__rem = ((uint64_t)(n)) % __base; \
(n) = ((uint64_t)(n)) / __base; \
__rem; \
})
/**************************************
** definitions needed by intel_pm.c **
**************************************/
void trace_intel_gpu_freq_change(int);
/****************
** linux/fb.h **
****************/
#include <uapi/linux/fb.h>
enum {
FBINFO_STATE_RUNNING = 0,
FBINFO_STATE_SUSPENDED = 1,
FBINFO_CAN_FORCE_OUTPUT = 0x200000,
FBINFO_DEFAULT = 0,
};
struct fb_cmap_user {
__u32 start;
__u32 len;
__u16 __user *red;
__u16 __user *green;
__u16 __user *blue;
__u16 __user *transp;
};
struct aperture {
resource_size_t base;
resource_size_t size;
};
struct apertures_struct {
unsigned int count;
struct aperture ranges[0];
};
struct fb_info {
int node;
int flags;
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_cmap cmap;
struct fb_ops *fbops;
char __iomem *screen_base;
unsigned long screen_size;
void *pseudo_palette;
void * par;
struct apertures_struct *apertures;
bool skip_vt_switch;
};
struct fb_ops {
struct module *owner;
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
int (*fb_set_par)(struct fb_info *info);
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
int (*fb_blank)(int blank, struct fb_info *info);
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
int (*fb_debug_enter)(struct fb_info *info);
int (*fb_debug_leave)(struct fb_info *info);
};
extern int fb_get_options(const char *name, char **option);
extern int register_framebuffer(struct fb_info *fb_info);
extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
extern struct apertures_struct *alloc_apertures(unsigned int max_num);
extern int unregister_framebuffer(struct fb_info *fb_info);
extern void fb_dealloc_cmap(struct fb_cmap *cmap);
extern void framebuffer_release(struct fb_info *info);
extern void fb_set_suspend(struct fb_info *info, int state);
extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to);
extern const struct fb_cmap *fb_default_cmap(int len);
extern int lock_fb_info(struct fb_info *info);
extern void unlock_fb_info(struct fb_info *info);
/***************************
** linux vgaswitcheroo.h **
***************************/
void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info);
/*******************
** linux/sysrq.h **
*******************/
struct sysrq_key_op { unsigned dummy; };
int register_sysrq_key(int key, struct sysrq_key_op *op);
int unregister_sysrq_key(int key, struct sysrq_key_op *op);
/*******************
** Configuration **
*******************/
@ -1459,6 +1602,9 @@ bool gpio_is_valid(int number);
/* evaluated in i915_drv.c */
enum { CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT = 1 };
#define CONFIG_DRM_I915_FBDEV 1
void update_genode_report();
/**************************
** Dummy trace funtions **
@ -1485,7 +1631,6 @@ enum { CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT = 1 };
#define trace_i915_reg_rw(...)
#define trace_i915_gem_request_complete(...)
#include <lx_emul/extern_c_end.h>
#endif /* _LX_EMUL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -14,10 +14,14 @@
/* Linux kernel API */
#include <lx_emul.h>
#if 0
#define TRACE \
do { \
PLOG("%s not implemented", __func__); \
} while (0)
#else
#define TRACE do { ; } while (0)
#endif
#define TRACE_AND_STOP \
do { \
@ -25,4 +29,12 @@
Genode::sleep_forever(); \
} while (0)
#define ASSERT(x) \
do { \
if (!(x)) { \
PWRN("%s:%u assertion failed", __func__, __LINE__); \
Genode::sleep_forever(); \
} \
} while (0)
#endif /* _LX_EMUL_PRIVATE_H_ */

View File

@ -14,11 +14,15 @@
/* Genode includes */
#include <base/printf.h>
#include <os/server.h>
#include <os/config.h>
#include <component.h>
/* Linux emulation environment includes */
#include <lx_emul.h>
#include <lx_emul/impl/internal/scheduler.h>
#include <lx_emul/impl/internal/timer.h>
#include <lx_emul/impl/internal/irq.h>
#include <lx_emul/impl/internal/pci_dev_registry.h>
#include <lx_emul/impl/internal/pci_backend_alloc.h>
@ -39,6 +43,13 @@ Lx::Timer & Lx::timer(Server::Entrypoint *ep, unsigned long *jiffies)
}
Lx::Irq & Lx::Irq::irq(Server::Entrypoint *ep)
{
static Lx::Irq irq(*ep);
return irq;
}
Platform::Connection *Lx::pci()
{
static Platform::Connection _pci;
@ -58,23 +69,15 @@ namespace Lx {
};
Framebuffer::Root * Framebuffer::root = nullptr;
extern "C" int postcore_i2c_init(); /* i2c-core.c */
extern "C" int module_i915_init(); /* i915_drv.c */
extern "C" void update_framebuffer_config();
static void run_linux(void *)
{
PDBG("postcore_i915_init");
postcore_i2c_init();
PDBG("module_i915_init");
module_i915_init();
while (1) {
Lx::scheduler().current()->block_and_schedule();
}
}
static void run_linux(void * m);
unsigned long jiffies;
@ -83,25 +86,74 @@ struct Server::Main
{
Entrypoint &ep;
bool _buffered_from_config()
{
try {
config()->reload();
return Genode::config()->xml_node().attribute_value("buffered",
false);
} catch (...) { return false; }
}
Framebuffer::Root root_component { &ep.rpc_ep(), Genode::env()->heap(),
_buffered_from_config() };
/* init singleton Lx::Timer */
Lx::Timer &timer = Lx::timer(&ep, &jiffies);
/* init singleton Lx::Irq */
Lx::Irq &irq = Lx::Irq::irq(&ep);
/* Linux task that handles the initialization */
Lx::Task linux { run_linux, nullptr, "linux",
Lx::Task linux { run_linux, reinterpret_cast<void*>(this), "linux",
Lx::Task::PRIORITY_0, Lx::scheduler() };
Main(Entrypoint &ep) : ep(ep)
{
Genode::printf("--- intel framebuffer driver ---\n");
Framebuffer::root = &root_component;
/* give all task a first kick before returning */
Lx::scheduler().schedule();
PDBG("returning from main");
}
};
struct Policy_agent
{
Server::Main &main;
Genode::Signal_rpc_member<Policy_agent> sd;
void handle(unsigned)
{
main.linux.unblock();
Lx::scheduler().schedule();
}
Policy_agent(Server::Main &m)
: main(m), sd(main.ep, *this, &Policy_agent::handle) {}
};
static void run_linux(void * m)
{
Server::Main * main = reinterpret_cast<Server::Main*>(m);
postcore_i2c_init();
module_i915_init();
Genode::env()->parent()->announce(main->ep.manage(*Framebuffer::root));
static Policy_agent pa(*main);
Genode::config()->sigh(pa.sd);
while (1) {
Lx::scheduler().current()->block_and_schedule();
update_framebuffer_config();
}
}
namespace Server {
char const *name() { return "intel_fb_ep"; }

View File

@ -1,5 +1,6 @@
REQUIRES = x86
TARGET = intel_fb_drv
LIBS = base intel_fb_drv intel_fb_include libc-setjmp server
LIBS = base intel_fb_drv intel_fb_include libc-setjmp server config blit
SRC_CC = main.cc lx_emul.cc dummies.cc
SRC_C = i2c-algo-bit.c
INC_DIR += $(REP_DIR)/src/include

View File

@ -14,6 +14,8 @@
/* Genode includes */
#include <timer_session/connection.h>
#include <lx_emul/impl/internal/timer.h>
/*
* XXX We may consider to use the Lx::Timer instead of opening a dedicated
* timer session.
@ -24,7 +26,11 @@ static Timer::Connection _delay_timer;
void udelay(unsigned long usecs) { _delay_timer.usleep(usecs); }
void msleep(unsigned int msecs) { _delay_timer.msleep(msecs); }
void msleep(unsigned int msecs)
{
_delay_timer.msleep(msecs);
Lx::timer_update_jiffies();
}
void mdelay(unsigned long msecs) { msleep(msecs); }

View File

@ -17,11 +17,13 @@
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
struct page *page = (struct page *)kzalloc(sizeof(struct page) * 1<<order, 0);
size_t size = PAGE_SIZE << order;
page->addr = Lx::Malloc::dma().alloc(size, 12);
Genode::Ram_dataspace_capability ds_cap = Lx::backend_alloc(size, Genode::UNCACHED);
page->addr = Genode::env()->rm_session()->attach(ds_cap);
page->paddr = Genode::Dataspace_client(ds_cap).phys_addr();
if (!page->addr) {
PERR("alloc_pages: %zu failed", size);
@ -31,7 +33,11 @@ struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
Lx::Addr_to_page_mapping::insert(page);
atomic_set(&page->_count, 1);
for (unsigned i = 0; i < 1UL<<order; i++) {
page[i].addr = (void*)((Genode::addr_t)page->addr + i*PAGE_SIZE);
page[i].paddr = page->paddr + i*PAGE_SIZE;
atomic_set(&page[i]._count, 1);
}
return page;
}

View File

@ -0,0 +1,213 @@
/*
* \brief Signal context for IRQ's
* \author Josef Soentgen
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2014-10-14
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__IRQ_H_
#define _LX_EMUL__IMPL__INTERNAL__IRQ_H_
/* Genode includes */
#include <base/tslab.h>
#include <irq_session/client.h>
#include <platform_device/client.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
namespace Lx { class Irq; }
class Lx::Irq
{
private:
/**
* Helper utilty for composing IRQ related names
*/
struct Name_composer
{
char name[16];
Name_composer(Platform::Device &device)
{
Genode::snprintf(name, sizeof(name),
"irq_%02x:%02x",
device.vendor_id(),
device.device_id());
}
};
/**
* This contains the Linux-driver handlers
*/
class Handler : public Lx::List<Handler>::Element
{
private:
void *_dev; /* Linux device */
irq_handler_t _handler; /* Linux handler */
irq_handler_t _thread_fn; /* Linux thread function */
public:
Handler(void *dev, irq_handler_t handler,
irq_handler_t thread_fn)
: _dev(dev), _handler(handler), _thread_fn(thread_fn) { }
bool handle()
{
switch (_handler(0, _dev)) {
case IRQ_WAKE_THREAD:
_thread_fn(0, _dev);
case IRQ_HANDLED:
return true;
case IRQ_NONE:
break;
}
return false;
}
};
public:
/**
* Context encapsulates the handling of an IRQ
*/
class Context : public Lx::List<Context>::Element
{
private:
Name_composer _name;
Platform::Device &_dev;
Genode::Irq_session_client _irq_sess;
Lx::List<Handler> _handler; /* List of registered handlers */
Lx::Task _task;
Genode::Signal_rpc_member<Context> _dispatcher;
/**
* Signal handler
*/
void _handle(unsigned)
{
_task.unblock();
/* kick off scheduling */
Lx::scheduler().schedule();
}
static void _run_irq(void *args)
{
Context *ctx = static_cast<Context*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
ctx->handle_irq();
}
}
public:
/**
* Constructor
*/
Context(Server::Entrypoint &ep,
Platform::Device &dev)
:
_name(dev),
_dev(dev),
_irq_sess(dev.irq(0)),
_task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()),
_dispatcher(ep, *this, &Context::_handle)
{
_irq_sess.sigh(_dispatcher);
/* initial ack to receive further IRQ signals */
_irq_sess.ack_irq();
}
/**
* Handle IRQ
*/
void handle_irq()
{
bool handled = false;
/* report IRQ to all clients */
for (Handler *h = _handler.first(); h; h = h->next()) {
if ((handled = h->handle())) break;
}
_irq_sess.ack_irq();
}
/**
* Add linux handler to context
*/
void add_handler(Handler *h) { _handler.append(h); }
bool device(Platform::Device &dev) {
return (&dev == &_dev); }
};
private:
using Context_slab = Genode::Tslab<Context, 3 * sizeof(Context)>;
using Handler_slab = Genode::Tslab<Handler, 3 * sizeof(Handler)>;
Server::Entrypoint &_ep;
Lx::List<Context> _list;
Context_slab _context_alloc;
Handler_slab _handler_alloc;
/**
* Find context for given device
*/
Context *_find_context(Platform::Device &dev)
{
for (Context *i = _list.first(); i; i = i->next())
if (i->device(dev)) return i;
return nullptr;
}
Irq(Server::Entrypoint &ep)
: _ep(ep),
_context_alloc(Genode::env()->heap()),
_handler_alloc(Genode::env()->heap()) { }
public:
static Irq &irq(Server::Entrypoint *ep = nullptr);
/**
* Request an IRQ
*/
void request_irq(Platform::Device &dev, irq_handler_t handler,
void *dev_id, irq_handler_t thread_fn = 0)
{
Context *ctx = _find_context(dev);
/* if this IRQ is not registered */
if (!ctx) {
ctx = new (&_context_alloc) Context(_ep, dev);
_list.insert(ctx);
}
/* register Linux handler */
Handler *h = new (&_handler_alloc)
Handler(dev_id, handler, thread_fn);
ctx->add_handler(h);
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__IRQ_H_ */

View File

@ -119,7 +119,7 @@ class Lx::Malloc
msb = SLAB_STOP_LOG2;
if (msb > SLAB_STOP_LOG2) {
// PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached);
PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached);
return 0;
}

View File

@ -26,6 +26,8 @@ namespace Lx {
class Mapped_io_mem_range;
void *ioremap(resource_size_t, unsigned long, Genode::Cache_attribute);
void iounmap(volatile void*);
Genode::Dataspace_capability ioremap_lookup(Genode::addr_t, Genode::size_t);
}
/**
@ -37,47 +39,58 @@ class Lx::Mapped_io_mem_range : public Lx::List<Mapped_io_mem_range>::Element
{
private:
Genode::Attached_dataspace _ds;
Genode::size_t const _size;
Genode::addr_t const _phys;
Genode::addr_t const _virt;
Genode::size_t const _size;
Genode::addr_t const _phys;
Genode::Rm_connection _rm;
Genode::Attached_dataspace _ds;
Genode::addr_t const _virt;
public:
Mapped_io_mem_range(Genode::addr_t phys, Genode::size_t size,
Genode::Io_mem_dataspace_capability ds_cap)
:
_ds(ds_cap),
_size(size),
_phys(phys),
_virt((Genode::addr_t)_ds.local_addr<void>() | (phys & 0xfffUL))
{ }
Genode::Io_mem_dataspace_capability ds_cap,
Genode::addr_t offset)
: _size(size),
_phys(phys),
_rm(0, size),
_ds(_rm.dataspace()),
_virt((Genode::addr_t)_ds.local_addr<void>() | (phys &0xfffUL)) {
_rm.attach_at(ds_cap, 0, size, offset); }
Genode::addr_t phys() const { return _phys; }
Genode::addr_t virt() const { return _virt; }
Genode::Dataspace_capability cap() const { return _ds.cap(); }
/**
* Return true if the mapped range contains the specified sub range
*/
bool contains(Genode::addr_t phys, Genode::size_t size) const
bool phys_range(Genode::addr_t phys, Genode::size_t size) const
{
return (phys >= _phys) && (phys + size - 1 <= _phys + _size - 1);
}
/**
* Return true if the mapped range contains the specified sub range
*/
bool virt_range(Genode::addr_t virt, Genode::size_t size) const
{
return (virt >= _virt) && (virt + size - 1 <= _virt + _size - 1);
}
};
static Lx::List<Lx::Mapped_io_mem_range> ranges;
void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
Genode::Cache_attribute cache_attribute)
{
using namespace Genode;
static Lx::List<Lx::Mapped_io_mem_range> ranges;
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->contains(phys_addr, size)) {
if (r->phys_range(phys_addr, size)) {
void * const virt = (void *)(r->virt() + phys_addr - r->phys());
PLOG("ioremap: return sub range phys 0x%lx (size %lx) to virt 0x%lx",
(long)phys_addr, (long)size, (long)virt);
@ -85,20 +98,20 @@ void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
}
}
addr_t offset;
Io_mem_dataspace_capability ds_cap =
Lx::pci_dev_registry()->io_mem(phys_addr, cache_attribute, size);
Lx::pci_dev_registry()->io_mem(phys_addr, cache_attribute,
size, offset);
if (!ds_cap.valid()) {
PERR("Failed to request I/O memory: [%zx,%lx)", phys_addr,
phys_addr + size);
return nullptr;
}
Genode::size_t const ds_size = Genode::Dataspace_client(ds_cap).size();
Lx::Mapped_io_mem_range *io_mem =
new (env()->heap()) Lx::Mapped_io_mem_range(phys_addr, ds_size, ds_cap);
new (env()->heap()) Lx::Mapped_io_mem_range(phys_addr, size,
ds_cap, offset);
ranges.insert(io_mem);
@ -109,4 +122,30 @@ void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
return (void *)(io_mem->virt() + sub_page_offset);
}
void Lx::iounmap(volatile void * virt)
{
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->virt() == (addr_t)virt) {
ranges.remove(r);
destroy(env()->heap(), r);
return;
}
}
}
Genode::Dataspace_capability
Lx::ioremap_lookup(Genode::addr_t virt_addr, Genode::size_t size)
{
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next())
if (r->virt_range(virt_addr, size))
return r->cap();
return Genode::Dataspace_capability();
}
#endif /* _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_ */

View File

@ -78,12 +78,17 @@ Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached)
cap = env()->ram_session()->alloc(size);
o = new (env()->heap()) Ram_object(cap);
} else {
/* transfer quota to pci driver, otherwise it will give us a exception */
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", size);
Genode::env()->parent()->upgrade(Lx::pci()->cap(), buf);
size_t donate = size;
cap = retry<Platform::Session::Out_of_metadata>(
[&] () { return Lx::pci()->alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(Lx::pci()->cap(), quota);
donate = donate * 2 > size ? 4096 : donate * 2;
});
cap = Lx::pci()->alloc_dma_buffer(size);
o = new (env()->heap()) Dma_object(cap);
}
@ -96,13 +101,16 @@ void Lx::backend_free(Genode::Ram_dataspace_capability cap)
{
using namespace Genode;
Memory_object_base *o = memory_pool.lookup_and_lock(cap);
if (!o)
return;
Memory_object_base *object;
memory_pool.apply(cap, [&] (Memory_object_base *o) {
object = o;
if (!object)
return;
o->free();
memory_pool.remove_locked(o);
destroy(env()->heap(), o);
object->free();
memory_pool.remove(object);
});
destroy(env()->heap(), object);
}

View File

@ -54,6 +54,7 @@ class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
Platform::Device_client _client;
Io_port _io_port;
Genode::Io_mem_session_capability _io_mem[DEVICE_COUNT_RESOURCE];
/* offset used in PCI config space */
enum Pci_config { IRQ = 0x3c, REV = 0x8, CMD = 0x4,
@ -143,7 +144,7 @@ class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
/* enable bus master */
cmd |= 0x4;
_client.config_write(CMD, cmd, Device::ACCESS_16BIT);
config_write(CMD, cmd);
/* get pci express capability */
this->pcie_cap = 0;
@ -178,12 +179,34 @@ class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
template <typename T>
void config_write(unsigned int devfn, T val)
{
_client.config_write(devfn, val, _access_size(val));
Genode::size_t donate = 4096;
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { _client.config_write(devfn, val, _access_size(val)); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(pci()->cap(), quota);
donate *= 2;
});
}
Platform::Device &client() { return _client; }
Io_port &io_port() { return _io_port; }
Genode::Io_mem_session_capability io_mem(unsigned bar,
Genode::Cache_attribute cache_attribute)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return Genode::Io_mem_session_capability();
if (!_io_mem[bar].valid())
_io_mem[bar] = _client.io_mem(_client.phys_bar_to_virt(bar),
cache_attribute);
return _io_mem[bar];
}
};
@ -200,7 +223,7 @@ void Lx::for_each_pci_device(FUNC const &func)
{
/*
* Functor that is called if the platform driver throws a
* 'Quota_exceeded' exception.
* 'Out_of_metadata' exception.
*/
auto handler = [&] () {
Genode::env()->parent()->upgrade(Lx::pci()->cap(),
@ -212,7 +235,7 @@ void Lx::for_each_pci_device(FUNC const &func)
*/
Platform::Device_capability cap;
auto attempt = [&] () { cap = Lx::pci()->first_device(); };
Genode::retry<Platform::Device::Quota_exceeded>(attempt, handler);
Genode::retry<Platform::Session::Out_of_metadata>(attempt, handler);
/*
* Iterate over the devices of the platform session.
@ -234,7 +257,7 @@ void Lx::for_each_pci_device(FUNC const &func)
Lx::pci()->release_device(cap);
cap = next_cap;
};
Genode::retry<Platform::Device::Quota_exceeded>(attempt, handler);
Genode::retry<Platform::Session::Out_of_metadata>(attempt, handler);
}
}

View File

@ -29,6 +29,7 @@ namespace Lx {
Pci_dev_registry *pci_dev_registry();
}
class Lx::Pci_dev_registry
{
private:
@ -45,7 +46,8 @@ class Lx::Pci_dev_registry
Genode::Io_mem_dataspace_capability io_mem(resource_size_t phys,
Genode::Cache_attribute cache_attribute,
Genode::size_t size)
Genode::size_t size,
Genode::addr_t &offset)
{
enum { PCI_ROM_RESOURCE = 6 };
@ -54,23 +56,18 @@ class Lx::Pci_dev_registry
unsigned bar = 0;
for (; bar < PCI_ROM_RESOURCE; bar++) {
if ((pci_resource_flags(d, bar) & IORESOURCE_MEM) &&
(pci_resource_start(d, bar) == phys))
(pci_resource_start(d, bar) <= phys) &&
(pci_resource_end(d, bar) >= (phys+size-1)))
break;
}
if (bar >= PCI_ROM_RESOURCE)
continue;
Platform::Device &device = d->client();
unsigned const resource_id =
device.phys_bar_to_virt(bar);
/* offset from the beginning of the PCI resource */
Genode::addr_t const offset =
phys - pci_resource_start(d, bar);
offset = phys - pci_resource_start(d, bar);
Genode::Io_mem_session_capability io_mem_cap =
device.io_mem(resource_id, cache_attribute, offset, size);
d->io_mem(bar, cache_attribute);
return Genode::Io_mem_session_client(io_mem_cap).dataspace();
}
@ -82,7 +79,6 @@ class Lx::Pci_dev_registry
template <typename T>
T io_read(unsigned port)
{
PDBG("io_read %u", port);
/* try I/O access on all PCI devices */
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
T value = 0;
@ -97,8 +93,6 @@ class Lx::Pci_dev_registry
template <typename T>
void io_write(unsigned port, T value)
{
PDBG("io_write %u", port);
/* try I/O access on all PCI devices, return on first success */
for (Pci_dev *d = _devs.first(); d; d = d->next())
if (d->io_port().out<T>(port, value))

View File

@ -52,7 +52,7 @@ class Lx::Scheduler
{
private:
bool verbose = true;
bool verbose = false;
Lx::List<Lx::Task> _present_list;
Genode::Lock _present_list_mutex;

View File

@ -120,6 +120,8 @@ class Lx::Task : public Lx::List<Lx::Task>::Element
void wait_enqueue(List *list)
{
if (_wait_le_enqueued && _wait_list == list) return;
if (_wait_le_enqueued) {
PERR("%p already queued in %p", this, _wait_list);
Genode::sleep_forever();

View File

@ -23,6 +23,7 @@
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
#include <lx_emul/impl/internal/scheduler.h>
namespace Lx {

View File

@ -0,0 +1,146 @@
/*
* \brief Work queue implementation
* \author Josef Soentgen
* \author Stefan Kalkowski
* \date 2015-10-26
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__WORK_H_
#define _LX_EMUL__IMPL__INTERNAL__WORK_H_
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
#include <lx_emul/impl/internal/list.h>
namespace Lx {
class Work;
}
class Lx::Work
{
public:
/**
* Context encapsulates a normal work item
*/
struct Context : public Lx::List<Context>::Element
{
void *work;
enum Type { NORMAL, DELAYED, TASKLET } type;
void exec() {
switch (type) {
case NORMAL:
{
work_struct *w = static_cast<work_struct *>(work);
w->func(w);
}
break;
case DELAYED:
{
delayed_work *w = static_cast<delayed_work *>(work);
w->work.func(&(w)->work);
}
break;
case TASKLET:
{
tasklet_struct *tasklet = static_cast<tasklet_struct *>(work);
tasklet->func(tasklet->data);
}
break;
}
}
Context(delayed_work *w) : work(w), type(DELAYED) { }
Context(work_struct *w) : work(w), type(NORMAL) { }
Context(tasklet_struct *w) : work(w), type(TASKLET) { }
};
private:
Lx::Task _task;
Lx::List<Context> _list;
Genode::Tslab<Context, 64 * sizeof(Context)> _work_alloc;
Work()
: _task(Work::run_work, reinterpret_cast<void*>(this), "work_queue",
Lx::Task::PRIORITY_2, Lx::scheduler()),
_work_alloc(Genode::env()->heap()) { }
public:
static Work & work_queue();
/**
* Unblock corresponding task
*/
void unblock() { _task.unblock(); }
/**
* Schedule work item
*/
template <typename WORK>
void schedule(WORK *work)
{
Context *c = new (&_work_alloc) Context(work);
_list.append(c);
}
/**
* Execute all available work items
*/
void exec()
{
while (Context *c = _list.first()) {
c->exec();
_list.remove(c);
destroy(&_work_alloc, c);
}
}
/**
* Cancel work item
*/
bool cancel_work(struct work_struct *work, bool sync = false)
{
for (Context *c = _list.first(); c; c = c->next()) {
if (c->work == work) {
if (sync)
c->exec();
_list.remove(c);
destroy(&_work_alloc, c);
return true;
}
}
return false;
}
static void run_work(void * wq)
{
Work * work_queue = reinterpret_cast<Work*>(wq);
while (1) {
work_queue->exec();
Lx::scheduler().current()->block_and_schedule();
}
}
};
Lx::Work & Lx::Work::work_queue()
{
static Lx::Work work;
return work;
}
#endif /* _LX_EMUL__IMPL__INTERNAL__WORK_H_ */

View File

@ -15,7 +15,7 @@
#include <lx_emul/impl/internal/mapped_io_mem_range.h>
void *ioremap(resource_size_t phys_addr, unsigned long size)
void *ioremap(phys_addr_t phys_addr, unsigned long size)
{
return Lx::ioremap(phys_addr, size, Genode::UNCACHED);
}

View File

@ -44,7 +44,7 @@ extern "C" int pci_register_driver(struct pci_driver *driver)
/* look if we find the device ID in the driver's 'id_table' */
pci_device_id const *matching_id = nullptr;
for (pci_device_id const *id = id_table; id->class_ != (unsigned)PCI_ANY_ID; id++)
for (pci_device_id const *id = id_table; id->class_ != 0; id++)
if (id->device == device_id)
matching_id = id;
@ -62,7 +62,7 @@ extern "C" int pci_register_driver(struct pci_driver *driver)
pci_dev->dev.driver = &driver->driver;
/* call probe function of the Linux driver */
if (!driver->probe(pci_dev, matching_id)) {
if (driver->probe(pci_dev, matching_id)) {
/* if the probing failed, revert the creation of 'pci_dev' */
pci_dev_put(pci_dev);
@ -88,6 +88,13 @@ extern "C" size_t pci_resource_start(struct pci_dev *dev, unsigned bar)
return dev->resource[bar].start;
}
extern "C" size_t pci_resource_end(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].end;
}
extern "C" size_t pci_resource_len(struct pci_dev *dev, unsigned bar)
{

View File

@ -26,14 +26,15 @@ signed long schedule_timeout(signed long timeout)
{
struct timer_list timer;
unsigned long expire = timeout + jiffies;
setup_timer(&timer, unblock_task, (unsigned long)Lx::scheduler().current());
mod_timer(&timer, timeout);
mod_timer(&timer, expire);
Lx::scheduler().current()->block_and_schedule();
del_timer(&timer);
timeout = (timeout - jiffies);
timeout = (expire - jiffies);
return timeout < 0 ? 0 : timeout;
}

View File

@ -0,0 +1,80 @@
/*
* \brief Implementation of linux/workqueue.h
* \author Stefan Kalkowski
* \date 2015-10-26
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/work.h>
int schedule_work(struct work_struct *work)
{
Lx::Work::work_queue().schedule(work);
Lx::Work::work_queue().unblock();
return 1;
}
static void _schedule_delayed_work(unsigned long w)
{
schedule_work((struct work_struct *)w);
}
bool queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay)
{
/* treat delayed work without delay like any other work */
if (delay == 0) {
schedule_work(&dwork->work);
} else {
setup_timer(&dwork->timer, _schedule_delayed_work, (unsigned long)&dwork->work);
mod_timer(&dwork->timer, delay);
}
return true;
}
int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
{
return queue_delayed_work(system_wq, dwork, delay);
}
bool cancel_work_sync(struct work_struct *work)
{
return Lx::Work::work_queue().cancel_work(work, true);
}
bool cancel_delayed_work(struct delayed_work *dwork)
{
int pending = timer_pending(&dwork->timer);
del_timer(&dwork->timer);
/* if the timer is still pending dwork was not executed */
return pending;
}
bool cancel_delayed_work_sync(struct delayed_work *dwork)
{
bool pending = cancel_delayed_work(dwork);
if (pending) {
PERR("WARN: delayed_work %p is executed directly in current '%s' routine",
dwork, Lx::scheduler().current()->name());
dwork->work.func(&dwork->work);
}
return pending;
}

View File

@ -24,3 +24,10 @@ typedef enum irqreturn {
IRQ_HANDLED = 1,
IRQ_WAKE_THREAD = 2,
} irqreturn_t;
/***********************
** linux/interrupt.h **
***********************/
typedef irqreturn_t (*irq_handler_t)(int, void *);

View File

@ -39,6 +39,15 @@
#define KERN_WARNING "WARNING: "
#define KERN_WARN "WARNING: "
static inline int _printk(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
lx_vprintf(fmt, args);
va_end(args);
return 0;
}
/*
* Debug macros
*/

View File

@ -96,6 +96,7 @@ return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); }
size_t pci_resource_len(struct pci_dev *dev, unsigned bar);
size_t pci_resource_start(struct pci_dev *dev, unsigned bar);
size_t pci_resource_end(struct pci_dev *dev, unsigned bar);
void pci_dev_put(struct pci_dev *dev);
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from);

View File

@ -41,7 +41,9 @@ struct sg_table
struct sg_page_iter
{
struct scatterlist *sg;
unsigned int sg_pgoffset; /* page offset within the sg */
unsigned int sg_pgoffset; /* page offset within the sg */
unsigned int __nents;
int __pg_advance;
};
struct sg_mapping_iter

View File

@ -183,17 +183,17 @@ void __wait_event(wait_queue_head_t);
#define wait_event(wq, condition) ({ _wait_event(wq, condition); })
#define wait_event_interruptible(wq, condition) ({ _wait_event(wq, condition); 0; })
#define _wait_event_timeout(wq, condition, timeout) \
({ int res = 1; \
prepare_to_wait(&wq, 0, 0); \
while (1) { \
if ((condition) || !res) { \
break; \
} \
res = schedule_timeout(jiffies + timeout); \
} \
finish_wait(&wq, 0); \
res; \
#define _wait_event_timeout(wq, condition, timeout) \
({ int res = 1; \
prepare_to_wait(&wq, 0, 0); \
while (1) { \
if ((condition) || !res) { \
break; \
} \
res = schedule_timeout(timeout); \
} \
finish_wait(&wq, 0); \
res; \
})
#define wait_event_timeout(wq, condition, timeout) \