static int ipu_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *orig_mode, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct drm_framebuffer *fb = ipu_crtc->base.fb; int ret; struct ipu_di_signal_cfg sig_cfg = {}; u32 out_pixel_fmt; struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch); int bpp; u32 v4l2_fmt; dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, mode->hdisplay); dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, mode->vdisplay); ipu_ch_param_zero(cpmem); switch (fb->pixel_format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: v4l2_fmt = V4L2_PIX_FMT_RGB32; bpp = 32; break; case DRM_FORMAT_RGB565: v4l2_fmt = V4L2_PIX_FMT_RGB565; bpp = 16; break; case DRM_FORMAT_RGB888: v4l2_fmt = V4L2_PIX_FMT_RGB24; bpp = 24; break; default: dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n", fb->pixel_format); return -EINVAL; } out_pixel_fmt = ipu_crtc->interface_pix_fmt; if (mode->flags & DRM_MODE_FLAG_INTERLACE) sig_cfg.interlaced = 1; if (mode->flags & DRM_MODE_FLAG_PHSYNC) sig_cfg.Hsync_pol = 1; if (mode->flags & DRM_MODE_FLAG_PVSYNC) sig_cfg.Vsync_pol = 1; sig_cfg.enable_pol = 1; sig_cfg.clk_pol = 0; sig_cfg.width = mode->hdisplay; sig_cfg.height = mode->vdisplay; sig_cfg.pixel_fmt = out_pixel_fmt; sig_cfg.h_start_width = mode->htotal - mode->hsync_end; sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start; sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay; sig_cfg.v_start_width = mode->vtotal - mode->vsync_end; sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start; sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay; sig_cfg.pixelclock = mode->clock * 1000; sig_cfg.clkflags = ipu_crtc->di_clkflags; sig_cfg.v_to_h_sync = 0; if (ipu_crtc->dp) { ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB, IPUV3_COLORSPACE_RGB); if (ret) { dev_err(ipu_crtc->dev, "initializing display processor failed with %d\n", ret); return ret; } ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1); } ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced, out_pixel_fmt, mode->hdisplay); if (ret) { dev_err(ipu_crtc->dev, "initializing display controller failed with %d\n", ret); return ret; } ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); if (ret) { dev_err(ipu_crtc->dev, "initializing panel failed with %d\n", ret); return ret; } ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay); ipu_cpmem_set_fmt(cpmem, v4l2_fmt); ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch); ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay); if (ret) { dev_err(ipu_crtc->dev, "initializing dmfc channel failed with %d\n", ret); return ret; } ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc, calc_bandwidth(mode, calc_vref(mode)), 64); if (ret) { dev_err(ipu_crtc->dev, "allocating dmfc bandwidth failed with %d\n", ret); return ret; } ipu_drm_set_base(crtc, x, y); return 0; }
/* TODO: this should be optimized so we don't allocate network and call open()/close() all the time */ static void collect (DiskIOMonitor *monitor) { gchar *contents = NULL; gsize len; GError *error; gchar **lines = NULL; guint n; gint64 now; Sample *sample = NULL; Sample *last = NULL; GVariantBuilder builder; error = NULL; if (!g_file_get_contents ("/proc/diskstats", &contents, &len, &error)) { g_warning ("Error loading contents /proc/vmstat: %s (%s, %d)", error->message, g_quark_to_string (error->domain), error->code); g_error_free (error); goto out; } now = g_get_real_time (); sample = &(monitor->samples[monitor->samples_next]); sample->timestamp = now; sample->bytes_read = 0; sample->bytes_written = 0; sample->num_ops = 0; if (monitor->samples_prev != -1) last = &(monitor->samples[monitor->samples_prev]); lines = g_strsplit (contents, "\n", -1); for (n = 0; lines != NULL && lines[n] != NULL; n++) { const gchar *line = lines[n]; guint num_parsed; gint dev_major, dev_minor; gchar dev_name[64]; /* TODO: big enough? */ guint64 num_reads, num_reads_merged, num_sectors_read, num_msec_reading; guint64 num_writes, num_writes_merged, num_sectors_written, num_msec_writing; guint64 num_io_in_progress, num_msec_doing_io, weighted_num_msec_doing_io; if (strlen (line) == 0) continue; /* From http://www.kernel.org/doc/Documentation/iostats.txt * * Field 1 -- # of reads completed * This is the total number of reads completed successfully. * Field 2 -- # of reads merged, field 6 -- # of writes merged * Reads and writes which are adjacent to each other may be merged for * efficiency. Thus two 4K reads may become one 8K read before it is * ultimately handed to the disk, and so it will be counted (and queued) * as only one I/O. This field lets you know how often this was done. * Field 3 -- # of sectors read * This is the total number of sectors read successfully. * Field 4 -- # of milliseconds spent reading * This is the total number of milliseconds spent by all reads (as * measured from __make_request() to end_that_request_last()). * Field 5 -- # of writes completed * This is the total number of writes completed successfully. * Field 7 -- # of sectors written * This is the total number of sectors written successfully. * Field 8 -- # of milliseconds spent writing * This is the total number of milliseconds spent by all writes (as * measured from __make_request() to end_that_request_last()). * Field 9 -- # of I/Os currently in progress * The only field that should go to zero. Incremented as requests are * given to appropriate struct request_queue and decremented as they finish. * Field 10 -- # of milliseconds spent doing I/Os * This field increases so long as field 9 is nonzero. * Field 11 -- weighted # of milliseconds spent doing I/Os * This field is incremented at each I/O start, I/O completion, I/O * merge, or read of these stats by the number of I/Os in progress * (field 9) times the number of milliseconds spent doing I/O since the * last update of this field. This can provide an easy measure of both * I/O completion time and the backlog that may be accumulating. */ num_parsed = sscanf (line, "%d %d %s" " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, &dev_major, &dev_minor, dev_name, &num_reads, &num_reads_merged, &num_sectors_read, &num_msec_reading, &num_writes, &num_writes_merged, &num_sectors_written, &num_msec_writing, &num_io_in_progress, &num_msec_doing_io, &weighted_num_msec_doing_io); if (num_parsed != 14) { g_warning ("Error parsing line %d of file /proc/diskstats (num_parsed=%d): `%s'", n, num_parsed, line); continue; } /* skip mapped devices and partitions... otherwise we'll count their * I/O more than once * * TODO: the way we identify dm devices and partitions is not * very elegant... we should consult sysfs via libgudev1 * instead. */ if (dev_major == 253) continue; if (g_str_has_prefix (dev_name, "sd") && g_ascii_isdigit (dev_name[strlen (dev_name) - 1])) continue; sample->bytes_read += num_sectors_read * 512; sample->bytes_written += num_sectors_written * 512; sample->num_ops += num_reads_merged + num_writes_merged; } if (last != NULL) { sample->bytes_read_per_sec = calc_bandwidth (monitor, sample, last, sample->bytes_read, last->bytes_read); sample->bytes_written_per_sec = calc_bandwidth (monitor, sample, last, sample->bytes_written, last->bytes_written); sample->io_operations_per_sec = calc_bandwidth (monitor, sample, last, sample->num_ops, last->num_ops); } out: g_strfreev (lines); g_free (contents); if (sample != NULL) { g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad")); g_variant_builder_add (&builder, "d", sample->bytes_read_per_sec); g_variant_builder_add (&builder, "d", sample->bytes_written_per_sec); g_variant_builder_add (&builder, "d", sample->io_operations_per_sec); cockpit_resource_monitor_emit_new_sample (COCKPIT_RESOURCE_MONITOR(monitor), now, g_variant_builder_end (&builder)); } monitor->samples_prev = monitor->samples_next; monitor->samples_next += 1; if (monitor->samples_next == monitor->samples_max) monitor->samples_next = 0; }