Merge tag 'drm-intel-next-2022-05-06' of git://anongit.freedesktop.org/drm/drm-intel into drm-next
drm/i915 feature pull #2 for v5.19: Features and functionality: - Add first set of DG2 PCI IDs for "motherboard down" designs (Matt Roper) - Add initial RPL-P PCI IDs as ADL-P subplatform (Matt Atwood) Refactoring and cleanups: - Power well refactoring and cleanup (Imre) - GVT-g refactor and mdev API cleanup (Christoph, Jason, Zhi) - DPLL refactoring and cleanup (Ville) - VBT panel specific data parsing cleanup (Ville) - Use drm_mode_init() for on-stack modes (Ville) Fixes: - Fix PSR state pipe A/B confusion by clearing more state on disable (José) - Fix FIFO underruns caused by not taking DRAM channel into account (Vinod) - Fix FBC flicker on display 11+ by enabling a workaround (José) - Fix VBT seamless DRRS min refresh rate check (Ville) - Fix panel type assumption on bogus VBT data (Ville) - Fix panel data parsing for VBT that misses panel data pointers block (Ville) - Fix spurious AUX timeout/hotplug handling on LTTPR links (Imre) Merges: - Backmerge drm-next (Jani) - GVT changes (Jani) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/87bkwbkkdo.fsf@intel.com
This commit is contained in:
commit
d53b8e19c2
Documentation/driver-api
arch/x86/kernel
drivers
gpu/drm/i915
KconfigMakefile
display
g4x_dp.cg4x_hdmi.cicl_dsi.cintel_bios.cintel_ddi.cintel_ddi_buf_trans.cintel_display.cintel_display.hintel_display_power.cintel_display_power.hintel_display_power_map.cintel_display_power_map.hintel_display_power_well.cintel_display_power_well.hintel_dp_link_training.cintel_dpio_phy.cintel_dpll.cintel_dpll.hintel_dpll_mgr.cintel_dpll_mgr.hintel_fbc.cintel_panel.cintel_pps.cintel_psr.cintel_tc.cintel_vbt_defs.h
gvt
Makefilecfg_space.ccmd_parser.cdmabuf.cexeclist.cfirmware.cgtt.cgvt.cgvt.hhandlers.chypercall.hinterrupt.ckvmgt.cmmio.cmmio.hmpt.hopregion.cpage_track.creg.hscheduler.ctrace.hvgpu.c
i915_driver.ci915_drv.hi915_pci.ci915_reg.hintel_device_info.cintel_device_info.hintel_gvt.cintel_gvt.hintel_gvt_mmio_table.cintel_pm.cs390
vfio/mdev
include
samples/vfio-mdev
@ -105,6 +105,7 @@ structure to represent a mediated device's driver::
|
|||||||
struct mdev_driver {
|
struct mdev_driver {
|
||||||
int (*probe) (struct mdev_device *dev);
|
int (*probe) (struct mdev_device *dev);
|
||||||
void (*remove) (struct mdev_device *dev);
|
void (*remove) (struct mdev_device *dev);
|
||||||
|
struct attribute_group **supported_type_groups;
|
||||||
struct device_driver driver;
|
struct device_driver driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -119,33 +120,15 @@ to register and unregister itself with the core driver:
|
|||||||
|
|
||||||
extern void mdev_unregister_driver(struct mdev_driver *drv);
|
extern void mdev_unregister_driver(struct mdev_driver *drv);
|
||||||
|
|
||||||
The mediated bus driver is responsible for adding mediated devices to the VFIO
|
The mediated bus driver's probe function should create a vfio_device on top of
|
||||||
group when devices are bound to the driver and removing mediated devices from
|
the mdev_device and connect it to an appropriate implementation of
|
||||||
the VFIO when devices are unbound from the driver.
|
vfio_device_ops.
|
||||||
|
|
||||||
|
|
||||||
Physical Device Driver Interface
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
The physical device driver interface provides the mdev_parent_ops[3] structure
|
|
||||||
to define the APIs to manage work in the mediated core driver that is related
|
|
||||||
to the physical device.
|
|
||||||
|
|
||||||
The structures in the mdev_parent_ops structure are as follows:
|
|
||||||
|
|
||||||
* dev_attr_groups: attributes of the parent device
|
|
||||||
* mdev_attr_groups: attributes of the mediated device
|
|
||||||
* supported_config: attributes to define supported configurations
|
|
||||||
* device_driver: device driver to bind for mediated device instances
|
|
||||||
|
|
||||||
The mdev_parent_ops also still has various functions pointers. Theses exist
|
|
||||||
for historical reasons only and shall not be used for new drivers.
|
|
||||||
|
|
||||||
When a driver wants to add the GUID creation sysfs to an existing device it has
|
When a driver wants to add the GUID creation sysfs to an existing device it has
|
||||||
probe'd to then it should call::
|
probe'd to then it should call::
|
||||||
|
|
||||||
extern int mdev_register_device(struct device *dev,
|
extern int mdev_register_device(struct device *dev,
|
||||||
const struct mdev_parent_ops *ops);
|
struct mdev_driver *mdev_driver);
|
||||||
|
|
||||||
This will provide the 'mdev_supported_types/XX/create' files which can then be
|
This will provide the 'mdev_supported_types/XX/create' files which can then be
|
||||||
used to trigger the creation of a mdev_device. The created mdev_device will be
|
used to trigger the creation of a mdev_device. The created mdev_device will be
|
||||||
|
@ -558,6 +558,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
|||||||
INTEL_ADLP_IDS(&gen11_early_ops),
|
INTEL_ADLP_IDS(&gen11_early_ops),
|
||||||
INTEL_ADLN_IDS(&gen11_early_ops),
|
INTEL_ADLN_IDS(&gen11_early_ops),
|
||||||
INTEL_RPLS_IDS(&gen11_early_ops),
|
INTEL_RPLS_IDS(&gen11_early_ops),
|
||||||
|
INTEL_RPLP_IDS(&gen11_early_ops),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);
|
struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);
|
||||||
|
@ -106,40 +106,30 @@ config DRM_I915_USERPTR
|
|||||||
If in doubt, say "Y".
|
If in doubt, say "Y".
|
||||||
|
|
||||||
config DRM_I915_GVT
|
config DRM_I915_GVT
|
||||||
bool "Enable Intel GVT-g graphics virtualization host support"
|
bool
|
||||||
|
|
||||||
|
config DRM_I915_GVT_KVMGT
|
||||||
|
tristate "Enable KVM host support Intel GVT-g graphics virtualization"
|
||||||
depends on DRM_I915
|
depends on DRM_I915
|
||||||
depends on X86
|
depends on X86
|
||||||
depends on 64BIT
|
depends on 64BIT
|
||||||
default n
|
depends on KVM
|
||||||
|
depends on VFIO_MDEV
|
||||||
|
select DRM_I915_GVT
|
||||||
|
select KVM_EXTERNAL_WRITE_TRACKING
|
||||||
|
|
||||||
help
|
help
|
||||||
Choose this option if you want to enable Intel GVT-g graphics
|
Choose this option if you want to enable Intel GVT-g graphics
|
||||||
virtualization technology host support with integrated graphics.
|
virtualization technology host support with integrated graphics.
|
||||||
With GVT-g, it's possible to have one integrated graphics
|
With GVT-g, it's possible to have one integrated graphics
|
||||||
device shared by multiple VMs under different hypervisors.
|
device shared by multiple VMs under KVM.
|
||||||
|
|
||||||
Note that at least one hypervisor like Xen or KVM is required for
|
Note that this driver only supports newer device from Broadwell on.
|
||||||
this driver to work, and it only supports newer device from
|
For further information and setup guide, you can visit:
|
||||||
Broadwell+. For further information and setup guide, you can
|
http://01.org/igvt-g.
|
||||||
visit: http://01.org/igvt-g.
|
|
||||||
|
|
||||||
Now it's just a stub to support the modifications of i915 for
|
|
||||||
GVT device model. It requires at least one MPT modules for Xen/KVM
|
|
||||||
and other components of GVT device model to work. Use it under
|
|
||||||
you own risk.
|
|
||||||
|
|
||||||
If in doubt, say "N".
|
If in doubt, say "N".
|
||||||
|
|
||||||
config DRM_I915_GVT_KVMGT
|
|
||||||
tristate "Enable KVM/VFIO support for Intel GVT-g"
|
|
||||||
depends on DRM_I915_GVT
|
|
||||||
depends on KVM
|
|
||||||
depends on VFIO_MDEV
|
|
||||||
select KVM_EXTERNAL_WRITE_TRACKING
|
|
||||||
default n
|
|
||||||
help
|
|
||||||
Choose this option if you want to enable KVMGT support for
|
|
||||||
Intel GVT-g.
|
|
||||||
|
|
||||||
config DRM_I915_PXP
|
config DRM_I915_PXP
|
||||||
bool "Enable Intel PXP support"
|
bool "Enable Intel PXP support"
|
||||||
depends on DRM_I915
|
depends on DRM_I915
|
||||||
|
@ -223,6 +223,7 @@ i915-y += \
|
|||||||
display/intel_cursor.o \
|
display/intel_cursor.o \
|
||||||
display/intel_display.o \
|
display/intel_display.o \
|
||||||
display/intel_display_power.o \
|
display/intel_display_power.o \
|
||||||
|
display/intel_display_power_map.o \
|
||||||
display/intel_display_power_well.o \
|
display/intel_display_power_well.o \
|
||||||
display/intel_dmc.o \
|
display/intel_dmc.o \
|
||||||
display/intel_dpio_phy.o \
|
display/intel_dpio_phy.o \
|
||||||
@ -331,13 +332,13 @@ i915-$(CONFIG_DRM_I915_SELFTEST) += \
|
|||||||
# virtual gpu code
|
# virtual gpu code
|
||||||
i915-y += i915_vgpu.o
|
i915-y += i915_vgpu.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_DRM_I915_GVT),y)
|
i915-$(CONFIG_DRM_I915_GVT) += \
|
||||||
i915-y += intel_gvt.o
|
intel_gvt.o \
|
||||||
|
intel_gvt_mmio_table.o
|
||||||
include $(src)/gvt/Makefile
|
include $(src)/gvt/Makefile
|
||||||
endif
|
|
||||||
|
|
||||||
obj-$(CONFIG_DRM_I915) += i915.o
|
obj-$(CONFIG_DRM_I915) += i915.o
|
||||||
obj-$(CONFIG_DRM_I915_GVT_KVMGT) += gvt/kvmgt.o
|
obj-$(CONFIG_DRM_I915_GVT_KVMGT) += kvmgt.o
|
||||||
|
|
||||||
# header test
|
# header test
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "intel_connector.h"
|
#include "intel_connector.h"
|
||||||
#include "intel_crtc.h"
|
#include "intel_crtc.h"
|
||||||
#include "intel_de.h"
|
#include "intel_de.h"
|
||||||
|
#include "intel_display_power.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dp.h"
|
#include "intel_dp.h"
|
||||||
#include "intel_dp_link_training.h"
|
#include "intel_dp_link_training.h"
|
||||||
@ -1375,7 +1376,7 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv,
|
|||||||
dig_port->max_lanes = 4;
|
dig_port->max_lanes = 4;
|
||||||
|
|
||||||
intel_encoder->type = INTEL_OUTPUT_DP;
|
intel_encoder->type = INTEL_OUTPUT_DP;
|
||||||
intel_encoder->power_domain = intel_port_to_power_domain(port);
|
intel_encoder->power_domain = intel_display_power_ddi_lanes_domain(dev_priv, port);
|
||||||
if (IS_CHERRYVIEW(dev_priv)) {
|
if (IS_CHERRYVIEW(dev_priv)) {
|
||||||
if (port == PORT_D)
|
if (port == PORT_D)
|
||||||
intel_encoder->pipe_mask = BIT(PIPE_C);
|
intel_encoder->pipe_mask = BIT(PIPE_C);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "intel_connector.h"
|
#include "intel_connector.h"
|
||||||
#include "intel_crtc.h"
|
#include "intel_crtc.h"
|
||||||
#include "intel_de.h"
|
#include "intel_de.h"
|
||||||
|
#include "intel_display_power.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dpio_phy.h"
|
#include "intel_dpio_phy.h"
|
||||||
#include "intel_fifo_underrun.h"
|
#include "intel_fifo_underrun.h"
|
||||||
@ -574,7 +575,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv,
|
|||||||
intel_encoder->shutdown = intel_hdmi_encoder_shutdown;
|
intel_encoder->shutdown = intel_hdmi_encoder_shutdown;
|
||||||
|
|
||||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||||
intel_encoder->power_domain = intel_port_to_power_domain(port);
|
intel_encoder->power_domain = intel_display_power_ddi_lanes_domain(dev_priv, port);
|
||||||
intel_encoder->port = port;
|
intel_encoder->port = port;
|
||||||
if (IS_CHERRYVIEW(dev_priv)) {
|
if (IS_CHERRYVIEW(dev_priv)) {
|
||||||
if (port == PORT_D)
|
if (port == PORT_D)
|
||||||
|
@ -400,8 +400,8 @@ static void get_dsi_io_power_domains(struct drm_i915_private *dev_priv,
|
|||||||
intel_dsi->io_wakeref[port] =
|
intel_dsi->io_wakeref[port] =
|
||||||
intel_display_power_get(dev_priv,
|
intel_display_power_get(dev_priv,
|
||||||
port == PORT_A ?
|
port == PORT_A ?
|
||||||
POWER_DOMAIN_PORT_DDI_A_IO :
|
POWER_DOMAIN_PORT_DDI_IO_A :
|
||||||
POWER_DOMAIN_PORT_DDI_B_IO);
|
POWER_DOMAIN_PORT_DDI_IO_B);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1426,8 +1426,8 @@ static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
|
|||||||
wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
|
wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
|
||||||
intel_display_power_put(dev_priv,
|
intel_display_power_put(dev_priv,
|
||||||
port == PORT_A ?
|
port == PORT_A ?
|
||||||
POWER_DOMAIN_PORT_DDI_A_IO :
|
POWER_DOMAIN_PORT_DDI_IO_A :
|
||||||
POWER_DOMAIN_PORT_DDI_B_IO,
|
POWER_DOMAIN_PORT_DDI_IO_B,
|
||||||
wakeref);
|
wakeref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,10 +186,14 @@ static const struct {
|
|||||||
.min_size = sizeof(struct bdb_edp), },
|
.min_size = sizeof(struct bdb_edp), },
|
||||||
{ .section_id = BDB_LVDS_OPTIONS,
|
{ .section_id = BDB_LVDS_OPTIONS,
|
||||||
.min_size = sizeof(struct bdb_lvds_options), },
|
.min_size = sizeof(struct bdb_lvds_options), },
|
||||||
|
/*
|
||||||
|
* BDB_LVDS_LFP_DATA depends on BDB_LVDS_LFP_DATA_PTRS,
|
||||||
|
* so keep the two ordered.
|
||||||
|
*/
|
||||||
{ .section_id = BDB_LVDS_LFP_DATA_PTRS,
|
{ .section_id = BDB_LVDS_LFP_DATA_PTRS,
|
||||||
.min_size = sizeof(struct bdb_lvds_lfp_data_ptrs), },
|
.min_size = sizeof(struct bdb_lvds_lfp_data_ptrs), },
|
||||||
{ .section_id = BDB_LVDS_LFP_DATA,
|
{ .section_id = BDB_LVDS_LFP_DATA,
|
||||||
.min_size = sizeof(struct bdb_lvds_lfp_data), },
|
.min_size = 0, /* special case */ },
|
||||||
{ .section_id = BDB_LVDS_BACKLIGHT,
|
{ .section_id = BDB_LVDS_BACKLIGHT,
|
||||||
.min_size = sizeof(struct bdb_lfp_backlight_data), },
|
.min_size = sizeof(struct bdb_lfp_backlight_data), },
|
||||||
{ .section_id = BDB_LFP_POWER,
|
{ .section_id = BDB_LFP_POWER,
|
||||||
@ -204,6 +208,23 @@ static const struct {
|
|||||||
.min_size = sizeof(struct bdb_generic_dtd), },
|
.min_size = sizeof(struct bdb_generic_dtd), },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static size_t lfp_data_min_size(struct drm_i915_private *i915)
|
||||||
|
{
|
||||||
|
const struct bdb_lvds_lfp_data_ptrs *ptrs;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
|
||||||
|
if (!ptrs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = sizeof(struct bdb_lvds_lfp_data);
|
||||||
|
if (ptrs->panel_name.table_size)
|
||||||
|
size = max(size, ptrs->panel_name.offset +
|
||||||
|
sizeof(struct bdb_lvds_lfp_data_tail));
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
static bool validate_lfp_data_ptrs(const void *bdb,
|
static bool validate_lfp_data_ptrs(const void *bdb,
|
||||||
const struct bdb_lvds_lfp_data_ptrs *ptrs)
|
const struct bdb_lvds_lfp_data_ptrs *ptrs)
|
||||||
{
|
{
|
||||||
@ -311,16 +332,144 @@ static bool fixup_lfp_data_ptrs(const void *bdb, void *ptrs_block)
|
|||||||
return validate_lfp_data_ptrs(bdb, ptrs);
|
return validate_lfp_data_ptrs(bdb, ptrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const void *find_fp_timing_terminator(const u8 *data, int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size - 1; i++) {
|
||||||
|
if (data[i] == 0xff && data[i+1] == 0xff)
|
||||||
|
return &data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_lfp_data_ptr(struct lvds_lfp_data_ptr_table *table,
|
||||||
|
int table_size, int total_size)
|
||||||
|
{
|
||||||
|
if (total_size < table_size)
|
||||||
|
return total_size;
|
||||||
|
|
||||||
|
table->table_size = table_size;
|
||||||
|
table->offset = total_size - table_size;
|
||||||
|
|
||||||
|
return total_size - table_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void next_lfp_data_ptr(struct lvds_lfp_data_ptr_table *next,
|
||||||
|
const struct lvds_lfp_data_ptr_table *prev,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
next->table_size = prev->table_size;
|
||||||
|
next->offset = prev->offset + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *generate_lfp_data_ptrs(struct drm_i915_private *i915,
|
||||||
|
const void *bdb)
|
||||||
|
{
|
||||||
|
int i, size, table_size, block_size, offset;
|
||||||
|
const void *t0, *t1, *block;
|
||||||
|
struct bdb_lvds_lfp_data_ptrs *ptrs;
|
||||||
|
void *ptrs_block;
|
||||||
|
|
||||||
|
block = find_raw_section(bdb, BDB_LVDS_LFP_DATA);
|
||||||
|
if (!block)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
drm_dbg_kms(&i915->drm, "Generating LFP data table pointers\n");
|
||||||
|
|
||||||
|
block_size = get_blocksize(block);
|
||||||
|
|
||||||
|
size = block_size;
|
||||||
|
t0 = find_fp_timing_terminator(block, size);
|
||||||
|
if (!t0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size -= t0 - block - 2;
|
||||||
|
t1 = find_fp_timing_terminator(t0 + 2, size);
|
||||||
|
if (!t1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size = t1 - t0;
|
||||||
|
if (size * 16 > block_size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptrs_block = kzalloc(sizeof(*ptrs) + 3, GFP_KERNEL);
|
||||||
|
if (!ptrs_block)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*(u8 *)(ptrs_block + 0) = BDB_LVDS_LFP_DATA_PTRS;
|
||||||
|
*(u16 *)(ptrs_block + 1) = sizeof(*ptrs);
|
||||||
|
ptrs = ptrs_block + 3;
|
||||||
|
|
||||||
|
table_size = sizeof(struct lvds_pnp_id);
|
||||||
|
size = make_lfp_data_ptr(&ptrs->ptr[0].panel_pnp_id, table_size, size);
|
||||||
|
|
||||||
|
table_size = sizeof(struct lvds_dvo_timing);
|
||||||
|
size = make_lfp_data_ptr(&ptrs->ptr[0].dvo_timing, table_size, size);
|
||||||
|
|
||||||
|
table_size = t0 - block + 2;
|
||||||
|
size = make_lfp_data_ptr(&ptrs->ptr[0].fp_timing, table_size, size);
|
||||||
|
|
||||||
|
if (ptrs->ptr[0].fp_timing.table_size)
|
||||||
|
ptrs->lvds_entries++;
|
||||||
|
if (ptrs->ptr[0].dvo_timing.table_size)
|
||||||
|
ptrs->lvds_entries++;
|
||||||
|
if (ptrs->ptr[0].panel_pnp_id.table_size)
|
||||||
|
ptrs->lvds_entries++;
|
||||||
|
|
||||||
|
if (size != 0 || ptrs->lvds_entries != 3) {
|
||||||
|
kfree(ptrs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = t1 - t0;
|
||||||
|
for (i = 1; i < 16; i++) {
|
||||||
|
next_lfp_data_ptr(&ptrs->ptr[i].fp_timing, &ptrs->ptr[i-1].fp_timing, size);
|
||||||
|
next_lfp_data_ptr(&ptrs->ptr[i].dvo_timing, &ptrs->ptr[i-1].dvo_timing, size);
|
||||||
|
next_lfp_data_ptr(&ptrs->ptr[i].panel_pnp_id, &ptrs->ptr[i-1].panel_pnp_id, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = t1 - t0;
|
||||||
|
table_size = sizeof(struct lvds_lfp_panel_name);
|
||||||
|
|
||||||
|
if (16 * (size + table_size) <= block_size) {
|
||||||
|
ptrs->panel_name.table_size = table_size;
|
||||||
|
ptrs->panel_name.offset = size * 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = block - bdb;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
ptrs->ptr[i].fp_timing.offset += offset;
|
||||||
|
ptrs->ptr[i].dvo_timing.offset += offset;
|
||||||
|
ptrs->ptr[i].panel_pnp_id.offset += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptrs->panel_name.table_size)
|
||||||
|
ptrs->panel_name.offset += offset;
|
||||||
|
|
||||||
|
return ptrs_block;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_bdb_block(struct drm_i915_private *i915,
|
init_bdb_block(struct drm_i915_private *i915,
|
||||||
const void *bdb, enum bdb_block_id section_id,
|
const void *bdb, enum bdb_block_id section_id,
|
||||||
size_t min_size)
|
size_t min_size)
|
||||||
{
|
{
|
||||||
struct bdb_block_entry *entry;
|
struct bdb_block_entry *entry;
|
||||||
|
void *temp_block = NULL;
|
||||||
const void *block;
|
const void *block;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
|
|
||||||
block = find_raw_section(bdb, section_id);
|
block = find_raw_section(bdb, section_id);
|
||||||
|
|
||||||
|
/* Modern VBTs lack the LFP data table pointers block, make one up */
|
||||||
|
if (!block && section_id == BDB_LVDS_LFP_DATA_PTRS) {
|
||||||
|
temp_block = generate_lfp_data_ptrs(i915, bdb);
|
||||||
|
if (temp_block)
|
||||||
|
block = temp_block + 3;
|
||||||
|
}
|
||||||
if (!block)
|
if (!block)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -331,12 +480,16 @@ init_bdb_block(struct drm_i915_private *i915,
|
|||||||
|
|
||||||
entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3),
|
entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!entry)
|
if (!entry) {
|
||||||
|
kfree(temp_block);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
entry->section_id = section_id;
|
entry->section_id = section_id;
|
||||||
memcpy(entry->data, block - 3, block_size + 3);
|
memcpy(entry->data, block - 3, block_size + 3);
|
||||||
|
|
||||||
|
kfree(temp_block);
|
||||||
|
|
||||||
drm_dbg_kms(&i915->drm, "Found BDB block %d (size %zu, min size %zu)\n",
|
drm_dbg_kms(&i915->drm, "Found BDB block %d (size %zu, min size %zu)\n",
|
||||||
section_id, block_size, min_size);
|
section_id, block_size, min_size);
|
||||||
|
|
||||||
@ -359,6 +512,9 @@ static void init_bdb_blocks(struct drm_i915_private *i915,
|
|||||||
enum bdb_block_id section_id = bdb_blocks[i].section_id;
|
enum bdb_block_id section_id = bdb_blocks[i].section_id;
|
||||||
size_t min_size = bdb_blocks[i].min_size;
|
size_t min_size = bdb_blocks[i].min_size;
|
||||||
|
|
||||||
|
if (section_id == BDB_LVDS_LFP_DATA)
|
||||||
|
min_size = lfp_data_min_size(i915);
|
||||||
|
|
||||||
init_bdb_block(i915, bdb, section_id, min_size);
|
init_bdb_block(i915, bdb, section_id, min_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,6 +585,94 @@ get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data,
|
|||||||
return (const void *)data + ptrs->ptr[index].fp_timing.offset;
|
return (const void *)data + ptrs->ptr[index].fp_timing.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct bdb_lvds_lfp_data_tail *
|
||||||
|
get_lfp_data_tail(const struct bdb_lvds_lfp_data *data,
|
||||||
|
const struct bdb_lvds_lfp_data_ptrs *ptrs)
|
||||||
|
{
|
||||||
|
if (ptrs->panel_name.table_size)
|
||||||
|
return (const void *)data + ptrs->panel_name.offset;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int opregion_get_panel_type(struct drm_i915_private *i915)
|
||||||
|
{
|
||||||
|
return intel_opregion_get_panel_type(i915);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vbt_get_panel_type(struct drm_i915_private *i915)
|
||||||
|
{
|
||||||
|
const struct bdb_lvds_options *lvds_options;
|
||||||
|
|
||||||
|
lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
|
||||||
|
if (!lvds_options)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (lvds_options->panel_type > 0xf) {
|
||||||
|
drm_dbg_kms(&i915->drm, "Invalid VBT panel type 0x%x\n",
|
||||||
|
lvds_options->panel_type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lvds_options->panel_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fallback_get_panel_type(struct drm_i915_private *i915)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum panel_type {
|
||||||
|
PANEL_TYPE_OPREGION,
|
||||||
|
PANEL_TYPE_VBT,
|
||||||
|
PANEL_TYPE_FALLBACK,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_panel_type(struct drm_i915_private *i915)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
const char *name;
|
||||||
|
int (*get_panel_type)(struct drm_i915_private *i915);
|
||||||
|
int panel_type;
|
||||||
|
} panel_types[] = {
|
||||||
|
[PANEL_TYPE_OPREGION] = {
|
||||||
|
.name = "OpRegion",
|
||||||
|
.get_panel_type = opregion_get_panel_type,
|
||||||
|
},
|
||||||
|
[PANEL_TYPE_VBT] = {
|
||||||
|
.name = "VBT",
|
||||||
|
.get_panel_type = vbt_get_panel_type,
|
||||||
|
},
|
||||||
|
[PANEL_TYPE_FALLBACK] = {
|
||||||
|
.name = "fallback",
|
||||||
|
.get_panel_type = fallback_get_panel_type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(panel_types); i++) {
|
||||||
|
panel_types[i].panel_type = panel_types[i].get_panel_type(i915);
|
||||||
|
|
||||||
|
drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf);
|
||||||
|
|
||||||
|
if (panel_types[i].panel_type >= 0)
|
||||||
|
drm_dbg_kms(&i915->drm, "Panel type (%s): %d\n",
|
||||||
|
panel_types[i].name, panel_types[i].panel_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0)
|
||||||
|
i = PANEL_TYPE_OPREGION;
|
||||||
|
else if (panel_types[PANEL_TYPE_VBT].panel_type >= 0)
|
||||||
|
i = PANEL_TYPE_VBT;
|
||||||
|
else
|
||||||
|
i = PANEL_TYPE_FALLBACK;
|
||||||
|
|
||||||
|
drm_dbg_kms(&i915->drm, "Selected panel type (%s): %d\n",
|
||||||
|
panel_types[i].name, panel_types[i].panel_type);
|
||||||
|
|
||||||
|
return panel_types[i].panel_type;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse general panel options */
|
/* Parse general panel options */
|
||||||
static void
|
static void
|
||||||
parse_panel_options(struct drm_i915_private *i915)
|
parse_panel_options(struct drm_i915_private *i915)
|
||||||
@ -436,7 +680,6 @@ parse_panel_options(struct drm_i915_private *i915)
|
|||||||
const struct bdb_lvds_options *lvds_options;
|
const struct bdb_lvds_options *lvds_options;
|
||||||
int panel_type;
|
int panel_type;
|
||||||
int drrs_mode;
|
int drrs_mode;
|
||||||
int ret;
|
|
||||||
|
|
||||||
lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
|
lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
|
||||||
if (!lvds_options)
|
if (!lvds_options)
|
||||||
@ -444,23 +687,7 @@ parse_panel_options(struct drm_i915_private *i915)
|
|||||||
|
|
||||||
i915->vbt.lvds_dither = lvds_options->pixel_dither;
|
i915->vbt.lvds_dither = lvds_options->pixel_dither;
|
||||||
|
|
||||||
ret = intel_opregion_get_panel_type(i915);
|
panel_type = get_panel_type(i915);
|
||||||
if (ret >= 0) {
|
|
||||||
drm_WARN_ON(&i915->drm, ret > 0xf);
|
|
||||||
panel_type = ret;
|
|
||||||
drm_dbg_kms(&i915->drm, "Panel type: %d (OpRegion)\n",
|
|
||||||
panel_type);
|
|
||||||
} else {
|
|
||||||
if (lvds_options->panel_type > 0xf) {
|
|
||||||
drm_dbg_kms(&i915->drm,
|
|
||||||
"Invalid VBT panel type 0x%x\n",
|
|
||||||
lvds_options->panel_type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
panel_type = lvds_options->panel_type;
|
|
||||||
drm_dbg_kms(&i915->drm, "Panel type: %d (VBT)\n",
|
|
||||||
panel_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
i915->vbt.panel_type = panel_type;
|
i915->vbt.panel_type = panel_type;
|
||||||
|
|
||||||
@ -489,25 +716,16 @@ parse_panel_options(struct drm_i915_private *i915)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to find integrated panel timing data */
|
|
||||||
static void
|
static void
|
||||||
parse_lfp_panel_dtd(struct drm_i915_private *i915)
|
parse_lfp_panel_dtd(struct drm_i915_private *i915,
|
||||||
|
const struct bdb_lvds_lfp_data *lvds_lfp_data,
|
||||||
|
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs)
|
||||||
{
|
{
|
||||||
const struct bdb_lvds_lfp_data *lvds_lfp_data;
|
|
||||||
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
|
|
||||||
const struct lvds_dvo_timing *panel_dvo_timing;
|
const struct lvds_dvo_timing *panel_dvo_timing;
|
||||||
const struct lvds_fp_timing *fp_timing;
|
const struct lvds_fp_timing *fp_timing;
|
||||||
struct drm_display_mode *panel_fixed_mode;
|
struct drm_display_mode *panel_fixed_mode;
|
||||||
int panel_type = i915->vbt.panel_type;
|
int panel_type = i915->vbt.panel_type;
|
||||||
|
|
||||||
lvds_lfp_data = find_section(i915, BDB_LVDS_LFP_DATA);
|
|
||||||
if (!lvds_lfp_data)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lvds_lfp_data_ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
|
|
||||||
if (!lvds_lfp_data_ptrs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||||
lvds_lfp_data_ptrs,
|
lvds_lfp_data_ptrs,
|
||||||
panel_type);
|
panel_type);
|
||||||
@ -538,6 +756,38 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_lfp_data(struct drm_i915_private *i915)
|
||||||
|
{
|
||||||
|
const struct bdb_lvds_lfp_data *data;
|
||||||
|
const struct bdb_lvds_lfp_data_tail *tail;
|
||||||
|
const struct bdb_lvds_lfp_data_ptrs *ptrs;
|
||||||
|
int panel_type = i915->vbt.panel_type;
|
||||||
|
|
||||||
|
ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
|
||||||
|
if (!ptrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data = find_section(i915, BDB_LVDS_LFP_DATA);
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!i915->vbt.lfp_lvds_vbt_mode)
|
||||||
|
parse_lfp_panel_dtd(i915, data, ptrs);
|
||||||
|
|
||||||
|
tail = get_lfp_data_tail(data, ptrs);
|
||||||
|
if (!tail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (i915->vbt.version >= 188) {
|
||||||
|
i915->vbt.seamless_drrs_min_refresh_rate =
|
||||||
|
tail->seamless_drrs_min_refresh_rate[panel_type];
|
||||||
|
drm_dbg_kms(&i915->drm,
|
||||||
|
"Seamless DRRS min refresh rate: %d Hz\n",
|
||||||
|
i915->vbt.seamless_drrs_min_refresh_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
parse_generic_dtd(struct drm_i915_private *i915)
|
parse_generic_dtd(struct drm_i915_private *i915)
|
||||||
{
|
{
|
||||||
@ -546,6 +796,17 @@ parse_generic_dtd(struct drm_i915_private *i915)
|
|||||||
struct drm_display_mode *panel_fixed_mode;
|
struct drm_display_mode *panel_fixed_mode;
|
||||||
int num_dtd;
|
int num_dtd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Older VBTs provided DTD information for internal displays through
|
||||||
|
* the "LFP panel tables" block (42). As of VBT revision 229 the
|
||||||
|
* DTD information should be provided via a newer "generic DTD"
|
||||||
|
* block (58). Just to be safe, we'll try the new generic DTD block
|
||||||
|
* first on VBT >= 229, but still fall back to trying the old LFP
|
||||||
|
* block if that fails.
|
||||||
|
*/
|
||||||
|
if (i915->vbt.version < 229)
|
||||||
|
return;
|
||||||
|
|
||||||
generic_dtd = find_section(i915, BDB_GENERIC_DTD);
|
generic_dtd = find_section(i915, BDB_GENERIC_DTD);
|
||||||
if (!generic_dtd)
|
if (!generic_dtd)
|
||||||
return;
|
return;
|
||||||
@ -616,23 +877,6 @@ parse_generic_dtd(struct drm_i915_private *i915)
|
|||||||
i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
|
i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
parse_panel_dtd(struct drm_i915_private *i915)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Older VBTs provided provided DTD information for internal displays
|
|
||||||
* through the "LFP panel DTD" block (42). As of VBT revision 229,
|
|
||||||
* that block is now deprecated and DTD information should be provided
|
|
||||||
* via a newer "generic DTD" block (58). Just to be safe, we'll
|
|
||||||
* try the new generic DTD block first on VBT >= 229, but still fall
|
|
||||||
* back to trying the old LFP block if that fails.
|
|
||||||
*/
|
|
||||||
if (i915->vbt.version >= 229)
|
|
||||||
parse_generic_dtd(i915);
|
|
||||||
if (!i915->vbt.lfp_lvds_vbt_mode)
|
|
||||||
parse_lfp_panel_dtd(i915);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
parse_lfp_backlight(struct drm_i915_private *i915)
|
parse_lfp_backlight(struct drm_i915_private *i915)
|
||||||
{
|
{
|
||||||
@ -2709,7 +2953,8 @@ void intel_bios_init(struct drm_i915_private *i915)
|
|||||||
parse_general_features(i915);
|
parse_general_features(i915);
|
||||||
parse_general_definitions(i915);
|
parse_general_definitions(i915);
|
||||||
parse_panel_options(i915);
|
parse_panel_options(i915);
|
||||||
parse_panel_dtd(i915);
|
parse_generic_dtd(i915);
|
||||||
|
parse_lfp_data(i915);
|
||||||
parse_lfp_backlight(i915);
|
parse_lfp_backlight(i915);
|
||||||
parse_sdvo_panel_data(i915);
|
parse_sdvo_panel_data(i915);
|
||||||
parse_driver_features(i915);
|
parse_driver_features(i915);
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "intel_ddi.h"
|
#include "intel_ddi.h"
|
||||||
#include "intel_ddi_buf_trans.h"
|
#include "intel_ddi_buf_trans.h"
|
||||||
#include "intel_de.h"
|
#include "intel_de.h"
|
||||||
|
#include "intel_display_power.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dp.h"
|
#include "intel_dp.h"
|
||||||
#include "intel_dp_link_training.h"
|
#include "intel_dp_link_training.h"
|
||||||
@ -4364,7 +4365,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
|||||||
encoder->get_power_domains = intel_ddi_get_power_domains;
|
encoder->get_power_domains = intel_ddi_get_power_domains;
|
||||||
|
|
||||||
encoder->type = INTEL_OUTPUT_DDI;
|
encoder->type = INTEL_OUTPUT_DDI;
|
||||||
encoder->power_domain = intel_port_to_power_domain(port);
|
encoder->power_domain = intel_display_power_ddi_lanes_domain(dev_priv, port);
|
||||||
encoder->port = port;
|
encoder->port = port;
|
||||||
encoder->cloneable = 0;
|
encoder->cloneable = 0;
|
||||||
encoder->pipe_mask = ~0;
|
encoder->pipe_mask = ~0;
|
||||||
@ -4492,8 +4493,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
drm_WARN_ON(&dev_priv->drm, port > PORT_I);
|
drm_WARN_ON(&dev_priv->drm, port > PORT_I);
|
||||||
dig_port->ddi_io_power_domain = POWER_DOMAIN_PORT_DDI_A_IO +
|
dig_port->ddi_io_power_domain = intel_display_power_ddi_io_domain(dev_priv, port);
|
||||||
port - PORT_A;
|
|
||||||
|
|
||||||
if (init_dp) {
|
if (init_dp) {
|
||||||
if (!intel_ddi_init_dp_connector(dig_port))
|
if (!intel_ddi_init_dp_connector(dig_port))
|
||||||
|
@ -1673,7 +1673,9 @@ void intel_ddi_buf_trans_init(struct intel_encoder *encoder)
|
|||||||
encoder->get_buf_trans = skl_get_buf_trans;
|
encoder->get_buf_trans = skl_get_buf_trans;
|
||||||
} else if (IS_BROADWELL(i915)) {
|
} else if (IS_BROADWELL(i915)) {
|
||||||
encoder->get_buf_trans = bdw_get_buf_trans;
|
encoder->get_buf_trans = bdw_get_buf_trans;
|
||||||
} else {
|
} else if (IS_HASWELL(i915)) {
|
||||||
encoder->get_buf_trans = hsw_get_buf_trans;
|
encoder->get_buf_trans = hsw_get_buf_trans;
|
||||||
|
} else {
|
||||||
|
MISSING_CASE(INTEL_INFO(i915)->platform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "display/intel_crt.h"
|
#include "display/intel_crt.h"
|
||||||
#include "display/intel_ddi.h"
|
#include "display/intel_ddi.h"
|
||||||
#include "display/intel_display_debugfs.h"
|
#include "display/intel_display_debugfs.h"
|
||||||
|
#include "display/intel_display_power.h"
|
||||||
#include "display/intel_dp.h"
|
#include "display/intel_dp.h"
|
||||||
#include "display/intel_dp_mst.h"
|
#include "display/intel_dp_mst.h"
|
||||||
#include "display/intel_dpll.h"
|
#include "display/intel_dpll.h"
|
||||||
@ -2157,153 +2158,82 @@ enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, enum port port)
|
|||||||
return TC_PORT_1 + port - PORT_C;
|
return TC_PORT_1 + port - PORT_C;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum intel_display_power_domain intel_port_to_power_domain(enum port port)
|
|
||||||
{
|
|
||||||
switch (port) {
|
|
||||||
case PORT_A:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_A_LANES;
|
|
||||||
case PORT_B:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_B_LANES;
|
|
||||||
case PORT_C:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_C_LANES;
|
|
||||||
case PORT_D:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_D_LANES;
|
|
||||||
case PORT_E:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_E_LANES;
|
|
||||||
case PORT_F:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_F_LANES;
|
|
||||||
case PORT_G:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_G_LANES;
|
|
||||||
case PORT_H:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_H_LANES;
|
|
||||||
case PORT_I:
|
|
||||||
return POWER_DOMAIN_PORT_DDI_I_LANES;
|
|
||||||
default:
|
|
||||||
MISSING_CASE(port);
|
|
||||||
return POWER_DOMAIN_PORT_OTHER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum intel_display_power_domain
|
enum intel_display_power_domain
|
||||||
intel_aux_power_domain(struct intel_digital_port *dig_port)
|
intel_aux_power_domain(struct intel_digital_port *dig_port)
|
||||||
{
|
{
|
||||||
if (intel_tc_port_in_tbt_alt_mode(dig_port)) {
|
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||||
switch (dig_port->aux_ch) {
|
|
||||||
case AUX_CH_C:
|
|
||||||
return POWER_DOMAIN_AUX_C_TBT;
|
|
||||||
case AUX_CH_D:
|
|
||||||
return POWER_DOMAIN_AUX_D_TBT;
|
|
||||||
case AUX_CH_E:
|
|
||||||
return POWER_DOMAIN_AUX_E_TBT;
|
|
||||||
case AUX_CH_F:
|
|
||||||
return POWER_DOMAIN_AUX_F_TBT;
|
|
||||||
case AUX_CH_G:
|
|
||||||
return POWER_DOMAIN_AUX_G_TBT;
|
|
||||||
case AUX_CH_H:
|
|
||||||
return POWER_DOMAIN_AUX_H_TBT;
|
|
||||||
case AUX_CH_I:
|
|
||||||
return POWER_DOMAIN_AUX_I_TBT;
|
|
||||||
default:
|
|
||||||
MISSING_CASE(dig_port->aux_ch);
|
|
||||||
return POWER_DOMAIN_AUX_C_TBT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intel_legacy_aux_to_power_domain(dig_port->aux_ch);
|
if (intel_tc_port_in_tbt_alt_mode(dig_port))
|
||||||
|
return intel_display_power_tbt_aux_domain(i915, dig_port->aux_ch);
|
||||||
|
|
||||||
|
return intel_display_power_legacy_aux_domain(i915, dig_port->aux_ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void get_crtc_power_domains(struct intel_crtc_state *crtc_state,
|
||||||
* Converts aux_ch to power_domain without caring about TBT ports for that use
|
struct intel_power_domain_mask *mask)
|
||||||
* intel_aux_power_domain()
|
|
||||||
*/
|
|
||||||
enum intel_display_power_domain
|
|
||||||
intel_legacy_aux_to_power_domain(enum aux_ch aux_ch)
|
|
||||||
{
|
|
||||||
switch (aux_ch) {
|
|
||||||
case AUX_CH_A:
|
|
||||||
return POWER_DOMAIN_AUX_A;
|
|
||||||
case AUX_CH_B:
|
|
||||||
return POWER_DOMAIN_AUX_B;
|
|
||||||
case AUX_CH_C:
|
|
||||||
return POWER_DOMAIN_AUX_C;
|
|
||||||
case AUX_CH_D:
|
|
||||||
return POWER_DOMAIN_AUX_D;
|
|
||||||
case AUX_CH_E:
|
|
||||||
return POWER_DOMAIN_AUX_E;
|
|
||||||
case AUX_CH_F:
|
|
||||||
return POWER_DOMAIN_AUX_F;
|
|
||||||
case AUX_CH_G:
|
|
||||||
return POWER_DOMAIN_AUX_G;
|
|
||||||
case AUX_CH_H:
|
|
||||||
return POWER_DOMAIN_AUX_H;
|
|
||||||
case AUX_CH_I:
|
|
||||||
return POWER_DOMAIN_AUX_I;
|
|
||||||
default:
|
|
||||||
MISSING_CASE(aux_ch);
|
|
||||||
return POWER_DOMAIN_AUX_A;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 get_crtc_power_domains(struct intel_crtc_state *crtc_state)
|
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
enum pipe pipe = crtc->pipe;
|
enum pipe pipe = crtc->pipe;
|
||||||
u64 mask;
|
|
||||||
|
bitmap_zero(mask->bits, POWER_DOMAIN_NUM);
|
||||||
|
|
||||||
if (!crtc_state->hw.active)
|
if (!crtc_state->hw.active)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
mask = BIT_ULL(POWER_DOMAIN_PIPE(pipe));
|
set_bit(POWER_DOMAIN_PIPE(pipe), mask->bits);
|
||||||
mask |= BIT_ULL(POWER_DOMAIN_TRANSCODER(cpu_transcoder));
|
set_bit(POWER_DOMAIN_TRANSCODER(cpu_transcoder), mask->bits);
|
||||||
if (crtc_state->pch_pfit.enabled ||
|
if (crtc_state->pch_pfit.enabled ||
|
||||||
crtc_state->pch_pfit.force_thru)
|
crtc_state->pch_pfit.force_thru)
|
||||||
mask |= BIT_ULL(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
|
set_bit(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe), mask->bits);
|
||||||
|
|
||||||
drm_for_each_encoder_mask(encoder, &dev_priv->drm,
|
drm_for_each_encoder_mask(encoder, &dev_priv->drm,
|
||||||
crtc_state->uapi.encoder_mask) {
|
crtc_state->uapi.encoder_mask) {
|
||||||
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
||||||
|
|
||||||
mask |= BIT_ULL(intel_encoder->power_domain);
|
set_bit(intel_encoder->power_domain, mask->bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_DDI(dev_priv) && crtc_state->has_audio)
|
if (HAS_DDI(dev_priv) && crtc_state->has_audio)
|
||||||
mask |= BIT_ULL(POWER_DOMAIN_AUDIO_MMIO);
|
set_bit(POWER_DOMAIN_AUDIO_MMIO, mask->bits);
|
||||||
|
|
||||||
if (crtc_state->shared_dpll)
|
if (crtc_state->shared_dpll)
|
||||||
mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE);
|
set_bit(POWER_DOMAIN_DISPLAY_CORE, mask->bits);
|
||||||
|
|
||||||
if (crtc_state->dsc.compression_enable)
|
if (crtc_state->dsc.compression_enable)
|
||||||
mask |= BIT_ULL(intel_dsc_power_domain(crtc, cpu_transcoder));
|
set_bit(intel_dsc_power_domain(crtc, cpu_transcoder), mask->bits);
|
||||||
|
|
||||||
return mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64
|
static void
|
||||||
modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state)
|
modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state,
|
||||||
|
struct intel_power_domain_mask *old_domains)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
enum intel_display_power_domain domain;
|
enum intel_display_power_domain domain;
|
||||||
u64 domains, new_domains, old_domains;
|
struct intel_power_domain_mask domains, new_domains;
|
||||||
|
|
||||||
domains = get_crtc_power_domains(crtc_state);
|
get_crtc_power_domains(crtc_state, &domains);
|
||||||
|
|
||||||
new_domains = domains & ~crtc->enabled_power_domains.mask;
|
bitmap_andnot(new_domains.bits,
|
||||||
old_domains = crtc->enabled_power_domains.mask & ~domains;
|
domains.bits,
|
||||||
|
crtc->enabled_power_domains.mask.bits,
|
||||||
|
POWER_DOMAIN_NUM);
|
||||||
|
bitmap_andnot(old_domains->bits,
|
||||||
|
crtc->enabled_power_domains.mask.bits,
|
||||||
|
domains.bits,
|
||||||
|
POWER_DOMAIN_NUM);
|
||||||
|
|
||||||
for_each_power_domain(domain, new_domains)
|
for_each_power_domain(domain, &new_domains)
|
||||||
intel_display_power_get_in_set(dev_priv,
|
intel_display_power_get_in_set(dev_priv,
|
||||||
&crtc->enabled_power_domains,
|
&crtc->enabled_power_domains,
|
||||||
domain);
|
domain);
|
||||||
|
|
||||||
return old_domains;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void modeset_put_crtc_power_domains(struct intel_crtc *crtc,
|
static void modeset_put_crtc_power_domains(struct intel_crtc *crtc,
|
||||||
u64 domains)
|
struct intel_power_domain_mask *domains)
|
||||||
{
|
{
|
||||||
intel_display_power_put_mask_in_set(to_i915(crtc->base.dev),
|
intel_display_power_put_mask_in_set(to_i915(crtc->base.dev),
|
||||||
&crtc->enabled_power_domains,
|
&crtc->enabled_power_domains,
|
||||||
@ -4974,9 +4904,12 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
|
|||||||
mode_changed && !crtc_state->hw.active)
|
mode_changed && !crtc_state->hw.active)
|
||||||
crtc_state->update_wm_post = true;
|
crtc_state->update_wm_post = true;
|
||||||
|
|
||||||
if (mode_changed && crtc_state->hw.enable &&
|
if (mode_changed) {
|
||||||
!drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll)) {
|
ret = intel_dpll_crtc_compute_clock(state, crtc);
|
||||||
ret = intel_dpll_crtc_compute_clock(crtc_state);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = intel_dpll_crtc_get_shared_dpll(state, crtc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -6969,8 +6902,9 @@ intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state)
|
|||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
struct drm_display_mode adjusted_mode =
|
struct drm_display_mode adjusted_mode;
|
||||||
crtc_state->hw.adjusted_mode;
|
|
||||||
|
drm_mode_init(&adjusted_mode, &crtc_state->hw.adjusted_mode);
|
||||||
|
|
||||||
if (crtc_state->vrr.enable) {
|
if (crtc_state->vrr.enable) {
|
||||||
adjusted_mode.crtc_vtotal = crtc_state->vrr.vmax;
|
adjusted_mode.crtc_vtotal = crtc_state->vrr.vmax;
|
||||||
@ -7028,14 +6962,10 @@ intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state)
|
|||||||
|
|
||||||
static void intel_modeset_clear_plls(struct intel_atomic_state *state)
|
static void intel_modeset_clear_plls(struct intel_atomic_state *state)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
||||||
struct intel_crtc_state *new_crtc_state;
|
struct intel_crtc_state *new_crtc_state;
|
||||||
struct intel_crtc *crtc;
|
struct intel_crtc *crtc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!dev_priv->dpll_funcs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||||
if (!intel_crtc_needs_modeset(new_crtc_state))
|
if (!intel_crtc_needs_modeset(new_crtc_state))
|
||||||
continue;
|
continue;
|
||||||
@ -8505,7 +8435,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
|
|||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
struct intel_crtc_state *new_crtc_state, *old_crtc_state;
|
struct intel_crtc_state *new_crtc_state, *old_crtc_state;
|
||||||
struct intel_crtc *crtc;
|
struct intel_crtc *crtc;
|
||||||
u64 put_domains[I915_MAX_PIPES] = {};
|
struct intel_power_domain_mask put_domains[I915_MAX_PIPES] = {};
|
||||||
intel_wakeref_t wakeref = 0;
|
intel_wakeref_t wakeref = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -8522,9 +8452,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
|
|||||||
new_crtc_state, i) {
|
new_crtc_state, i) {
|
||||||
if (intel_crtc_needs_modeset(new_crtc_state) ||
|
if (intel_crtc_needs_modeset(new_crtc_state) ||
|
||||||
new_crtc_state->update_pipe) {
|
new_crtc_state->update_pipe) {
|
||||||
|
modeset_get_crtc_power_domains(new_crtc_state, &put_domains[crtc->pipe]);
|
||||||
put_domains[crtc->pipe] =
|
|
||||||
modeset_get_crtc_power_domains(new_crtc_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8624,7 +8552,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
|
|||||||
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
||||||
intel_post_plane_update(state, crtc);
|
intel_post_plane_update(state, crtc);
|
||||||
|
|
||||||
modeset_put_crtc_power_domains(crtc, put_domains[crtc->pipe]);
|
modeset_put_crtc_power_domains(crtc, &put_domains[crtc->pipe]);
|
||||||
|
|
||||||
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
|
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
|
||||||
|
|
||||||
@ -9737,7 +9665,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
|
|||||||
}
|
}
|
||||||
|
|
||||||
intel_plane_possible_crtcs_init(i915);
|
intel_plane_possible_crtcs_init(i915);
|
||||||
intel_shared_dpll_init(dev);
|
intel_shared_dpll_init(i915);
|
||||||
intel_fdi_pll_freq_update(i915);
|
intel_fdi_pll_freq_update(i915);
|
||||||
|
|
||||||
intel_update_czclk(i915);
|
intel_update_czclk(i915);
|
||||||
@ -9844,9 +9772,6 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|||||||
PLL_REF_INPUT_DREFCLK |
|
PLL_REF_INPUT_DREFCLK |
|
||||||
DPLL_VCO_ENABLE;
|
DPLL_VCO_ENABLE;
|
||||||
|
|
||||||
intel_de_write(dev_priv, FP0(pipe), fp);
|
|
||||||
intel_de_write(dev_priv, FP1(pipe), fp);
|
|
||||||
|
|
||||||
intel_de_write(dev_priv, HTOTAL(pipe), (640 - 1) | ((800 - 1) << 16));
|
intel_de_write(dev_priv, HTOTAL(pipe), (640 - 1) | ((800 - 1) << 16));
|
||||||
intel_de_write(dev_priv, HBLANK(pipe), (640 - 1) | ((800 - 1) << 16));
|
intel_de_write(dev_priv, HBLANK(pipe), (640 - 1) | ((800 - 1) << 16));
|
||||||
intel_de_write(dev_priv, HSYNC(pipe), (656 - 1) | ((752 - 1) << 16));
|
intel_de_write(dev_priv, HSYNC(pipe), (656 - 1) | ((752 - 1) << 16));
|
||||||
@ -9855,6 +9780,9 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|||||||
intel_de_write(dev_priv, VSYNC(pipe), (490 - 1) | ((492 - 1) << 16));
|
intel_de_write(dev_priv, VSYNC(pipe), (490 - 1) | ((492 - 1) << 16));
|
||||||
intel_de_write(dev_priv, PIPESRC(pipe), ((640 - 1) << 16) | (480 - 1));
|
intel_de_write(dev_priv, PIPESRC(pipe), ((640 - 1) << 16) | (480 - 1));
|
||||||
|
|
||||||
|
intel_de_write(dev_priv, FP0(pipe), fp);
|
||||||
|
intel_de_write(dev_priv, FP1(pipe), fp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apparently we need to have VGA mode enabled prior to changing
|
* Apparently we need to have VGA mode enabled prior to changing
|
||||||
* the P1/P2 dividers. Otherwise the DPLL will keep using the old
|
* the P1/P2 dividers. Otherwise the DPLL will keep using the old
|
||||||
@ -10465,11 +10393,11 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
|
|||||||
for_each_intel_crtc(dev, crtc) {
|
for_each_intel_crtc(dev, crtc) {
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
to_intel_crtc_state(crtc->base.state);
|
to_intel_crtc_state(crtc->base.state);
|
||||||
u64 put_domains;
|
struct intel_power_domain_mask put_domains;
|
||||||
|
|
||||||
put_domains = modeset_get_crtc_power_domains(crtc_state);
|
modeset_get_crtc_power_domains(crtc_state, &put_domains);
|
||||||
if (drm_WARN_ON(dev, put_domains))
|
if (drm_WARN_ON(dev, !bitmap_empty(put_domains.bits, POWER_DOMAIN_NUM)))
|
||||||
modeset_put_crtc_power_domains(crtc, put_domains);
|
modeset_put_crtc_power_domains(crtc, &put_domains);
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
|
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
|
||||||
|
@ -635,11 +635,9 @@ void intel_cpu_transcoder_get_m2_n2(struct intel_crtc *crtc,
|
|||||||
void i9xx_crtc_clock_get(struct intel_crtc *crtc,
|
void i9xx_crtc_clock_get(struct intel_crtc *crtc,
|
||||||
struct intel_crtc_state *pipe_config);
|
struct intel_crtc_state *pipe_config);
|
||||||
int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
|
int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
|
||||||
enum intel_display_power_domain intel_port_to_power_domain(enum port port);
|
enum intel_display_power_domain intel_port_to_power_domain(struct intel_digital_port *dig_port);
|
||||||
enum intel_display_power_domain
|
enum intel_display_power_domain
|
||||||
intel_aux_power_domain(struct intel_digital_port *dig_port);
|
intel_aux_power_domain(struct intel_digital_port *dig_port);
|
||||||
enum intel_display_power_domain
|
|
||||||
intel_legacy_aux_to_power_domain(enum aux_ch aux_ch);
|
|
||||||
void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
|
void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
|
||||||
struct intel_crtc_state *crtc_state);
|
struct intel_crtc_state *crtc_state);
|
||||||
void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
|
void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,10 @@
|
|||||||
|
|
||||||
#include "intel_runtime_pm.h"
|
#include "intel_runtime_pm.h"
|
||||||
|
|
||||||
|
enum aux_ch;
|
||||||
enum dpio_channel;
|
enum dpio_channel;
|
||||||
enum dpio_phy;
|
enum dpio_phy;
|
||||||
|
enum port;
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
struct i915_power_well;
|
struct i915_power_well;
|
||||||
struct intel_encoder;
|
struct intel_encoder;
|
||||||
@ -25,10 +27,10 @@ enum intel_display_power_domain {
|
|||||||
POWER_DOMAIN_PIPE_B,
|
POWER_DOMAIN_PIPE_B,
|
||||||
POWER_DOMAIN_PIPE_C,
|
POWER_DOMAIN_PIPE_C,
|
||||||
POWER_DOMAIN_PIPE_D,
|
POWER_DOMAIN_PIPE_D,
|
||||||
POWER_DOMAIN_PIPE_A_PANEL_FITTER,
|
POWER_DOMAIN_PIPE_PANEL_FITTER_A,
|
||||||
POWER_DOMAIN_PIPE_B_PANEL_FITTER,
|
POWER_DOMAIN_PIPE_PANEL_FITTER_B,
|
||||||
POWER_DOMAIN_PIPE_C_PANEL_FITTER,
|
POWER_DOMAIN_PIPE_PANEL_FITTER_C,
|
||||||
POWER_DOMAIN_PIPE_D_PANEL_FITTER,
|
POWER_DOMAIN_PIPE_PANEL_FITTER_D,
|
||||||
POWER_DOMAIN_TRANSCODER_A,
|
POWER_DOMAIN_TRANSCODER_A,
|
||||||
POWER_DOMAIN_TRANSCODER_B,
|
POWER_DOMAIN_TRANSCODER_B,
|
||||||
POWER_DOMAIN_TRANSCODER_C,
|
POWER_DOMAIN_TRANSCODER_C,
|
||||||
@ -40,46 +42,34 @@ enum intel_display_power_domain {
|
|||||||
/* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */
|
/* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */
|
||||||
POWER_DOMAIN_TRANSCODER_VDSC_PW2,
|
POWER_DOMAIN_TRANSCODER_VDSC_PW2,
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DDI_A_LANES,
|
POWER_DOMAIN_PORT_DDI_LANES_A,
|
||||||
POWER_DOMAIN_PORT_DDI_B_LANES,
|
POWER_DOMAIN_PORT_DDI_LANES_B,
|
||||||
POWER_DOMAIN_PORT_DDI_C_LANES,
|
POWER_DOMAIN_PORT_DDI_LANES_C,
|
||||||
POWER_DOMAIN_PORT_DDI_D_LANES,
|
POWER_DOMAIN_PORT_DDI_LANES_D,
|
||||||
POWER_DOMAIN_PORT_DDI_E_LANES,
|
POWER_DOMAIN_PORT_DDI_LANES_E,
|
||||||
POWER_DOMAIN_PORT_DDI_F_LANES,
|
POWER_DOMAIN_PORT_DDI_LANES_F,
|
||||||
POWER_DOMAIN_PORT_DDI_G_LANES,
|
|
||||||
POWER_DOMAIN_PORT_DDI_H_LANES,
|
|
||||||
POWER_DOMAIN_PORT_DDI_I_LANES,
|
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_TC1 = POWER_DOMAIN_PORT_DDI_D_LANES, /* tgl+ */
|
POWER_DOMAIN_PORT_DDI_LANES_TC1,
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_TC2,
|
POWER_DOMAIN_PORT_DDI_LANES_TC2,
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_TC3,
|
POWER_DOMAIN_PORT_DDI_LANES_TC3,
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_TC4,
|
POWER_DOMAIN_PORT_DDI_LANES_TC4,
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_TC5,
|
POWER_DOMAIN_PORT_DDI_LANES_TC5,
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_TC6,
|
POWER_DOMAIN_PORT_DDI_LANES_TC6,
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_D_XELPD = POWER_DOMAIN_PORT_DDI_LANES_TC5, /* XELPD */
|
POWER_DOMAIN_PORT_DDI_IO_A,
|
||||||
POWER_DOMAIN_PORT_DDI_LANES_E_XELPD,
|
POWER_DOMAIN_PORT_DDI_IO_B,
|
||||||
|
POWER_DOMAIN_PORT_DDI_IO_C,
|
||||||
|
POWER_DOMAIN_PORT_DDI_IO_D,
|
||||||
|
POWER_DOMAIN_PORT_DDI_IO_E,
|
||||||
|
POWER_DOMAIN_PORT_DDI_IO_F,
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DDI_A_IO,
|
POWER_DOMAIN_PORT_DDI_IO_TC1,
|
||||||
POWER_DOMAIN_PORT_DDI_B_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_C_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_D_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_E_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_F_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_G_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_H_IO,
|
|
||||||
POWER_DOMAIN_PORT_DDI_I_IO,
|
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DDI_IO_TC1 = POWER_DOMAIN_PORT_DDI_D_IO, /* tgl+ */
|
|
||||||
POWER_DOMAIN_PORT_DDI_IO_TC2,
|
POWER_DOMAIN_PORT_DDI_IO_TC2,
|
||||||
POWER_DOMAIN_PORT_DDI_IO_TC3,
|
POWER_DOMAIN_PORT_DDI_IO_TC3,
|
||||||
POWER_DOMAIN_PORT_DDI_IO_TC4,
|
POWER_DOMAIN_PORT_DDI_IO_TC4,
|
||||||
POWER_DOMAIN_PORT_DDI_IO_TC5,
|
POWER_DOMAIN_PORT_DDI_IO_TC5,
|
||||||
POWER_DOMAIN_PORT_DDI_IO_TC6,
|
POWER_DOMAIN_PORT_DDI_IO_TC6,
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DDI_IO_D_XELPD = POWER_DOMAIN_PORT_DDI_IO_TC5, /* XELPD */
|
|
||||||
POWER_DOMAIN_PORT_DDI_IO_E_XELPD,
|
|
||||||
|
|
||||||
POWER_DOMAIN_PORT_DSI,
|
POWER_DOMAIN_PORT_DSI,
|
||||||
POWER_DOMAIN_PORT_CRT,
|
POWER_DOMAIN_PORT_CRT,
|
||||||
POWER_DOMAIN_PORT_OTHER,
|
POWER_DOMAIN_PORT_OTHER,
|
||||||
@ -92,30 +82,17 @@ enum intel_display_power_domain {
|
|||||||
POWER_DOMAIN_AUX_D,
|
POWER_DOMAIN_AUX_D,
|
||||||
POWER_DOMAIN_AUX_E,
|
POWER_DOMAIN_AUX_E,
|
||||||
POWER_DOMAIN_AUX_F,
|
POWER_DOMAIN_AUX_F,
|
||||||
POWER_DOMAIN_AUX_G,
|
|
||||||
POWER_DOMAIN_AUX_H,
|
|
||||||
POWER_DOMAIN_AUX_I,
|
|
||||||
|
|
||||||
POWER_DOMAIN_AUX_USBC1 = POWER_DOMAIN_AUX_D, /* tgl+ */
|
POWER_DOMAIN_AUX_USBC1,
|
||||||
POWER_DOMAIN_AUX_USBC2,
|
POWER_DOMAIN_AUX_USBC2,
|
||||||
POWER_DOMAIN_AUX_USBC3,
|
POWER_DOMAIN_AUX_USBC3,
|
||||||
POWER_DOMAIN_AUX_USBC4,
|
POWER_DOMAIN_AUX_USBC4,
|
||||||
POWER_DOMAIN_AUX_USBC5,
|
POWER_DOMAIN_AUX_USBC5,
|
||||||
POWER_DOMAIN_AUX_USBC6,
|
POWER_DOMAIN_AUX_USBC6,
|
||||||
|
|
||||||
POWER_DOMAIN_AUX_D_XELPD = POWER_DOMAIN_AUX_USBC5, /* XELPD */
|
|
||||||
POWER_DOMAIN_AUX_E_XELPD,
|
|
||||||
|
|
||||||
POWER_DOMAIN_AUX_IO_A,
|
POWER_DOMAIN_AUX_IO_A,
|
||||||
POWER_DOMAIN_AUX_C_TBT,
|
|
||||||
POWER_DOMAIN_AUX_D_TBT,
|
|
||||||
POWER_DOMAIN_AUX_E_TBT,
|
|
||||||
POWER_DOMAIN_AUX_F_TBT,
|
|
||||||
POWER_DOMAIN_AUX_G_TBT,
|
|
||||||
POWER_DOMAIN_AUX_H_TBT,
|
|
||||||
POWER_DOMAIN_AUX_I_TBT,
|
|
||||||
|
|
||||||
POWER_DOMAIN_AUX_TBT1 = POWER_DOMAIN_AUX_D_TBT, /* tgl+ */
|
POWER_DOMAIN_AUX_TBT1,
|
||||||
POWER_DOMAIN_AUX_TBT2,
|
POWER_DOMAIN_AUX_TBT2,
|
||||||
POWER_DOMAIN_AUX_TBT3,
|
POWER_DOMAIN_AUX_TBT3,
|
||||||
POWER_DOMAIN_AUX_TBT4,
|
POWER_DOMAIN_AUX_TBT4,
|
||||||
@ -130,15 +107,20 @@ enum intel_display_power_domain {
|
|||||||
POWER_DOMAIN_INIT,
|
POWER_DOMAIN_INIT,
|
||||||
|
|
||||||
POWER_DOMAIN_NUM,
|
POWER_DOMAIN_NUM,
|
||||||
|
POWER_DOMAIN_INVALID = POWER_DOMAIN_NUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
|
#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
|
||||||
#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
|
#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
|
||||||
((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER)
|
((pipe) + POWER_DOMAIN_PIPE_PANEL_FITTER_A)
|
||||||
#define POWER_DOMAIN_TRANSCODER(tran) \
|
#define POWER_DOMAIN_TRANSCODER(tran) \
|
||||||
((tran) == TRANSCODER_EDP ? POWER_DOMAIN_TRANSCODER_EDP : \
|
((tran) == TRANSCODER_EDP ? POWER_DOMAIN_TRANSCODER_EDP : \
|
||||||
(tran) + POWER_DOMAIN_TRANSCODER_A)
|
(tran) + POWER_DOMAIN_TRANSCODER_A)
|
||||||
|
|
||||||
|
struct intel_power_domain_mask {
|
||||||
|
DECLARE_BITMAP(bits, POWER_DOMAIN_NUM);
|
||||||
|
};
|
||||||
|
|
||||||
struct i915_power_domains {
|
struct i915_power_domains {
|
||||||
/*
|
/*
|
||||||
* Power wells needed for initialization at driver init and suspend
|
* Power wells needed for initialization at driver init and suspend
|
||||||
@ -156,41 +138,21 @@ struct i915_power_domains {
|
|||||||
|
|
||||||
struct delayed_work async_put_work;
|
struct delayed_work async_put_work;
|
||||||
intel_wakeref_t async_put_wakeref;
|
intel_wakeref_t async_put_wakeref;
|
||||||
u64 async_put_domains[2];
|
struct intel_power_domain_mask async_put_domains[2];
|
||||||
|
|
||||||
struct i915_power_well *power_wells;
|
struct i915_power_well *power_wells;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intel_display_power_domain_set {
|
struct intel_display_power_domain_set {
|
||||||
u64 mask;
|
struct intel_power_domain_mask mask;
|
||||||
#ifdef CONFIG_DRM_I915_DEBUG_RUNTIME_PM
|
#ifdef CONFIG_DRM_I915_DEBUG_RUNTIME_PM
|
||||||
intel_wakeref_t wakerefs[POWER_DOMAIN_NUM];
|
intel_wakeref_t wakerefs[POWER_DOMAIN_NUM];
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define for_each_power_domain(domain, mask) \
|
#define for_each_power_domain(__domain, __mask) \
|
||||||
for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \
|
for ((__domain) = 0; (__domain) < POWER_DOMAIN_NUM; (__domain)++) \
|
||||||
for_each_if(BIT_ULL(domain) & (mask))
|
for_each_if(test_bit((__domain), (__mask)->bits))
|
||||||
|
|
||||||
#define for_each_power_well(__dev_priv, __power_well) \
|
|
||||||
for ((__power_well) = (__dev_priv)->power_domains.power_wells; \
|
|
||||||
(__power_well) - (__dev_priv)->power_domains.power_wells < \
|
|
||||||
(__dev_priv)->power_domains.power_well_count; \
|
|
||||||
(__power_well)++)
|
|
||||||
|
|
||||||
#define for_each_power_well_reverse(__dev_priv, __power_well) \
|
|
||||||
for ((__power_well) = (__dev_priv)->power_domains.power_wells + \
|
|
||||||
(__dev_priv)->power_domains.power_well_count - 1; \
|
|
||||||
(__power_well) - (__dev_priv)->power_domains.power_wells >= 0; \
|
|
||||||
(__power_well)--)
|
|
||||||
|
|
||||||
#define for_each_power_domain_well(__dev_priv, __power_well, __domain_mask) \
|
|
||||||
for_each_power_well(__dev_priv, __power_well) \
|
|
||||||
for_each_if((__power_well)->desc->domains & (__domain_mask))
|
|
||||||
|
|
||||||
#define for_each_power_domain_well_reverse(__dev_priv, __power_well, __domain_mask) \
|
|
||||||
for_each_power_well_reverse(__dev_priv, __power_well) \
|
|
||||||
for_each_if((__power_well)->desc->domains & (__domain_mask))
|
|
||||||
|
|
||||||
int intel_power_domains_init(struct drm_i915_private *dev_priv);
|
int intel_power_domains_init(struct drm_i915_private *dev_priv);
|
||||||
void intel_power_domains_cleanup(struct drm_i915_private *dev_priv);
|
void intel_power_domains_cleanup(struct drm_i915_private *dev_priv);
|
||||||
@ -271,17 +233,26 @@ intel_display_power_get_in_set_if_enabled(struct drm_i915_private *i915,
|
|||||||
void
|
void
|
||||||
intel_display_power_put_mask_in_set(struct drm_i915_private *i915,
|
intel_display_power_put_mask_in_set(struct drm_i915_private *i915,
|
||||||
struct intel_display_power_domain_set *power_domain_set,
|
struct intel_display_power_domain_set *power_domain_set,
|
||||||
u64 mask);
|
struct intel_power_domain_mask *mask);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
intel_display_power_put_all_in_set(struct drm_i915_private *i915,
|
intel_display_power_put_all_in_set(struct drm_i915_private *i915,
|
||||||
struct intel_display_power_domain_set *power_domain_set)
|
struct intel_display_power_domain_set *power_domain_set)
|
||||||
{
|
{
|
||||||
intel_display_power_put_mask_in_set(i915, power_domain_set, power_domain_set->mask);
|
intel_display_power_put_mask_in_set(i915, power_domain_set, &power_domain_set->mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void intel_display_power_debug(struct drm_i915_private *i915, struct seq_file *m);
|
void intel_display_power_debug(struct drm_i915_private *i915, struct seq_file *m);
|
||||||
|
|
||||||
|
enum intel_display_power_domain
|
||||||
|
intel_display_power_ddi_lanes_domain(struct drm_i915_private *i915, enum port port);
|
||||||
|
enum intel_display_power_domain
|
||||||
|
intel_display_power_ddi_io_domain(struct drm_i915_private *i915, enum port port);
|
||||||
|
enum intel_display_power_domain
|
||||||
|
intel_display_power_legacy_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch);
|
||||||
|
enum intel_display_power_domain
|
||||||
|
intel_display_power_tbt_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: We should probably switch this to a 0-based scheme to be consistent
|
* FIXME: We should probably switch this to a 0-based scheme to be consistent
|
||||||
* with how we now name/number DBUF_CTL instances.
|
* with how we now name/number DBUF_CTL instances.
|
||||||
@ -305,9 +276,4 @@ void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv,
|
|||||||
for ((wf) = intel_display_power_get_if_enabled((i915), (domain)); (wf); \
|
for ((wf) = intel_display_power_get_if_enabled((i915), (domain)); (wf); \
|
||||||
intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0)
|
intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0)
|
||||||
|
|
||||||
void chv_phy_powergate_lanes(struct intel_encoder *encoder,
|
|
||||||
bool override, unsigned int mask);
|
|
||||||
bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy,
|
|
||||||
enum dpio_channel ch, bool override);
|
|
||||||
|
|
||||||
#endif /* __INTEL_DISPLAY_POWER_H__ */
|
#endif /* __INTEL_DISPLAY_POWER_H__ */
|
||||||
|
1501
drivers/gpu/drm/i915/display/intel_display_power_map.c
Normal file
1501
drivers/gpu/drm/i915/display/intel_display_power_map.c
Normal file
File diff suppressed because it is too large
Load Diff
14
drivers/gpu/drm/i915/display/intel_display_power_map.h
Normal file
14
drivers/gpu/drm/i915/display/intel_display_power_map.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2022 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INTEL_DISPLAY_POWER_MAP_H__
|
||||||
|
#define __INTEL_DISPLAY_POWER_MAP_H__
|
||||||
|
|
||||||
|
struct i915_power_domains;
|
||||||
|
|
||||||
|
int intel_display_power_map_init(struct i915_power_domains *power_domains);
|
||||||
|
void intel_display_power_map_cleanup(struct i915_power_domains *power_domains);
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
@ -8,10 +8,23 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include "intel_display.h"
|
#include "intel_display.h"
|
||||||
|
#include "intel_display_power.h"
|
||||||
|
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
struct i915_power_well;
|
struct i915_power_well;
|
||||||
|
|
||||||
|
#define for_each_power_well(__dev_priv, __power_well) \
|
||||||
|
for ((__power_well) = (__dev_priv)->power_domains.power_wells; \
|
||||||
|
(__power_well) - (__dev_priv)->power_domains.power_wells < \
|
||||||
|
(__dev_priv)->power_domains.power_well_count; \
|
||||||
|
(__power_well)++)
|
||||||
|
|
||||||
|
#define for_each_power_well_reverse(__dev_priv, __power_well) \
|
||||||
|
for ((__power_well) = (__dev_priv)->power_domains.power_wells + \
|
||||||
|
(__dev_priv)->power_domains.power_well_count - 1; \
|
||||||
|
(__power_well) - (__dev_priv)->power_domains.power_wells >= 0; \
|
||||||
|
(__power_well)--)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* i915_power_well_id:
|
* i915_power_well_id:
|
||||||
*
|
*
|
||||||
@ -20,7 +33,7 @@ struct i915_power_well;
|
|||||||
* wells must be assigned DISP_PW_ID_NONE.
|
* wells must be assigned DISP_PW_ID_NONE.
|
||||||
*/
|
*/
|
||||||
enum i915_power_well_id {
|
enum i915_power_well_id {
|
||||||
DISP_PW_ID_NONE,
|
DISP_PW_ID_NONE = 0, /* must be kept zero */
|
||||||
|
|
||||||
VLV_DISP_PW_DISP2D,
|
VLV_DISP_PW_DISP2D,
|
||||||
BXT_DISP_PW_DPIO_CMN_A,
|
BXT_DISP_PW_DPIO_CMN_A,
|
||||||
@ -36,45 +49,13 @@ enum i915_power_well_id {
|
|||||||
TGL_DISP_PW_TC_COLD_OFF,
|
TGL_DISP_PW_TC_COLD_OFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i915_power_well_regs {
|
struct i915_power_well_instance {
|
||||||
i915_reg_t bios;
|
|
||||||
i915_reg_t driver;
|
|
||||||
i915_reg_t kvmr;
|
|
||||||
i915_reg_t debug;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct i915_power_well_ops {
|
|
||||||
const struct i915_power_well_regs *regs;
|
|
||||||
/*
|
|
||||||
* Synchronize the well's hw state to match the current sw state, for
|
|
||||||
* example enable/disable it based on the current refcount. Called
|
|
||||||
* during driver init and resume time, possibly after first calling
|
|
||||||
* the enable/disable handlers.
|
|
||||||
*/
|
|
||||||
void (*sync_hw)(struct drm_i915_private *i915,
|
|
||||||
struct i915_power_well *power_well);
|
|
||||||
/*
|
|
||||||
* Enable the well and resources that depend on it (for example
|
|
||||||
* interrupts located on the well). Called after the 0->1 refcount
|
|
||||||
* transition.
|
|
||||||
*/
|
|
||||||
void (*enable)(struct drm_i915_private *i915,
|
|
||||||
struct i915_power_well *power_well);
|
|
||||||
/*
|
|
||||||
* Disable the well and resources that depend on it. Called after
|
|
||||||
* the 1->0 refcount transition.
|
|
||||||
*/
|
|
||||||
void (*disable)(struct drm_i915_private *i915,
|
|
||||||
struct i915_power_well *power_well);
|
|
||||||
/* Returns the hw enabled state. */
|
|
||||||
bool (*is_enabled)(struct drm_i915_private *i915,
|
|
||||||
struct i915_power_well *power_well);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct i915_power_well_desc {
|
|
||||||
const char *name;
|
const char *name;
|
||||||
bool always_on;
|
const struct i915_power_domain_list {
|
||||||
u64 domains;
|
const enum intel_display_power_domain *list;
|
||||||
|
u8 count;
|
||||||
|
} *domain_list;
|
||||||
|
|
||||||
/* unique identifier for this power well */
|
/* unique identifier for this power well */
|
||||||
enum i915_power_well_id id;
|
enum i915_power_well_id id;
|
||||||
/*
|
/*
|
||||||
@ -98,33 +79,45 @@ struct i915_power_well_desc {
|
|||||||
* constrol/status registers.
|
* constrol/status registers.
|
||||||
*/
|
*/
|
||||||
u8 idx;
|
u8 idx;
|
||||||
/* Mask of pipes whose IRQ logic is backed by the pw */
|
|
||||||
u8 irq_pipe_mask;
|
|
||||||
/*
|
|
||||||
* Instead of waiting for the status bit to ack enables,
|
|
||||||
* just wait a specific amount of time and then consider
|
|
||||||
* the well enabled.
|
|
||||||
*/
|
|
||||||
u16 fixed_enable_delay;
|
|
||||||
/* The pw is backing the VGA functionality */
|
|
||||||
bool has_vga:1;
|
|
||||||
bool has_fuses:1;
|
|
||||||
/*
|
|
||||||
* The pw is for an ICL+ TypeC PHY port in
|
|
||||||
* Thunderbolt mode.
|
|
||||||
*/
|
|
||||||
bool is_tc_tbt:1;
|
|
||||||
} hsw;
|
} hsw;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct i915_power_well_desc {
|
||||||
const struct i915_power_well_ops *ops;
|
const struct i915_power_well_ops *ops;
|
||||||
|
const struct i915_power_well_instance_list {
|
||||||
|
const struct i915_power_well_instance *list;
|
||||||
|
u8 count;
|
||||||
|
} *instances;
|
||||||
|
|
||||||
|
/* Mask of pipes whose IRQ logic is backed by the pw */
|
||||||
|
u16 irq_pipe_mask:4;
|
||||||
|
u16 always_on:1;
|
||||||
|
/*
|
||||||
|
* Instead of waiting for the status bit to ack enables,
|
||||||
|
* just wait a specific amount of time and then consider
|
||||||
|
* the well enabled.
|
||||||
|
*/
|
||||||
|
u16 fixed_enable_delay:1;
|
||||||
|
/* The pw is backing the VGA functionality */
|
||||||
|
u16 has_vga:1;
|
||||||
|
u16 has_fuses:1;
|
||||||
|
/*
|
||||||
|
* The pw is for an ICL+ TypeC PHY port in
|
||||||
|
* Thunderbolt mode.
|
||||||
|
*/
|
||||||
|
u16 is_tc_tbt:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i915_power_well {
|
struct i915_power_well {
|
||||||
const struct i915_power_well_desc *desc;
|
const struct i915_power_well_desc *desc;
|
||||||
|
struct intel_power_domain_mask domains;
|
||||||
/* power well enable/disable usage count */
|
/* power well enable/disable usage count */
|
||||||
int count;
|
int count;
|
||||||
/* cached hw enabled state */
|
/* cached hw enabled state */
|
||||||
bool hw_enabled;
|
bool hw_enabled;
|
||||||
|
/* index into desc->instances->list */
|
||||||
|
u8 instance_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i915_power_well *lookup_power_well(struct drm_i915_private *i915,
|
struct i915_power_well *lookup_power_well(struct drm_i915_private *i915,
|
||||||
@ -147,7 +140,34 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
|
|||||||
enum i915_power_well_id power_well_id);
|
enum i915_power_well_id power_well_id);
|
||||||
bool intel_power_well_is_always_on(struct i915_power_well *power_well);
|
bool intel_power_well_is_always_on(struct i915_power_well *power_well);
|
||||||
const char *intel_power_well_name(struct i915_power_well *power_well);
|
const char *intel_power_well_name(struct i915_power_well *power_well);
|
||||||
u64 intel_power_well_domains(struct i915_power_well *power_well);
|
struct intel_power_domain_mask *intel_power_well_domains(struct i915_power_well *power_well);
|
||||||
int intel_power_well_refcount(struct i915_power_well *power_well);
|
int intel_power_well_refcount(struct i915_power_well *power_well);
|
||||||
|
|
||||||
|
void chv_phy_powergate_lanes(struct intel_encoder *encoder,
|
||||||
|
bool override, unsigned int mask);
|
||||||
|
bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy,
|
||||||
|
enum dpio_channel ch, bool override);
|
||||||
|
|
||||||
|
void gen9_enable_dc5(struct drm_i915_private *dev_priv);
|
||||||
|
void skl_enable_dc6(struct drm_i915_private *dev_priv);
|
||||||
|
void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv);
|
||||||
|
void gen9_set_dc_state(struct drm_i915_private *dev_priv, u32 state);
|
||||||
|
void gen9_disable_dc_states(struct drm_i915_private *dev_priv);
|
||||||
|
void bxt_enable_dc9(struct drm_i915_private *dev_priv);
|
||||||
|
void bxt_disable_dc9(struct drm_i915_private *dev_priv);
|
||||||
|
|
||||||
|
extern const struct i915_power_well_ops i9xx_always_on_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops chv_pipe_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops chv_dpio_cmn_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops i830_pipes_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops hsw_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops gen9_dc_off_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops bxt_dpio_cmn_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops vlv_display_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops vlv_dpio_cmn_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops vlv_dpio_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops icl_aux_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops icl_ddi_power_well_ops;
|
||||||
|
extern const struct i915_power_well_ops tgl_tc_cold_off_ops;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -82,19 +82,8 @@ static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp,
|
|||||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
||||||
{
|
{
|
||||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||||
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (intel_dp_is_edp(intel_dp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Detecting LTTPRs must be avoided on platforms with an AUX timeout
|
|
||||||
* period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1).
|
|
||||||
*/
|
|
||||||
if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ret = drm_dp_read_lttpr_common_caps(&intel_dp->aux, dpcd,
|
ret = drm_dp_read_lttpr_common_caps(&intel_dp->aux, dpcd,
|
||||||
intel_dp->lttpr_common_caps);
|
intel_dp->lttpr_common_caps);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -197,13 +186,25 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI
|
|||||||
*/
|
*/
|
||||||
int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp)
|
int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp)
|
||||||
{
|
{
|
||||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
int lttpr_count;
|
int lttpr_count = 0;
|
||||||
|
|
||||||
if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
|
/*
|
||||||
return -EIO;
|
* Detecting LTTPRs must be avoided on platforms with an AUX timeout
|
||||||
|
* period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1).
|
||||||
|
*/
|
||||||
|
if (!intel_dp_is_edp(intel_dp) &&
|
||||||
|
(DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915))) {
|
||||||
|
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||||
|
|
||||||
lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd);
|
if (drm_dp_dpcd_probe(&intel_dp->aux, DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The DPTX shall read the DPRX caps after LTTPR detection, so re-read
|
* The DPTX shall read the DPRX caps after LTTPR detection, so re-read
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "intel_ddi.h"
|
#include "intel_ddi.h"
|
||||||
#include "intel_ddi_buf_trans.h"
|
#include "intel_ddi_buf_trans.h"
|
||||||
#include "intel_de.h"
|
#include "intel_de.h"
|
||||||
|
#include "intel_display_power_well.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dp.h"
|
#include "intel_dp.h"
|
||||||
#include "intel_dpio_phy.h"
|
#include "intel_dpio_phy.h"
|
||||||
|
@ -18,7 +18,10 @@
|
|||||||
#include "vlv_sideband.h"
|
#include "vlv_sideband.h"
|
||||||
|
|
||||||
struct intel_dpll_funcs {
|
struct intel_dpll_funcs {
|
||||||
int (*crtc_compute_clock)(struct intel_crtc_state *crtc_state);
|
int (*crtc_compute_clock)(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc);
|
||||||
|
int (*crtc_get_shared_dpll)(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intel_limit {
|
struct intel_limit {
|
||||||
@ -759,8 +762,8 @@ chv_find_best_dpll(const struct intel_limit *limit,
|
|||||||
bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
|
bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
|
||||||
struct dpll *best_clock)
|
struct dpll *best_clock)
|
||||||
{
|
{
|
||||||
int refclk = 100000;
|
|
||||||
const struct intel_limit *limit = &intel_limits_bxt;
|
const struct intel_limit *limit = &intel_limits_bxt;
|
||||||
|
int refclk = 100000;
|
||||||
|
|
||||||
return chv_find_best_dpll(limit, crtc_state,
|
return chv_find_best_dpll(limit, crtc_state,
|
||||||
crtc_state->port_clock, refclk,
|
crtc_state->port_clock, refclk,
|
||||||
@ -927,32 +930,48 @@ static void i8xx_compute_dpll(struct intel_crtc_state *crtc_state,
|
|||||||
crtc_state->dpll_hw_state.dpll = dpll;
|
crtc_state->dpll_hw_state.dpll = dpll;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hsw_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int hsw_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
return 0;
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
}
|
||||||
struct intel_atomic_state *state =
|
|
||||||
to_intel_atomic_state(crtc_state->uapi.state);
|
static int hsw_crtc_get_shared_dpll(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
struct intel_encoder *encoder =
|
struct intel_encoder *encoder =
|
||||||
intel_get_crtc_new_encoder(state, crtc_state);
|
intel_get_crtc_new_encoder(state, crtc_state);
|
||||||
|
int ret;
|
||||||
if (IS_DG2(dev_priv))
|
|
||||||
return intel_mpllb_calc_state(crtc_state, encoder);
|
|
||||||
|
|
||||||
if (DISPLAY_VER(dev_priv) < 11 &&
|
if (DISPLAY_VER(dev_priv) < 11 &&
|
||||||
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
|
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
|
ret = intel_reserve_shared_dplls(state, crtc, encoder);
|
||||||
|
if (ret) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"failed to find PLL for pipe %c\n",
|
"failed to find PLL for pipe %c\n",
|
||||||
pipe_name(crtc->pipe));
|
pipe_name(crtc->pipe));
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dg2_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
struct intel_encoder *encoder =
|
||||||
|
intel_get_crtc_new_encoder(state, crtc_state);
|
||||||
|
|
||||||
|
return intel_mpllb_calc_state(crtc_state, encoder);
|
||||||
|
}
|
||||||
|
|
||||||
static bool ilk_needs_fb_cb_tune(const struct dpll *dpll, int factor)
|
static bool ilk_needs_fb_cb_tune(const struct dpll *dpll, int factor)
|
||||||
{
|
{
|
||||||
return dpll->m < factor * dpll->n;
|
return dpll->m < factor * dpll->n;
|
||||||
@ -1068,18 +1087,15 @@ static void ilk_compute_dpll(struct intel_crtc_state *crtc_state,
|
|||||||
crtc_state->dpll_hw_state.dpll = dpll;
|
crtc_state->dpll_hw_state.dpll = dpll;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ilk_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int ilk_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct intel_crtc_state *crtc_state =
|
||||||
struct intel_atomic_state *state =
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
to_intel_atomic_state(crtc_state->uapi.state);
|
|
||||||
const struct intel_limit *limit;
|
const struct intel_limit *limit;
|
||||||
int refclk = 120000;
|
int refclk = 120000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
|
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
|
||||||
if (!crtc_state->has_pch_encoder)
|
if (!crtc_state->has_pch_encoder)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1118,11 +1134,27 @@ static int ilk_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
ilk_compute_dpll(crtc_state, &crtc_state->dpll,
|
ilk_compute_dpll(crtc_state, &crtc_state->dpll,
|
||||||
&crtc_state->dpll);
|
&crtc_state->dpll);
|
||||||
|
|
||||||
if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ilk_crtc_get_shared_dpll(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
|
||||||
|
if (!crtc_state->has_pch_encoder)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = intel_reserve_shared_dplls(state, crtc, NULL);
|
||||||
|
if (ret) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"failed to find PLL for pipe %c\n",
|
"failed to find PLL for pipe %c\n",
|
||||||
pipe_name(crtc->pipe));
|
pipe_name(crtc->pipe));
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1163,14 +1195,14 @@ void chv_compute_dpll(struct intel_crtc_state *crtc_state)
|
|||||||
(crtc_state->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
|
(crtc_state->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int chv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int chv_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
int refclk = 100000;
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||||
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
const struct intel_limit *limit = &intel_limits_chv;
|
const struct intel_limit *limit = &intel_limits_chv;
|
||||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
int refclk = 100000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (!crtc_state->clock_set &&
|
if (!crtc_state->clock_set &&
|
||||||
!chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
!chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
||||||
@ -1184,14 +1216,14 @@ static int chv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vlv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int vlv_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
int refclk = 100000;
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||||
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
const struct intel_limit *limit = &intel_limits_vlv;
|
const struct intel_limit *limit = &intel_limits_vlv;
|
||||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
int refclk = 100000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (!crtc_state->clock_set &&
|
if (!crtc_state->clock_set &&
|
||||||
!vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
!vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
||||||
@ -1205,16 +1237,15 @@ static int vlv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int g4x_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int g4x_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
const struct intel_limit *limit;
|
const struct intel_limit *limit;
|
||||||
int refclk = 96000;
|
int refclk = 96000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
||||||
if (intel_panel_use_ssc(dev_priv)) {
|
if (intel_panel_use_ssc(dev_priv)) {
|
||||||
refclk = dev_priv->vbt.lvds_ssc_freq;
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
||||||
@ -1251,16 +1282,15 @@ static int g4x_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pnv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int pnv_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
const struct intel_limit *limit;
|
const struct intel_limit *limit;
|
||||||
int refclk = 96000;
|
int refclk = 96000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
||||||
if (intel_panel_use_ssc(dev_priv)) {
|
if (intel_panel_use_ssc(dev_priv)) {
|
||||||
refclk = dev_priv->vbt.lvds_ssc_freq;
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
||||||
@ -1288,16 +1318,15 @@ static int pnv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i9xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int i9xx_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
const struct intel_limit *limit;
|
const struct intel_limit *limit;
|
||||||
int refclk = 96000;
|
int refclk = 96000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
||||||
if (intel_panel_use_ssc(dev_priv)) {
|
if (intel_panel_use_ssc(dev_priv)) {
|
||||||
refclk = dev_priv->vbt.lvds_ssc_freq;
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
||||||
@ -1325,16 +1354,15 @@ static int i9xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i8xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
static int i8xx_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
const struct intel_limit *limit;
|
const struct intel_limit *limit;
|
||||||
int refclk = 48000;
|
int refclk = 48000;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
||||||
if (intel_panel_use_ssc(dev_priv)) {
|
if (intel_panel_use_ssc(dev_priv)) {
|
||||||
refclk = dev_priv->vbt.lvds_ssc_freq;
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
||||||
@ -1364,12 +1392,18 @@ static int i8xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct intel_dpll_funcs dg2_dpll_funcs = {
|
||||||
|
.crtc_compute_clock = dg2_crtc_compute_clock,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct intel_dpll_funcs hsw_dpll_funcs = {
|
static const struct intel_dpll_funcs hsw_dpll_funcs = {
|
||||||
.crtc_compute_clock = hsw_crtc_compute_clock,
|
.crtc_compute_clock = hsw_crtc_compute_clock,
|
||||||
|
.crtc_get_shared_dpll = hsw_crtc_get_shared_dpll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_dpll_funcs ilk_dpll_funcs = {
|
static const struct intel_dpll_funcs ilk_dpll_funcs = {
|
||||||
.crtc_compute_clock = ilk_crtc_compute_clock,
|
.crtc_compute_clock = ilk_crtc_compute_clock,
|
||||||
|
.crtc_get_shared_dpll = ilk_crtc_get_shared_dpll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_dpll_funcs chv_dpll_funcs = {
|
static const struct intel_dpll_funcs chv_dpll_funcs = {
|
||||||
@ -1396,18 +1430,54 @@ static const struct intel_dpll_funcs i8xx_dpll_funcs = {
|
|||||||
.crtc_compute_clock = i8xx_crtc_compute_clock,
|
.crtc_compute_clock = i8xx_crtc_compute_clock,
|
||||||
};
|
};
|
||||||
|
|
||||||
int intel_dpll_crtc_compute_clock(struct intel_crtc_state *crtc_state)
|
int intel_dpll_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||||
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
|
||||||
return i915->dpll_funcs->crtc_compute_clock(crtc_state);
|
drm_WARN_ON(&i915->drm, !intel_crtc_needs_modeset(crtc_state));
|
||||||
|
|
||||||
|
if (drm_WARN_ON(&i915->drm, crtc_state->shared_dpll))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(&crtc_state->dpll_hw_state, 0,
|
||||||
|
sizeof(crtc_state->dpll_hw_state));
|
||||||
|
|
||||||
|
if (!crtc_state->hw.enable)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return i915->dpll_funcs->crtc_compute_clock(state, crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int intel_dpll_crtc_get_shared_dpll(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||||
|
struct intel_crtc_state *crtc_state =
|
||||||
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
|
||||||
|
drm_WARN_ON(&i915->drm, !intel_crtc_needs_modeset(crtc_state));
|
||||||
|
|
||||||
|
if (drm_WARN_ON(&i915->drm, crtc_state->shared_dpll))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!crtc_state->hw.enable)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!i915->dpll_funcs->crtc_get_shared_dpll)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return i915->dpll_funcs->crtc_get_shared_dpll(state, crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv)
|
intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv))
|
if (IS_DG2(dev_priv))
|
||||||
|
dev_priv->dpll_funcs = &dg2_dpll_funcs;
|
||||||
|
else if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv))
|
||||||
dev_priv->dpll_funcs = &hsw_dpll_funcs;
|
dev_priv->dpll_funcs = &hsw_dpll_funcs;
|
||||||
else if (HAS_PCH_SPLIT(dev_priv))
|
else if (HAS_PCH_SPLIT(dev_priv))
|
||||||
dev_priv->dpll_funcs = &ilk_dpll_funcs;
|
dev_priv->dpll_funcs = &ilk_dpll_funcs;
|
||||||
|
@ -10,12 +10,16 @@
|
|||||||
|
|
||||||
struct dpll;
|
struct dpll;
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
|
struct intel_atomic_state;
|
||||||
struct intel_crtc;
|
struct intel_crtc;
|
||||||
struct intel_crtc_state;
|
struct intel_crtc_state;
|
||||||
enum pipe;
|
enum pipe;
|
||||||
|
|
||||||
void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv);
|
void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv);
|
||||||
int intel_dpll_crtc_compute_clock(struct intel_crtc_state *crtc_state);
|
int intel_dpll_crtc_compute_clock(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc);
|
||||||
|
int intel_dpll_crtc_get_shared_dpll(struct intel_atomic_state *state,
|
||||||
|
struct intel_crtc *crtc);
|
||||||
int vlv_calc_dpll_params(int refclk, struct dpll *clock);
|
int vlv_calc_dpll_params(int refclk, struct dpll *clock);
|
||||||
int pnv_calc_dpll_params(int refclk, struct dpll *clock);
|
int pnv_calc_dpll_params(int refclk, struct dpll *clock);
|
||||||
int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
|
int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
|
||||||
|
@ -90,9 +90,9 @@ struct intel_shared_dpll_funcs {
|
|||||||
struct intel_dpll_mgr {
|
struct intel_dpll_mgr {
|
||||||
const struct dpll_info *dpll_info;
|
const struct dpll_info *dpll_info;
|
||||||
|
|
||||||
bool (*get_dplls)(struct intel_atomic_state *state,
|
int (*get_dplls)(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder);
|
struct intel_encoder *encoder);
|
||||||
void (*put_dplls)(struct intel_atomic_state *state,
|
void (*put_dplls)(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc);
|
struct intel_crtc *crtc);
|
||||||
void (*update_active_dpll)(struct intel_atomic_state *state,
|
void (*update_active_dpll)(struct intel_atomic_state *state,
|
||||||
@ -514,9 +514,9 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
|
|||||||
udelay(200);
|
udelay(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ibx_get_dpll(struct intel_atomic_state *state,
|
static int ibx_get_dpll(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
@ -541,7 +541,7 @@ static bool ibx_get_dpll(struct intel_atomic_state *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!pll)
|
if (!pll)
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
/* reference the pll */
|
/* reference the pll */
|
||||||
intel_reference_shared_dpll(state, crtc,
|
intel_reference_shared_dpll(state, crtc,
|
||||||
@ -549,7 +549,7 @@ static bool ibx_get_dpll(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
crtc_state->shared_dpll = pll;
|
crtc_state->shared_dpll = pll;
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
|
static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
|
||||||
@ -584,7 +584,7 @@ static const struct intel_dpll_mgr pch_pll_mgr = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
|
static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
|
||||||
struct intel_shared_dpll *pll)
|
struct intel_shared_dpll *pll)
|
||||||
{
|
{
|
||||||
const enum intel_dpll_id id = pll->info->id;
|
const enum intel_dpll_id id = pll->info->id;
|
||||||
|
|
||||||
@ -1060,16 +1060,13 @@ static int hsw_ddi_spll_get_freq(struct drm_i915_private *i915,
|
|||||||
return link_clock * 2;
|
return link_clock * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hsw_get_dpll(struct intel_atomic_state *state,
|
static int hsw_get_dpll(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
struct intel_shared_dpll *pll;
|
struct intel_shared_dpll *pll = NULL;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
||||||
pll = hsw_ddi_wrpll_get_dpll(state, crtc);
|
pll = hsw_ddi_wrpll_get_dpll(state, crtc);
|
||||||
@ -1077,18 +1074,16 @@ static bool hsw_get_dpll(struct intel_atomic_state *state,
|
|||||||
pll = hsw_ddi_lcpll_get_dpll(crtc_state);
|
pll = hsw_ddi_lcpll_get_dpll(crtc_state);
|
||||||
else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
|
else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
|
||||||
pll = hsw_ddi_spll_get_dpll(state, crtc);
|
pll = hsw_ddi_spll_get_dpll(state, crtc);
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!pll)
|
if (!pll)
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
intel_reference_shared_dpll(state, crtc,
|
intel_reference_shared_dpll(state, crtc,
|
||||||
pll, &crtc_state->dpll_hw_state);
|
pll, &crtc_state->dpll_hw_state);
|
||||||
|
|
||||||
crtc_state->shared_dpll = pll;
|
crtc_state->shared_dpll = pll;
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hsw_update_dpll_ref_clks(struct drm_i915_private *i915)
|
static void hsw_update_dpll_ref_clks(struct drm_i915_private *i915)
|
||||||
@ -1493,7 +1488,7 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
|
|||||||
params->dco_integer * MHz(1)) * 0x8000, MHz(1));
|
params->dco_integer * MHz(1)) * 0x8000, MHz(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
skl_ddi_calculate_wrpll(int clock /* in Hz */,
|
skl_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||||
int ref_clock,
|
int ref_clock,
|
||||||
struct skl_wrpll_params *wrpll_params)
|
struct skl_wrpll_params *wrpll_params)
|
||||||
@ -1552,7 +1547,7 @@ skip_remaining_dividers:
|
|||||||
|
|
||||||
if (!ctx.p) {
|
if (!ctx.p) {
|
||||||
DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
|
DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1564,14 +1559,15 @@ skip_remaining_dividers:
|
|||||||
skl_wrpll_params_populate(wrpll_params, afe_clock, ref_clock,
|
skl_wrpll_params_populate(wrpll_params, afe_clock, ref_clock,
|
||||||
ctx.central_freq, p0, p1, p2);
|
ctx.central_freq, p0, p1, p2);
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
|
static int skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
struct skl_wrpll_params wrpll_params = {};
|
struct skl_wrpll_params wrpll_params = {};
|
||||||
u32 ctrl1, cfgcr1, cfgcr2;
|
u32 ctrl1, cfgcr1, cfgcr2;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See comment in intel_dpll_hw_state to understand why we always use 0
|
* See comment in intel_dpll_hw_state to understand why we always use 0
|
||||||
@ -1581,10 +1577,10 @@ static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
|
|||||||
|
|
||||||
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
|
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
|
||||||
|
|
||||||
if (!skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000,
|
ret = skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000,
|
||||||
i915->dpll.ref_clks.nssc,
|
i915->dpll.ref_clks.nssc, &wrpll_params);
|
||||||
&wrpll_params))
|
if (ret)
|
||||||
return false;
|
return ret;
|
||||||
|
|
||||||
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
|
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
|
||||||
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
|
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
|
||||||
@ -1596,13 +1592,11 @@ static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
|
|||||||
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
|
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
|
||||||
wrpll_params.central_freq;
|
wrpll_params.central_freq;
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
||||||
crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
|
crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
|
||||||
crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
|
crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
|
||||||
return true;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
|
static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
|
||||||
@ -1676,7 +1670,7 @@ static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
|
|||||||
return dco_freq / (p0 * p1 * p2 * 5);
|
return dco_freq / (p0 * p1 * p2 * 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
u32 ctrl1;
|
u32 ctrl1;
|
||||||
@ -1708,12 +1702,9 @@ skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
|
static int skl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
|
||||||
@ -1750,33 +1741,23 @@ static int skl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
|
|||||||
return link_clock * 2;
|
return link_clock * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool skl_get_dpll(struct intel_atomic_state *state,
|
static int skl_get_dpll(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
|
||||||
struct intel_shared_dpll *pll;
|
struct intel_shared_dpll *pll;
|
||||||
bool bret;
|
int ret;
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
||||||
bret = skl_ddi_hdmi_pll_dividers(crtc_state);
|
ret = skl_ddi_hdmi_pll_dividers(crtc_state);
|
||||||
if (!bret) {
|
else if (intel_crtc_has_dp_encoder(crtc_state))
|
||||||
drm_dbg_kms(&i915->drm,
|
ret = skl_ddi_dp_set_dpll_hw_state(crtc_state);
|
||||||
"Could not get HDMI pll dividers.\n");
|
else
|
||||||
return false;
|
ret = -EINVAL;
|
||||||
}
|
if (ret)
|
||||||
} else if (intel_crtc_has_dp_encoder(crtc_state)) {
|
return ret;
|
||||||
bret = skl_ddi_dp_set_dpll_hw_state(crtc_state);
|
|
||||||
if (!bret) {
|
|
||||||
drm_dbg_kms(&i915->drm,
|
|
||||||
"Could not set DP dpll HW state.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
|
||||||
pll = intel_find_shared_dpll(state, crtc,
|
pll = intel_find_shared_dpll(state, crtc,
|
||||||
@ -1789,14 +1770,14 @@ static bool skl_get_dpll(struct intel_atomic_state *state,
|
|||||||
BIT(DPLL_ID_SKL_DPLL2) |
|
BIT(DPLL_ID_SKL_DPLL2) |
|
||||||
BIT(DPLL_ID_SKL_DPLL1));
|
BIT(DPLL_ID_SKL_DPLL1));
|
||||||
if (!pll)
|
if (!pll)
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
intel_reference_shared_dpll(state, crtc,
|
intel_reference_shared_dpll(state, crtc,
|
||||||
pll, &crtc_state->dpll_hw_state);
|
pll, &crtc_state->dpll_hw_state);
|
||||||
|
|
||||||
crtc_state->shared_dpll = pll;
|
crtc_state->shared_dpll = pll;
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skl_ddi_pll_get_freq(struct drm_i915_private *i915,
|
static int skl_ddi_pll_get_freq(struct drm_i915_private *i915,
|
||||||
@ -2095,7 +2076,7 @@ static const struct dpll bxt_dp_clk_val[] = {
|
|||||||
{ .dot = 432000, .p1 = 3, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
|
{ .dot = 432000, .p1 = 3, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state,
|
bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state,
|
||||||
struct dpll *clk_div)
|
struct dpll *clk_div)
|
||||||
{
|
{
|
||||||
@ -2111,12 +2092,12 @@ bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state,
|
|||||||
drm_dbg(&i915->drm, "no PLL dividers found for clock %d pipe %c\n",
|
drm_dbg(&i915->drm, "no PLL dividers found for clock %d pipe %c\n",
|
||||||
crtc_state->port_clock,
|
crtc_state->port_clock,
|
||||||
pipe_name(crtc->pipe));
|
pipe_name(crtc->pipe));
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_WARN_ON(&i915->drm, clk_div->m1 != 2);
|
drm_WARN_ON(&i915->drm, clk_div->m1 != 2);
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state,
|
static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state,
|
||||||
@ -2139,8 +2120,8 @@ static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state,
|
|||||||
clk_div->dot != crtc_state->port_clock);
|
clk_div->dot != crtc_state->port_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
|
static int bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
|
||||||
const struct dpll *clk_div)
|
const struct dpll *clk_div)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
struct intel_dpll_hw_state *dpll_hw_state = &crtc_state->dpll_hw_state;
|
struct intel_dpll_hw_state *dpll_hw_state = &crtc_state->dpll_hw_state;
|
||||||
@ -2149,8 +2130,6 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
|
|||||||
u32 prop_coef, int_coef, gain_ctl, targ_cnt;
|
u32 prop_coef, int_coef, gain_ctl, targ_cnt;
|
||||||
u32 lanestagger;
|
u32 lanestagger;
|
||||||
|
|
||||||
memset(dpll_hw_state, 0, sizeof(*dpll_hw_state));
|
|
||||||
|
|
||||||
if (vco >= 6200000 && vco <= 6700000) {
|
if (vco >= 6200000 && vco <= 6700000) {
|
||||||
prop_coef = 4;
|
prop_coef = 4;
|
||||||
int_coef = 9;
|
int_coef = 9;
|
||||||
@ -2169,7 +2148,7 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
|
|||||||
targ_cnt = 9;
|
targ_cnt = 9;
|
||||||
} else {
|
} else {
|
||||||
drm_err(&i915->drm, "Invalid VCO\n");
|
drm_err(&i915->drm, "Invalid VCO\n");
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clock > 270000)
|
if (clock > 270000)
|
||||||
@ -2206,10 +2185,10 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
|
|||||||
|
|
||||||
dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
|
dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
struct dpll clk_div = {};
|
struct dpll clk_div = {};
|
||||||
@ -2219,7 +2198,7 @@ bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
|||||||
return bxt_ddi_set_dpll_hw_state(crtc_state, &clk_div);
|
return bxt_ddi_set_dpll_hw_state(crtc_state, &clk_div);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
struct dpll clk_div = {};
|
struct dpll clk_div = {};
|
||||||
@ -2246,23 +2225,25 @@ static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915,
|
|||||||
return chv_calc_dpll_params(i915->dpll.ref_clks.nssc, &clock);
|
return chv_calc_dpll_params(i915->dpll.ref_clks.nssc, &clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bxt_get_dpll(struct intel_atomic_state *state,
|
static int bxt_get_dpll(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
struct intel_shared_dpll *pll;
|
struct intel_shared_dpll *pll;
|
||||||
enum intel_dpll_id id;
|
enum intel_dpll_id id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
||||||
!bxt_ddi_hdmi_set_dpll_hw_state(crtc_state))
|
ret = bxt_ddi_hdmi_set_dpll_hw_state(crtc_state);
|
||||||
return false;
|
else if (intel_crtc_has_dp_encoder(crtc_state))
|
||||||
|
ret = bxt_ddi_dp_set_dpll_hw_state(crtc_state);
|
||||||
if (intel_crtc_has_dp_encoder(crtc_state) &&
|
else
|
||||||
!bxt_ddi_dp_set_dpll_hw_state(crtc_state))
|
ret = -EINVAL;
|
||||||
return false;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* 1:1 mapping between ports and PLLs */
|
/* 1:1 mapping between ports and PLLs */
|
||||||
id = (enum intel_dpll_id) encoder->port;
|
id = (enum intel_dpll_id) encoder->port;
|
||||||
@ -2276,7 +2257,7 @@ static bool bxt_get_dpll(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
crtc_state->shared_dpll = pll;
|
crtc_state->shared_dpll = pll;
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bxt_update_dpll_ref_clks(struct drm_i915_private *i915)
|
static void bxt_update_dpll_ref_clks(struct drm_i915_private *i915)
|
||||||
@ -2513,8 +2494,8 @@ static const struct skl_wrpll_params tgl_tbt_pll_24MHz_values = {
|
|||||||
/* the following params are unused */
|
/* the following params are unused */
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
|
static int icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
|
||||||
struct skl_wrpll_params *pll_params)
|
struct skl_wrpll_params *pll_params)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
const struct icl_combo_pll_params *params =
|
const struct icl_combo_pll_params *params =
|
||||||
@ -2527,16 +2508,16 @@ static bool icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
|
|||||||
for (i = 0; i < ARRAY_SIZE(icl_dp_combo_pll_24MHz_values); i++) {
|
for (i = 0; i < ARRAY_SIZE(icl_dp_combo_pll_24MHz_values); i++) {
|
||||||
if (clock == params[i].clock) {
|
if (clock == params[i].clock) {
|
||||||
*pll_params = params[i].wrpll;
|
*pll_params = params[i].wrpll;
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MISSING_CASE(clock);
|
MISSING_CASE(clock);
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
|
static int icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
|
||||||
struct skl_wrpll_params *pll_params)
|
struct skl_wrpll_params *pll_params)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
|
|
||||||
@ -2568,7 +2549,7 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icl_ddi_tbt_pll_get_freq(struct drm_i915_private *i915,
|
static int icl_ddi_tbt_pll_get_freq(struct drm_i915_private *i915,
|
||||||
@ -2598,7 +2579,7 @@ static int icl_wrpll_ref_clock(struct drm_i915_private *i915)
|
|||||||
return ref_clock;
|
return ref_clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
icl_calc_wrpll(struct intel_crtc_state *crtc_state,
|
icl_calc_wrpll(struct intel_crtc_state *crtc_state,
|
||||||
struct skl_wrpll_params *wrpll_params)
|
struct skl_wrpll_params *wrpll_params)
|
||||||
{
|
{
|
||||||
@ -2633,13 +2614,13 @@ icl_calc_wrpll(struct intel_crtc_state *crtc_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (best_div == 0)
|
if (best_div == 0)
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
icl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
|
icl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
|
||||||
icl_wrpll_params_populate(wrpll_params, best_dco, ref_clock,
|
icl_wrpll_params_populate(wrpll_params, best_dco, ref_clock,
|
||||||
pdiv, qdiv, kdiv);
|
pdiv, qdiv, kdiv);
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
|
static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
|
||||||
@ -2709,8 +2690,6 @@ static void icl_calc_dpll_state(struct drm_i915_private *i915,
|
|||||||
{
|
{
|
||||||
u32 dco_fraction = pll_params->dco_fraction;
|
u32 dco_fraction = pll_params->dco_fraction;
|
||||||
|
|
||||||
memset(pll_state, 0, sizeof(*pll_state));
|
|
||||||
|
|
||||||
if (ehl_combo_pll_div_frac_wa_needed(i915))
|
if (ehl_combo_pll_div_frac_wa_needed(i915))
|
||||||
dco_fraction = DIV_ROUND_CLOSEST(dco_fraction, 2);
|
dco_fraction = DIV_ROUND_CLOSEST(dco_fraction, 2);
|
||||||
|
|
||||||
@ -2731,10 +2710,10 @@ static void icl_calc_dpll_state(struct drm_i915_private *i915,
|
|||||||
pll_state->div0 = TGL_DPLL0_DIV0_AFC_STARTUP(i915->vbt.override_afc_startup_val);
|
pll_state->div0 = TGL_DPLL0_DIV0_AFC_STARTUP(i915->vbt.override_afc_startup_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
|
static int icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
|
||||||
u32 *target_dco_khz,
|
u32 *target_dco_khz,
|
||||||
struct intel_dpll_hw_state *state,
|
struct intel_dpll_hw_state *state,
|
||||||
bool is_dkl)
|
bool is_dkl)
|
||||||
{
|
{
|
||||||
static const u8 div1_vals[] = { 7, 5, 3, 2 };
|
static const u8 div1_vals[] = { 7, 5, 3, 2 };
|
||||||
u32 dco_min_freq, dco_max_freq;
|
u32 dco_min_freq, dco_max_freq;
|
||||||
@ -2800,19 +2779,19 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
|
|||||||
hsdiv |
|
hsdiv |
|
||||||
MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(div2);
|
MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(div2);
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The specification for this function uses real numbers, so the math had to be
|
* The specification for this function uses real numbers, so the math had to be
|
||||||
* adapted to integer-only calculation, that's why it looks so different.
|
* adapted to integer-only calculation, that's why it looks so different.
|
||||||
*/
|
*/
|
||||||
static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
|
static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
|
||||||
struct intel_dpll_hw_state *pll_state)
|
struct intel_dpll_hw_state *pll_state)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
int refclk_khz = dev_priv->dpll.ref_clks.nssc;
|
int refclk_khz = dev_priv->dpll.ref_clks.nssc;
|
||||||
@ -2826,14 +2805,14 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
|
|||||||
bool use_ssc = false;
|
bool use_ssc = false;
|
||||||
bool is_dp = !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI);
|
bool is_dp = !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI);
|
||||||
bool is_dkl = DISPLAY_VER(dev_priv) >= 12;
|
bool is_dkl = DISPLAY_VER(dev_priv) >= 12;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(pll_state, 0, sizeof(*pll_state));
|
ret = icl_mg_pll_find_divisors(clock, is_dp, use_ssc, &dco_khz,
|
||||||
|
pll_state, is_dkl);
|
||||||
if (!icl_mg_pll_find_divisors(clock, is_dp, use_ssc, &dco_khz,
|
if (ret) {
|
||||||
pll_state, is_dkl)) {
|
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"Failed to find divisors for clock %d\n", clock);
|
"Failed to find divisors for clock %d\n", clock);
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
m1div = 2;
|
m1div = 2;
|
||||||
@ -2848,7 +2827,7 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
|
|||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"Failed to find mdiv for clock %d\n",
|
"Failed to find mdiv for clock %d\n",
|
||||||
clock);
|
clock);
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m2div_rem = dco_khz % (refclk_khz * m1div);
|
m2div_rem = dco_khz % (refclk_khz * m1div);
|
||||||
@ -2875,7 +2854,7 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
MISSING_CASE(refclk_khz);
|
MISSING_CASE(refclk_khz);
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3018,7 +2997,7 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
|
|||||||
pll_state->mg_pll_bias &= pll_state->mg_pll_bias_mask;
|
pll_state->mg_pll_bias &= pll_state->mg_pll_bias_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv,
|
static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv,
|
||||||
@ -3140,9 +3119,9 @@ static u32 intel_get_hti_plls(struct drm_i915_private *i915)
|
|||||||
return REG_FIELD_GET(HDPORT_DPLL_USED_MASK, i915->hti_state);
|
return REG_FIELD_GET(HDPORT_DPLL_USED_MASK, i915->hti_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
|
static int icl_get_combo_phy_dpll(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
@ -3160,11 +3139,10 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
|
|||||||
else
|
else
|
||||||
ret = icl_calc_dp_combo_pll(crtc_state, &pll_params);
|
ret = icl_calc_dp_combo_pll(crtc_state, &pll_params);
|
||||||
|
|
||||||
if (!ret) {
|
if (ret) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"Could not calculate combo PHY PLL state.\n");
|
"Could not calculate combo PHY PLL state.\n");
|
||||||
|
return ret;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
|
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
|
||||||
@ -3209,7 +3187,7 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
|
|||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"No combo PHY PLL found for [ENCODER:%d:%s]\n",
|
"No combo PHY PLL found for [ENCODER:%d:%s]\n",
|
||||||
encoder->base.base.id, encoder->base.name);
|
encoder->base.base.id, encoder->base.name);
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_reference_shared_dpll(state, crtc,
|
intel_reference_shared_dpll(state, crtc,
|
||||||
@ -3217,12 +3195,12 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
icl_update_active_dpll(state, crtc, encoder);
|
icl_update_active_dpll(state, crtc, encoder);
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
|
static int icl_get_tc_phy_dplls(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
@ -3230,12 +3208,14 @@ static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
|
|||||||
struct skl_wrpll_params pll_params = { };
|
struct skl_wrpll_params pll_params = { };
|
||||||
struct icl_port_dpll *port_dpll;
|
struct icl_port_dpll *port_dpll;
|
||||||
enum intel_dpll_id dpll_id;
|
enum intel_dpll_id dpll_id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
|
port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
|
||||||
if (!icl_calc_tbt_pll(crtc_state, &pll_params)) {
|
ret = icl_calc_tbt_pll(crtc_state, &pll_params);
|
||||||
|
if (ret) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"Could not calculate TBT PLL state.\n");
|
"Could not calculate TBT PLL state.\n");
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
|
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
|
||||||
@ -3245,14 +3225,15 @@ static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
|
|||||||
BIT(DPLL_ID_ICL_TBTPLL));
|
BIT(DPLL_ID_ICL_TBTPLL));
|
||||||
if (!port_dpll->pll) {
|
if (!port_dpll->pll) {
|
||||||
drm_dbg_kms(&dev_priv->drm, "No TBT-ALT PLL found\n");
|
drm_dbg_kms(&dev_priv->drm, "No TBT-ALT PLL found\n");
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
intel_reference_shared_dpll(state, crtc,
|
intel_reference_shared_dpll(state, crtc,
|
||||||
port_dpll->pll, &port_dpll->hw_state);
|
port_dpll->pll, &port_dpll->hw_state);
|
||||||
|
|
||||||
|
|
||||||
port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY];
|
port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY];
|
||||||
if (!icl_calc_mg_pll_state(crtc_state, &port_dpll->hw_state)) {
|
ret = icl_calc_mg_pll_state(crtc_state, &port_dpll->hw_state);
|
||||||
|
if (ret) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"Could not calculate MG PHY PLL state.\n");
|
"Could not calculate MG PHY PLL state.\n");
|
||||||
goto err_unreference_tbt_pll;
|
goto err_unreference_tbt_pll;
|
||||||
@ -3264,6 +3245,7 @@ static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
|
|||||||
&port_dpll->hw_state,
|
&port_dpll->hw_state,
|
||||||
BIT(dpll_id));
|
BIT(dpll_id));
|
||||||
if (!port_dpll->pll) {
|
if (!port_dpll->pll) {
|
||||||
|
ret = -EINVAL;
|
||||||
drm_dbg_kms(&dev_priv->drm, "No MG PHY PLL found\n");
|
drm_dbg_kms(&dev_priv->drm, "No MG PHY PLL found\n");
|
||||||
goto err_unreference_tbt_pll;
|
goto err_unreference_tbt_pll;
|
||||||
}
|
}
|
||||||
@ -3272,18 +3254,18 @@ static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
icl_update_active_dpll(state, crtc, encoder);
|
icl_update_active_dpll(state, crtc, encoder);
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
|
|
||||||
err_unreference_tbt_pll:
|
err_unreference_tbt_pll:
|
||||||
port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
|
port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
|
||||||
intel_unreference_shared_dpll(state, crtc, port_dpll->pll);
|
intel_unreference_shared_dpll(state, crtc, port_dpll->pll);
|
||||||
|
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool icl_get_dplls(struct intel_atomic_state *state,
|
static int icl_get_dplls(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
|
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
|
||||||
@ -3295,7 +3277,7 @@ static bool icl_get_dplls(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
MISSING_CASE(phy);
|
MISSING_CASE(phy);
|
||||||
|
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void icl_put_dplls(struct intel_atomic_state *state,
|
static void icl_put_dplls(struct intel_atomic_state *state,
|
||||||
@ -4081,13 +4063,12 @@ static const struct intel_dpll_mgr adlp_pll_mgr = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_shared_dpll_init - Initialize shared DPLLs
|
* intel_shared_dpll_init - Initialize shared DPLLs
|
||||||
* @dev: drm device
|
* @dev_priv: i915 device
|
||||||
*
|
*
|
||||||
* Initialize shared DPLLs for @dev.
|
* Initialize shared DPLLs for @dev_priv.
|
||||||
*/
|
*/
|
||||||
void intel_shared_dpll_init(struct drm_device *dev)
|
void intel_shared_dpll_init(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
||||||
const struct intel_dpll_mgr *dpll_mgr = NULL;
|
const struct intel_dpll_mgr *dpll_mgr = NULL;
|
||||||
const struct dpll_info *dpll_info;
|
const struct dpll_info *dpll_info;
|
||||||
int i;
|
int i;
|
||||||
@ -4126,7 +4107,7 @@ void intel_shared_dpll_init(struct drm_device *dev)
|
|||||||
dpll_info = dpll_mgr->dpll_info;
|
dpll_info = dpll_mgr->dpll_info;
|
||||||
|
|
||||||
for (i = 0; dpll_info[i].name; i++) {
|
for (i = 0; dpll_info[i].name; i++) {
|
||||||
drm_WARN_ON(dev, i != dpll_info[i].id);
|
drm_WARN_ON(&dev_priv->drm, i != dpll_info[i].id);
|
||||||
dev_priv->dpll.shared_dplls[i].info = &dpll_info[i];
|
dev_priv->dpll.shared_dplls[i].info = &dpll_info[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4154,17 +4135,18 @@ void intel_shared_dpll_init(struct drm_device *dev)
|
|||||||
* intel_release_shared_dplls().
|
* intel_release_shared_dplls().
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* True if all required DPLLs were successfully reserved.
|
* 0 if all required DPLLs were successfully reserved,
|
||||||
|
* negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
bool intel_reserve_shared_dplls(struct intel_atomic_state *state,
|
int intel_reserve_shared_dplls(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll.mgr;
|
const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll.mgr;
|
||||||
|
|
||||||
if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr))
|
if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr))
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
return dpll_mgr->get_dplls(state, crtc, encoder);
|
return dpll_mgr->get_dplls(state, crtc, encoder);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
__a > __b ? (__a - __b) : (__b - __a); })
|
__a > __b ? (__a - __b) : (__b - __a); })
|
||||||
|
|
||||||
enum tc_port;
|
enum tc_port;
|
||||||
struct drm_device;
|
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
struct intel_atomic_state;
|
struct intel_atomic_state;
|
||||||
struct intel_crtc;
|
struct intel_crtc;
|
||||||
@ -337,9 +336,9 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
|
|||||||
bool state);
|
bool state);
|
||||||
#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
|
#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
|
||||||
#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
|
#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
|
||||||
bool intel_reserve_shared_dplls(struct intel_atomic_state *state,
|
int intel_reserve_shared_dplls(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc,
|
struct intel_crtc *crtc,
|
||||||
struct intel_encoder *encoder);
|
struct intel_encoder *encoder);
|
||||||
void intel_release_shared_dplls(struct intel_atomic_state *state,
|
void intel_release_shared_dplls(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc);
|
struct intel_crtc *crtc);
|
||||||
void icl_set_active_port_dpll(struct intel_crtc_state *crtc_state,
|
void icl_set_active_port_dpll(struct intel_crtc_state *crtc_state,
|
||||||
@ -356,7 +355,7 @@ bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
|
|||||||
void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
|
void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
|
||||||
void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
|
void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
|
||||||
void intel_shared_dpll_swap_state(struct intel_atomic_state *state);
|
void intel_shared_dpll_swap_state(struct intel_atomic_state *state);
|
||||||
void intel_shared_dpll_init(struct drm_device *dev);
|
void intel_shared_dpll_init(struct drm_i915_private *dev_priv);
|
||||||
void intel_dpll_update_ref_clks(struct drm_i915_private *dev_priv);
|
void intel_dpll_update_ref_clks(struct drm_i915_private *dev_priv);
|
||||||
void intel_dpll_readout_hw_state(struct drm_i915_private *dev_priv);
|
void intel_dpll_readout_hw_state(struct drm_i915_private *dev_priv);
|
||||||
void intel_dpll_sanitize_state(struct drm_i915_private *dev_priv);
|
void intel_dpll_sanitize_state(struct drm_i915_private *dev_priv);
|
||||||
|
@ -811,6 +811,14 @@ static void intel_fbc_program_cfb(struct intel_fbc *fbc)
|
|||||||
fbc->funcs->program_cfb(fbc);
|
fbc->funcs->program_cfb(fbc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intel_fbc_program_workarounds(struct intel_fbc *fbc)
|
||||||
|
{
|
||||||
|
/* Wa_22014263786:icl,jsl,tgl,dg1,rkl,adls,dg2,adlp */
|
||||||
|
if (DISPLAY_VER(fbc->i915) >= 11)
|
||||||
|
intel_de_rmw(fbc->i915, ILK_DPFC_CHICKEN(fbc->id), 0,
|
||||||
|
DPFC_CHICKEN_FORCE_SLB_INVALIDATION);
|
||||||
|
}
|
||||||
|
|
||||||
static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc)
|
static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = fbc->i915;
|
struct drm_i915_private *i915 = fbc->i915;
|
||||||
@ -1086,7 +1094,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
|
|||||||
*/
|
*/
|
||||||
if (DISPLAY_VER(i915) >= 12 && crtc_state->has_psr2) {
|
if (DISPLAY_VER(i915) >= 12 && crtc_state->has_psr2) {
|
||||||
plane_state->no_fbc_reason = "PSR2 enabled";
|
plane_state->no_fbc_reason = "PSR2 enabled";
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pixel_format_is_valid(plane_state)) {
|
if (!pixel_format_is_valid(plane_state)) {
|
||||||
@ -1112,7 +1120,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
|
|||||||
if (plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE &&
|
if (plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE &&
|
||||||
fb->format->has_alpha) {
|
fb->format->has_alpha) {
|
||||||
plane_state->no_fbc_reason = "per-pixel alpha not supported";
|
plane_state->no_fbc_reason = "per-pixel alpha not supported";
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!intel_fbc_hw_tracking_covers_screen(plane_state)) {
|
if (!intel_fbc_hw_tracking_covers_screen(plane_state)) {
|
||||||
@ -1128,7 +1136,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
|
|||||||
if (DISPLAY_VER(i915) >= 9 &&
|
if (DISPLAY_VER(i915) >= 9 &&
|
||||||
plane_state->view.color_plane[0].y & 3) {
|
plane_state->view.color_plane[0].y & 3) {
|
||||||
plane_state->no_fbc_reason = "plane start Y offset misaligned";
|
plane_state->no_fbc_reason = "plane start Y offset misaligned";
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wa_22010751166: icl, ehl, tgl, dg1, rkl */
|
/* Wa_22010751166: icl, ehl, tgl, dg1, rkl */
|
||||||
@ -1136,7 +1144,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
|
|||||||
(plane_state->view.color_plane[0].y +
|
(plane_state->view.color_plane[0].y +
|
||||||
(drm_rect_height(&plane_state->uapi.src) >> 16)) & 3) {
|
(drm_rect_height(&plane_state->uapi.src) >> 16)) & 3) {
|
||||||
plane_state->no_fbc_reason = "plane end Y offset misaligned";
|
plane_state->no_fbc_reason = "plane end Y offset misaligned";
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WaFbcExceedCdClockThreshold:hsw,bdw */
|
/* WaFbcExceedCdClockThreshold:hsw,bdw */
|
||||||
@ -1462,6 +1470,7 @@ static void __intel_fbc_enable(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
intel_fbc_update_state(state, crtc, plane);
|
intel_fbc_update_state(state, crtc, plane);
|
||||||
|
|
||||||
|
intel_fbc_program_workarounds(fbc);
|
||||||
intel_fbc_program_cfb(fbc);
|
intel_fbc_program_cfb(fbc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,13 +75,17 @@ const struct drm_display_mode *
|
|||||||
intel_panel_downclock_mode(struct intel_connector *connector,
|
intel_panel_downclock_mode(struct intel_connector *connector,
|
||||||
const struct drm_display_mode *adjusted_mode)
|
const struct drm_display_mode *adjusted_mode)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
const struct drm_display_mode *fixed_mode, *best_mode = NULL;
|
const struct drm_display_mode *fixed_mode, *best_mode = NULL;
|
||||||
int vrefresh = drm_mode_vrefresh(adjusted_mode);
|
int min_vrefresh = i915->vbt.seamless_drrs_min_refresh_rate;
|
||||||
|
int max_vrefresh = drm_mode_vrefresh(adjusted_mode);
|
||||||
|
|
||||||
/* pick the fixed_mode with the lowest refresh rate */
|
/* pick the fixed_mode with the lowest refresh rate */
|
||||||
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
|
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
|
||||||
if (drm_mode_vrefresh(fixed_mode) < vrefresh) {
|
int vrefresh = drm_mode_vrefresh(fixed_mode);
|
||||||
vrefresh = drm_mode_vrefresh(fixed_mode);
|
|
||||||
|
if (vrefresh >= min_vrefresh && vrefresh < max_vrefresh) {
|
||||||
|
max_vrefresh = vrefresh;
|
||||||
best_mode = fixed_mode;
|
best_mode = fixed_mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "g4x_dp.h"
|
#include "g4x_dp.h"
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include "intel_de.h"
|
#include "intel_de.h"
|
||||||
|
#include "intel_display_power_well.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dp.h"
|
#include "intel_dp.h"
|
||||||
#include "intel_dpll.h"
|
#include "intel_dpll.h"
|
||||||
|
@ -1353,6 +1353,9 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
|
|||||||
drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, 0);
|
drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, 0);
|
||||||
|
|
||||||
intel_dp->psr.enabled = false;
|
intel_dp->psr.enabled = false;
|
||||||
|
intel_dp->psr.psr2_enabled = false;
|
||||||
|
intel_dp->psr.psr2_sel_fetch_enabled = false;
|
||||||
|
intel_dp->psr.psr2_sel_fetch_cff_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include "i915_reg.h"
|
#include "i915_reg.h"
|
||||||
#include "intel_display.h"
|
#include "intel_display.h"
|
||||||
|
#include "intel_display_power_map.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dp_mst.h"
|
#include "intel_dp_mst.h"
|
||||||
#include "intel_tc.h"
|
#include "intel_tc.h"
|
||||||
@ -61,10 +62,12 @@ bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port)
|
|||||||
static enum intel_display_power_domain
|
static enum intel_display_power_domain
|
||||||
tc_cold_get_power_domain(struct intel_digital_port *dig_port, enum tc_port_mode mode)
|
tc_cold_get_power_domain(struct intel_digital_port *dig_port, enum tc_port_mode mode)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||||
|
|
||||||
if (mode == TC_PORT_TBT_ALT || !intel_tc_cold_requires_aux_pw(dig_port))
|
if (mode == TC_PORT_TBT_ALT || !intel_tc_cold_requires_aux_pw(dig_port))
|
||||||
return POWER_DOMAIN_TC_COLD_OFF;
|
return POWER_DOMAIN_TC_COLD_OFF;
|
||||||
|
|
||||||
return intel_legacy_aux_to_power_domain(dig_port->aux_ch);
|
return intel_display_power_legacy_aux_domain(i915, dig_port->aux_ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static intel_wakeref_t
|
static intel_wakeref_t
|
||||||
|
@ -735,7 +735,7 @@ struct lvds_lfp_data_ptr {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct bdb_lvds_lfp_data_ptrs {
|
struct bdb_lvds_lfp_data_ptrs {
|
||||||
u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
|
u8 lvds_entries;
|
||||||
struct lvds_lfp_data_ptr ptr[16];
|
struct lvds_lfp_data_ptr ptr[16];
|
||||||
struct lvds_lfp_data_ptr_table panel_name; /* 156-163? */
|
struct lvds_lfp_data_ptr_table panel_name; /* 156-163? */
|
||||||
} __packed;
|
} __packed;
|
||||||
@ -769,6 +769,11 @@ struct lvds_pnp_id {
|
|||||||
u8 mfg_year;
|
u8 mfg_year;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For reference only. fp_timing has variable size so
|
||||||
|
* the data must be accessed using the data table pointers.
|
||||||
|
* Do not use this directly!
|
||||||
|
*/
|
||||||
struct lvds_lfp_data_entry {
|
struct lvds_lfp_data_entry {
|
||||||
struct lvds_fp_timing fp_timing;
|
struct lvds_fp_timing fp_timing;
|
||||||
struct lvds_dvo_timing dvo_timing;
|
struct lvds_dvo_timing dvo_timing;
|
||||||
@ -783,6 +788,23 @@ struct lvds_lfp_panel_name {
|
|||||||
u8 name[13];
|
u8 name[13];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct lvds_lfp_black_border {
|
||||||
|
u8 top; /* 227 */
|
||||||
|
u8 bottom; /* 227 */
|
||||||
|
u8 left; /* 238 */
|
||||||
|
u8 right; /* 238 */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct bdb_lvds_lfp_data_tail {
|
||||||
|
struct lvds_lfp_panel_name panel_name[16]; /* 156-163? */
|
||||||
|
u16 scaling_enable; /* 187 */
|
||||||
|
u8 seamless_drrs_min_refresh_rate[16]; /* 188 */
|
||||||
|
u8 pixel_overlap_count[16]; /* 208 */
|
||||||
|
struct lvds_lfp_black_border black_border[16]; /* 227 */
|
||||||
|
u16 dual_lfp_port_sync_enable; /* 231 */
|
||||||
|
u16 gpu_dithering_for_banding_artifacts; /* 245 */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Block 43 - LFP Backlight Control Data Block
|
* Block 43 - LFP Backlight Control Data Block
|
||||||
*/
|
*/
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
GVT_DIR := gvt
|
|
||||||
GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
|
|
||||||
interrupt.o gtt.o cfg_space.o opregion.o mmio.o display.o edid.o \
|
|
||||||
execlist.o scheduler.o sched_policy.o mmio_context.o cmd_parser.o debugfs.o \
|
|
||||||
fb_decoder.o dmabuf.o page_track.o
|
|
||||||
|
|
||||||
ccflags-y += -I $(srctree)/$(src) -I $(srctree)/$(src)/$(GVT_DIR)/
|
kvmgt-$(CONFIG_DRM_I915_GVT) += \
|
||||||
i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
|
gvt/aperture_gm.o \
|
||||||
|
gvt/cfg_space.o \
|
||||||
|
gvt/cmd_parser.o \
|
||||||
|
gvt/debugfs.o \
|
||||||
|
gvt/display.o \
|
||||||
|
gvt/dmabuf.o \
|
||||||
|
gvt/edid.o \
|
||||||
|
gvt/execlist.o \
|
||||||
|
gvt/fb_decoder.o \
|
||||||
|
gvt/firmware.o \
|
||||||
|
gvt/gtt.o \
|
||||||
|
gvt/handlers.o \
|
||||||
|
gvt/interrupt.o \
|
||||||
|
gvt/kvmgt.o \
|
||||||
|
gvt/mmio.o \
|
||||||
|
gvt/mmio_context.o \
|
||||||
|
gvt/opregion.o \
|
||||||
|
gvt/page_track.o \
|
||||||
|
gvt/sched_policy.o \
|
||||||
|
gvt/scheduler.o \
|
||||||
|
gvt/trace_points.o \
|
||||||
|
gvt/vgpu.o
|
||||||
|
@ -129,60 +129,16 @@ int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_aperture(struct intel_vgpu *vgpu, bool map)
|
static void map_aperture(struct intel_vgpu *vgpu, bool map)
|
||||||
{
|
{
|
||||||
phys_addr_t aperture_pa = vgpu_aperture_pa_base(vgpu);
|
if (map != vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked)
|
||||||
unsigned long aperture_sz = vgpu_aperture_sz(vgpu);
|
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map;
|
||||||
u64 first_gfn;
|
|
||||||
u64 val;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2];
|
|
||||||
if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
|
||||||
val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
|
|
||||||
else
|
|
||||||
val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
|
|
||||||
|
|
||||||
first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT;
|
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn,
|
|
||||||
aperture_pa >> PAGE_SHIFT,
|
|
||||||
aperture_sz >> PAGE_SHIFT,
|
|
||||||
map);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int trap_gttmmio(struct intel_vgpu *vgpu, bool trap)
|
static void trap_gttmmio(struct intel_vgpu *vgpu, bool trap)
|
||||||
{
|
{
|
||||||
u64 start, end;
|
if (trap != vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked)
|
||||||
u64 val;
|
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (trap == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0];
|
|
||||||
if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
|
||||||
start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
|
|
||||||
else
|
|
||||||
start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
|
|
||||||
|
|
||||||
start &= ~GENMASK(3, 0);
|
|
||||||
end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1;
|
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_set_trap_area(vgpu, start, end, trap);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int emulate_pci_command_write(struct intel_vgpu *vgpu,
|
static int emulate_pci_command_write(struct intel_vgpu *vgpu,
|
||||||
@ -191,26 +147,17 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,
|
|||||||
u8 old = vgpu_cfg_space(vgpu)[offset];
|
u8 old = vgpu_cfg_space(vgpu)[offset];
|
||||||
u8 new = *(u8 *)p_data;
|
u8 new = *(u8 *)p_data;
|
||||||
u8 changed = old ^ new;
|
u8 changed = old ^ new;
|
||||||
int ret;
|
|
||||||
|
|
||||||
vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
|
vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
|
||||||
if (!(changed & PCI_COMMAND_MEMORY))
|
if (!(changed & PCI_COMMAND_MEMORY))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (old & PCI_COMMAND_MEMORY) {
|
if (old & PCI_COMMAND_MEMORY) {
|
||||||
ret = trap_gttmmio(vgpu, false);
|
trap_gttmmio(vgpu, false);
|
||||||
if (ret)
|
map_aperture(vgpu, false);
|
||||||
return ret;
|
|
||||||
ret = map_aperture(vgpu, false);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
} else {
|
} else {
|
||||||
ret = trap_gttmmio(vgpu, true);
|
trap_gttmmio(vgpu, true);
|
||||||
if (ret)
|
map_aperture(vgpu, true);
|
||||||
return ret;
|
|
||||||
ret = map_aperture(vgpu, true);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -230,13 +177,12 @@ static int emulate_pci_rom_bar_write(struct intel_vgpu *vgpu,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
|
static void emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||||
void *p_data, unsigned int bytes)
|
void *p_data, unsigned int bytes)
|
||||||
{
|
{
|
||||||
u32 new = *(u32 *)(p_data);
|
u32 new = *(u32 *)(p_data);
|
||||||
bool lo = IS_ALIGNED(offset, 8);
|
bool lo = IS_ALIGNED(offset, 8);
|
||||||
u64 size;
|
u64 size;
|
||||||
int ret = 0;
|
|
||||||
bool mmio_enabled =
|
bool mmio_enabled =
|
||||||
vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY;
|
vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY;
|
||||||
struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar;
|
struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar;
|
||||||
@ -259,14 +205,14 @@ static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
|
|||||||
* Untrap the BAR, since guest hasn't configured a
|
* Untrap the BAR, since guest hasn't configured a
|
||||||
* valid GPA
|
* valid GPA
|
||||||
*/
|
*/
|
||||||
ret = trap_gttmmio(vgpu, false);
|
trap_gttmmio(vgpu, false);
|
||||||
break;
|
break;
|
||||||
case PCI_BASE_ADDRESS_2:
|
case PCI_BASE_ADDRESS_2:
|
||||||
case PCI_BASE_ADDRESS_3:
|
case PCI_BASE_ADDRESS_3:
|
||||||
size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1);
|
size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1);
|
||||||
intel_vgpu_write_pci_bar(vgpu, offset,
|
intel_vgpu_write_pci_bar(vgpu, offset,
|
||||||
size >> (lo ? 0 : 32), lo);
|
size >> (lo ? 0 : 32), lo);
|
||||||
ret = map_aperture(vgpu, false);
|
map_aperture(vgpu, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Unimplemented BARs */
|
/* Unimplemented BARs */
|
||||||
@ -282,19 +228,18 @@ static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
|
|||||||
*/
|
*/
|
||||||
trap_gttmmio(vgpu, false);
|
trap_gttmmio(vgpu, false);
|
||||||
intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
|
intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
|
||||||
ret = trap_gttmmio(vgpu, mmio_enabled);
|
trap_gttmmio(vgpu, mmio_enabled);
|
||||||
break;
|
break;
|
||||||
case PCI_BASE_ADDRESS_2:
|
case PCI_BASE_ADDRESS_2:
|
||||||
case PCI_BASE_ADDRESS_3:
|
case PCI_BASE_ADDRESS_3:
|
||||||
map_aperture(vgpu, false);
|
map_aperture(vgpu, false);
|
||||||
intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
|
intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
|
||||||
ret = map_aperture(vgpu, mmio_enabled);
|
map_aperture(vgpu, mmio_enabled);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
|
intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -336,8 +281,8 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
|
|||||||
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
|
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
|
||||||
if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
|
if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return emulate_pci_bar_write(vgpu, offset, p_data, bytes);
|
emulate_pci_bar_write(vgpu, offset, p_data, bytes);
|
||||||
|
break;
|
||||||
case INTEL_GVT_PCI_SWSCI:
|
case INTEL_GVT_PCI_SWSCI:
|
||||||
if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
|
if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1011,7 +1011,7 @@ static int cmd_reg_handler(struct parser_exec_state *s,
|
|||||||
if (GRAPHICS_VER(s->engine->i915) == 9 &&
|
if (GRAPHICS_VER(s->engine->i915) == 9 &&
|
||||||
intel_gvt_mmio_is_sr_in_ctx(gvt, offset) &&
|
intel_gvt_mmio_is_sr_in_ctx(gvt, offset) &&
|
||||||
!strncmp(cmd, "lri", 3)) {
|
!strncmp(cmd, "lri", 3)) {
|
||||||
intel_gvt_hypervisor_read_gpa(s->vgpu,
|
intel_gvt_read_gpa(s->vgpu,
|
||||||
s->workload->ring_context_gpa + 12, &ctx_sr_ctl, 4);
|
s->workload->ring_context_gpa + 12, &ctx_sr_ctl, 4);
|
||||||
/* check inhibit context */
|
/* check inhibit context */
|
||||||
if (ctx_sr_ctl & 1) {
|
if (ctx_sr_ctl & 1) {
|
||||||
@ -1775,7 +1775,7 @@ static int copy_gma_to_hva(struct intel_vgpu *vgpu, struct intel_vgpu_mm *mm,
|
|||||||
copy_len = (end_gma - gma) >= (I915_GTT_PAGE_SIZE - offset) ?
|
copy_len = (end_gma - gma) >= (I915_GTT_PAGE_SIZE - offset) ?
|
||||||
I915_GTT_PAGE_SIZE - offset : end_gma - gma;
|
I915_GTT_PAGE_SIZE - offset : end_gma - gma;
|
||||||
|
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, gpa, va + len, copy_len);
|
intel_gvt_read_gpa(vgpu, gpa, va + len, copy_len);
|
||||||
|
|
||||||
len += copy_len;
|
len += copy_len;
|
||||||
gma += copy_len;
|
gma += copy_len;
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/dma-buf.h>
|
#include <linux/dma-buf.h>
|
||||||
#include <linux/vfio.h>
|
#include <linux/mdev.h>
|
||||||
|
|
||||||
#include <drm/drm_fourcc.h>
|
#include <drm/drm_fourcc.h>
|
||||||
#include <drm/drm_plane.h>
|
#include <drm/drm_plane.h>
|
||||||
@ -42,24 +42,6 @@
|
|||||||
|
|
||||||
#define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12))
|
#define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12))
|
||||||
|
|
||||||
static int vgpu_pin_dma_address(struct intel_vgpu *vgpu,
|
|
||||||
unsigned long size,
|
|
||||||
dma_addr_t dma_addr)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (intel_gvt_hypervisor_dma_pin_guest_page(vgpu, dma_addr))
|
|
||||||
ret = -EINVAL;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vgpu_unpin_dma_address(struct intel_vgpu *vgpu,
|
|
||||||
dma_addr_t dma_addr)
|
|
||||||
{
|
|
||||||
intel_gvt_hypervisor_dma_unmap_guest_page(vgpu, dma_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vgpu_gem_get_pages(
|
static int vgpu_gem_get_pages(
|
||||||
struct drm_i915_gem_object *obj)
|
struct drm_i915_gem_object *obj)
|
||||||
{
|
{
|
||||||
@ -95,7 +77,7 @@ static int vgpu_gem_get_pages(
|
|||||||
for_each_sg(st->sgl, sg, page_num, i) {
|
for_each_sg(st->sgl, sg, page_num, i) {
|
||||||
dma_addr_t dma_addr =
|
dma_addr_t dma_addr =
|
||||||
GEN8_DECODE_PTE(readq(>t_entries[i]));
|
GEN8_DECODE_PTE(readq(>t_entries[i]));
|
||||||
if (vgpu_pin_dma_address(vgpu, PAGE_SIZE, dma_addr)) {
|
if (intel_gvt_dma_pin_guest_page(vgpu, dma_addr)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -114,7 +96,7 @@ out:
|
|||||||
for_each_sg(st->sgl, sg, i, j) {
|
for_each_sg(st->sgl, sg, i, j) {
|
||||||
dma_addr = sg_dma_address(sg);
|
dma_addr = sg_dma_address(sg);
|
||||||
if (dma_addr)
|
if (dma_addr)
|
||||||
vgpu_unpin_dma_address(vgpu, dma_addr);
|
intel_gvt_dma_unmap_guest_page(vgpu, dma_addr);
|
||||||
}
|
}
|
||||||
sg_free_table(st);
|
sg_free_table(st);
|
||||||
kfree(st);
|
kfree(st);
|
||||||
@ -136,7 +118,7 @@ static void vgpu_gem_put_pages(struct drm_i915_gem_object *obj,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for_each_sg(pages->sgl, sg, fb_info->size, i)
|
for_each_sg(pages->sgl, sg, fb_info->size, i)
|
||||||
vgpu_unpin_dma_address(vgpu,
|
intel_gvt_dma_unmap_guest_page(vgpu,
|
||||||
sg_dma_address(sg));
|
sg_dma_address(sg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +139,6 @@ static void dmabuf_gem_object_free(struct kref *kref)
|
|||||||
dmabuf_obj = list_entry(pos, struct intel_vgpu_dmabuf_obj, list);
|
dmabuf_obj = list_entry(pos, struct intel_vgpu_dmabuf_obj, list);
|
||||||
if (dmabuf_obj == obj) {
|
if (dmabuf_obj == obj) {
|
||||||
list_del(pos);
|
list_del(pos);
|
||||||
intel_gvt_hypervisor_put_vfio_device(vgpu);
|
|
||||||
idr_remove(&vgpu->object_idr,
|
idr_remove(&vgpu->object_idr,
|
||||||
dmabuf_obj->dmabuf_id);
|
dmabuf_obj->dmabuf_id);
|
||||||
kfree(dmabuf_obj->info);
|
kfree(dmabuf_obj->info);
|
||||||
@ -491,14 +472,6 @@ int intel_vgpu_query_plane(struct intel_vgpu *vgpu, void *args)
|
|||||||
|
|
||||||
kref_init(&dmabuf_obj->kref);
|
kref_init(&dmabuf_obj->kref);
|
||||||
|
|
||||||
mutex_lock(&vgpu->dmabuf_lock);
|
|
||||||
if (intel_gvt_hypervisor_get_vfio_device(vgpu)) {
|
|
||||||
gvt_vgpu_err("get vfio device failed\n");
|
|
||||||
mutex_unlock(&vgpu->dmabuf_lock);
|
|
||||||
goto out_free_info;
|
|
||||||
}
|
|
||||||
mutex_unlock(&vgpu->dmabuf_lock);
|
|
||||||
|
|
||||||
update_fb_info(gfx_plane_info, &fb_info);
|
update_fb_info(gfx_plane_info, &fb_info);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dmabuf_obj->list);
|
INIT_LIST_HEAD(&dmabuf_obj->list);
|
||||||
@ -603,7 +576,6 @@ void intel_vgpu_dmabuf_cleanup(struct intel_vgpu *vgpu)
|
|||||||
dmabuf_obj->vgpu = NULL;
|
dmabuf_obj->vgpu = NULL;
|
||||||
|
|
||||||
idr_remove(&vgpu->object_idr, dmabuf_obj->dmabuf_id);
|
idr_remove(&vgpu->object_idr, dmabuf_obj->dmabuf_id);
|
||||||
intel_gvt_hypervisor_put_vfio_device(vgpu);
|
|
||||||
list_del(pos);
|
list_del(pos);
|
||||||
|
|
||||||
/* dmabuf_obj might be freed in dmabuf_obj_put */
|
/* dmabuf_obj might be freed in dmabuf_obj_put */
|
||||||
|
@ -159,12 +159,12 @@ static void emulate_csb_update(struct intel_vgpu_execlist *execlist,
|
|||||||
hwsp_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
|
hwsp_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
|
||||||
vgpu->hws_pga[execlist->engine->id]);
|
vgpu->hws_pga[execlist->engine->id]);
|
||||||
if (hwsp_gpa != INTEL_GVT_INVALID_ADDR) {
|
if (hwsp_gpa != INTEL_GVT_INVALID_ADDR) {
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu,
|
intel_gvt_write_gpa(vgpu,
|
||||||
hwsp_gpa + I915_HWS_CSB_BUF0_INDEX * 4 + write_pointer * 8,
|
hwsp_gpa + I915_HWS_CSB_BUF0_INDEX * 4 + write_pointer * 8,
|
||||||
status, 8);
|
status, 8);
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu,
|
intel_gvt_write_gpa(vgpu,
|
||||||
hwsp_gpa + INTEL_HWS_CSB_WRITE_INDEX(execlist->engine->i915) * 4,
|
hwsp_gpa + INTEL_HWS_CSB_WRITE_INDEX(execlist->engine->i915) * 4,
|
||||||
&write_pointer, 4);
|
&write_pointer, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
gvt_dbg_el("vgpu%d: w pointer %u reg %x csb l %x csb h %x\n",
|
gvt_dbg_el("vgpu%d: w pointer %u reg %x csb l %x csb h %x\n",
|
||||||
|
@ -66,22 +66,16 @@ static struct bin_attribute firmware_attr = {
|
|||||||
.mmap = NULL,
|
.mmap = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mmio_snapshot_handler(struct intel_gvt *gvt, u32 offset, void *data)
|
|
||||||
{
|
|
||||||
*(u32 *)(data + offset) = intel_uncore_read_notrace(gvt->gt->uncore,
|
|
||||||
_MMIO(offset));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
||||||
{
|
{
|
||||||
struct intel_gvt_device_info *info = &gvt->device_info;
|
struct intel_gvt_device_info *info = &gvt->device_info;
|
||||||
struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
|
struct drm_i915_private *i915 = gvt->gt->i915;
|
||||||
|
struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
|
||||||
struct gvt_firmware_header *h;
|
struct gvt_firmware_header *h;
|
||||||
void *firmware;
|
void *firmware;
|
||||||
void *p;
|
void *p;
|
||||||
unsigned long size, crc32_start;
|
unsigned long size, crc32_start;
|
||||||
int i, ret;
|
int ret;
|
||||||
|
|
||||||
size = sizeof(*h) + info->mmio_size + info->cfg_space_size;
|
size = sizeof(*h) + info->mmio_size + info->cfg_space_size;
|
||||||
firmware = vzalloc(size);
|
firmware = vzalloc(size);
|
||||||
@ -99,17 +93,16 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
|||||||
|
|
||||||
p = firmware + h->cfg_space_offset;
|
p = firmware + h->cfg_space_offset;
|
||||||
|
|
||||||
for (i = 0; i < h->cfg_space_size; i += 4)
|
memcpy(gvt->firmware.cfg_space, i915->vgpu.initial_cfg_space,
|
||||||
pci_read_config_dword(pdev, i, p + i);
|
info->cfg_space_size);
|
||||||
|
memcpy(p, gvt->firmware.cfg_space, info->cfg_space_size);
|
||||||
memcpy(gvt->firmware.cfg_space, p, info->cfg_space_size);
|
|
||||||
|
|
||||||
p = firmware + h->mmio_offset;
|
p = firmware + h->mmio_offset;
|
||||||
|
|
||||||
/* Take a snapshot of hw mmio registers. */
|
memcpy(gvt->firmware.mmio, i915->vgpu.initial_mmio,
|
||||||
intel_gvt_for_each_tracked_mmio(gvt, mmio_snapshot_handler, p);
|
info->mmio_size);
|
||||||
|
|
||||||
memcpy(gvt->firmware.mmio, p, info->mmio_size);
|
memcpy(p, gvt->firmware.mmio, info->mmio_size);
|
||||||
|
|
||||||
crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4;
|
crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4;
|
||||||
h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start);
|
h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start);
|
||||||
|
@ -49,6 +49,22 @@
|
|||||||
static bool enable_out_of_sync = false;
|
static bool enable_out_of_sync = false;
|
||||||
static int preallocated_oos_pages = 8192;
|
static int preallocated_oos_pages = 8192;
|
||||||
|
|
||||||
|
static bool intel_gvt_is_valid_gfn(struct intel_vgpu *vgpu, unsigned long gfn)
|
||||||
|
{
|
||||||
|
struct kvm *kvm = vgpu->kvm;
|
||||||
|
int idx;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
if (!vgpu->attached)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
idx = srcu_read_lock(&kvm->srcu);
|
||||||
|
ret = kvm_is_visible_gfn(kvm, gfn);
|
||||||
|
srcu_read_unlock(&kvm->srcu, idx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* validate a gm address and related range size,
|
* validate a gm address and related range size,
|
||||||
* translate it to host gm address
|
* translate it to host gm address
|
||||||
@ -314,7 +330,7 @@ static inline int gtt_get_entry64(void *pt,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (hypervisor_access) {
|
if (hypervisor_access) {
|
||||||
ret = intel_gvt_hypervisor_read_gpa(vgpu, gpa +
|
ret = intel_gvt_read_gpa(vgpu, gpa +
|
||||||
(index << info->gtt_entry_size_shift),
|
(index << info->gtt_entry_size_shift),
|
||||||
&e->val64, 8);
|
&e->val64, 8);
|
||||||
if (WARN_ON(ret))
|
if (WARN_ON(ret))
|
||||||
@ -339,7 +355,7 @@ static inline int gtt_set_entry64(void *pt,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (hypervisor_access) {
|
if (hypervisor_access) {
|
||||||
ret = intel_gvt_hypervisor_write_gpa(vgpu, gpa +
|
ret = intel_gvt_write_gpa(vgpu, gpa +
|
||||||
(index << info->gtt_entry_size_shift),
|
(index << info->gtt_entry_size_shift),
|
||||||
&e->val64, 8);
|
&e->val64, 8);
|
||||||
if (WARN_ON(ret))
|
if (WARN_ON(ret))
|
||||||
@ -997,7 +1013,7 @@ static inline void ppgtt_invalidate_pte(struct intel_vgpu_ppgtt_spt *spt,
|
|||||||
if (!pfn || pfn == vgpu->gtt.scratch_pt[type].page_mfn)
|
if (!pfn || pfn == vgpu->gtt.scratch_pt[type].page_mfn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
intel_gvt_hypervisor_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT);
|
intel_gvt_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt)
|
static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt)
|
||||||
@ -1162,15 +1178,16 @@ static int is_2MB_gtt_possible(struct intel_vgpu *vgpu,
|
|||||||
struct intel_gvt_gtt_entry *entry)
|
struct intel_gvt_gtt_entry *entry)
|
||||||
{
|
{
|
||||||
const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
|
const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
|
||||||
unsigned long pfn;
|
kvm_pfn_t pfn;
|
||||||
|
|
||||||
if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M))
|
if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pfn = intel_gvt_hypervisor_gfn_to_mfn(vgpu, ops->get_pfn(entry));
|
if (!vgpu->attached)
|
||||||
if (pfn == INTEL_GVT_INVALID_ADDR)
|
return -EINVAL;
|
||||||
|
pfn = gfn_to_pfn(vgpu->kvm, ops->get_pfn(entry));
|
||||||
|
if (is_error_noslot_pfn(pfn))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return PageTransHuge(pfn_to_page(pfn));
|
return PageTransHuge(pfn_to_page(pfn));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1195,8 +1212,8 @@ static int split_2MB_gtt_entry(struct intel_vgpu *vgpu,
|
|||||||
return PTR_ERR(sub_spt);
|
return PTR_ERR(sub_spt);
|
||||||
|
|
||||||
for_each_shadow_entry(sub_spt, &sub_se, sub_index) {
|
for_each_shadow_entry(sub_spt, &sub_se, sub_index) {
|
||||||
ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu,
|
ret = intel_gvt_dma_map_guest_page(vgpu, start_gfn + sub_index,
|
||||||
start_gfn + sub_index, PAGE_SIZE, &dma_addr);
|
PAGE_SIZE, &dma_addr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ppgtt_invalidate_spt(spt);
|
ppgtt_invalidate_spt(spt);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1241,8 +1258,8 @@ static int split_64KB_gtt_entry(struct intel_vgpu *vgpu,
|
|||||||
ops->set_64k_splited(&entry);
|
ops->set_64k_splited(&entry);
|
||||||
|
|
||||||
for (i = 0; i < GTT_64K_PTE_STRIDE; i++) {
|
for (i = 0; i < GTT_64K_PTE_STRIDE; i++) {
|
||||||
ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu,
|
ret = intel_gvt_dma_map_guest_page(vgpu, start_gfn + i,
|
||||||
start_gfn + i, PAGE_SIZE, &dma_addr);
|
PAGE_SIZE, &dma_addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1296,8 +1313,7 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* direct shadow */
|
/* direct shadow */
|
||||||
ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, page_size,
|
ret = intel_gvt_dma_map_guest_page(vgpu, gfn, page_size, &dma_addr);
|
||||||
&dma_addr);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
@ -1331,7 +1347,7 @@ static int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt)
|
|||||||
ppgtt_set_shadow_entry(spt, &se, i);
|
ppgtt_set_shadow_entry(spt, &se, i);
|
||||||
} else {
|
} else {
|
||||||
gfn = ops->get_pfn(&ge);
|
gfn = ops->get_pfn(&ge);
|
||||||
if (!intel_gvt_hypervisor_is_valid_gfn(vgpu, gfn)) {
|
if (!intel_gvt_is_valid_gfn(vgpu, gfn)) {
|
||||||
ops->set_pfn(&se, gvt->gtt.scratch_mfn);
|
ops->set_pfn(&se, gvt->gtt.scratch_mfn);
|
||||||
ppgtt_set_shadow_entry(spt, &se, i);
|
ppgtt_set_shadow_entry(spt, &se, i);
|
||||||
continue;
|
continue;
|
||||||
@ -1497,7 +1513,7 @@ static int attach_oos_page(struct intel_vgpu_oos_page *oos_page,
|
|||||||
struct intel_gvt *gvt = spt->vgpu->gvt;
|
struct intel_gvt *gvt = spt->vgpu->gvt;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_read_gpa(spt->vgpu,
|
ret = intel_gvt_read_gpa(spt->vgpu,
|
||||||
spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
|
spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
|
||||||
oos_page->mem, I915_GTT_PAGE_SIZE);
|
oos_page->mem, I915_GTT_PAGE_SIZE);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -2228,8 +2244,7 @@ static void ggtt_invalidate_pte(struct intel_vgpu *vgpu,
|
|||||||
|
|
||||||
pfn = pte_ops->get_pfn(entry);
|
pfn = pte_ops->get_pfn(entry);
|
||||||
if (pfn != vgpu->gvt->gtt.scratch_mfn)
|
if (pfn != vgpu->gvt->gtt.scratch_mfn)
|
||||||
intel_gvt_hypervisor_dma_unmap_guest_page(vgpu,
|
intel_gvt_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT);
|
||||||
pfn << PAGE_SHIFT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
|
static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
|
||||||
@ -2315,13 +2330,13 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
|
|||||||
/* one PTE update may be issued in multiple writes and the
|
/* one PTE update may be issued in multiple writes and the
|
||||||
* first write may not construct a valid gfn
|
* first write may not construct a valid gfn
|
||||||
*/
|
*/
|
||||||
if (!intel_gvt_hypervisor_is_valid_gfn(vgpu, gfn)) {
|
if (!intel_gvt_is_valid_gfn(vgpu, gfn)) {
|
||||||
ops->set_pfn(&m, gvt->gtt.scratch_mfn);
|
ops->set_pfn(&m, gvt->gtt.scratch_mfn);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn,
|
ret = intel_gvt_dma_map_guest_page(vgpu, gfn, PAGE_SIZE,
|
||||||
PAGE_SIZE, &dma_addr);
|
&dma_addr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
gvt_vgpu_err("fail to populate guest ggtt entry\n");
|
gvt_vgpu_err("fail to populate guest ggtt entry\n");
|
||||||
/* guest driver may read/write the entry when partial
|
/* guest driver may read/write the entry when partial
|
||||||
|
@ -1,340 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the next
|
|
||||||
* paragraph) shall be included in all copies or substantial portions of the
|
|
||||||
* Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Kevin Tian <kevin.tian@intel.com>
|
|
||||||
* Eddie Dong <eddie.dong@intel.com>
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Niu Bing <bing.niu@intel.com>
|
|
||||||
* Zhi Wang <zhi.a.wang@intel.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
|
|
||||||
#include "i915_drv.h"
|
|
||||||
#include "intel_gvt.h"
|
|
||||||
#include "gvt.h"
|
|
||||||
#include <linux/vfio.h>
|
|
||||||
#include <linux/mdev.h>
|
|
||||||
|
|
||||||
struct intel_gvt_host intel_gvt_host;
|
|
||||||
|
|
||||||
static const char * const supported_hypervisors[] = {
|
|
||||||
[INTEL_GVT_HYPERVISOR_XEN] = "XEN",
|
|
||||||
[INTEL_GVT_HYPERVISOR_KVM] = "KVM",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct intel_gvt_ops intel_gvt_ops = {
|
|
||||||
.emulate_cfg_read = intel_vgpu_emulate_cfg_read,
|
|
||||||
.emulate_cfg_write = intel_vgpu_emulate_cfg_write,
|
|
||||||
.emulate_mmio_read = intel_vgpu_emulate_mmio_read,
|
|
||||||
.emulate_mmio_write = intel_vgpu_emulate_mmio_write,
|
|
||||||
.vgpu_create = intel_gvt_create_vgpu,
|
|
||||||
.vgpu_destroy = intel_gvt_destroy_vgpu,
|
|
||||||
.vgpu_release = intel_gvt_release_vgpu,
|
|
||||||
.vgpu_reset = intel_gvt_reset_vgpu,
|
|
||||||
.vgpu_activate = intel_gvt_activate_vgpu,
|
|
||||||
.vgpu_deactivate = intel_gvt_deactivate_vgpu,
|
|
||||||
.vgpu_query_plane = intel_vgpu_query_plane,
|
|
||||||
.vgpu_get_dmabuf = intel_vgpu_get_dmabuf,
|
|
||||||
.write_protect_handler = intel_vgpu_page_track_handler,
|
|
||||||
.emulate_hotplug = intel_vgpu_emulate_hotplug,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void init_device_info(struct intel_gvt *gvt)
|
|
||||||
{
|
|
||||||
struct intel_gvt_device_info *info = &gvt->device_info;
|
|
||||||
struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
|
|
||||||
|
|
||||||
info->max_support_vgpus = 8;
|
|
||||||
info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE;
|
|
||||||
info->mmio_size = 2 * 1024 * 1024;
|
|
||||||
info->mmio_bar = 0;
|
|
||||||
info->gtt_start_offset = 8 * 1024 * 1024;
|
|
||||||
info->gtt_entry_size = 8;
|
|
||||||
info->gtt_entry_size_shift = 3;
|
|
||||||
info->gmadr_bytes_in_cmd = 8;
|
|
||||||
info->max_surface_size = 36 * 1024 * 1024;
|
|
||||||
info->msi_cap_offset = pdev->msi_cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void intel_gvt_test_and_emulate_vblank(struct intel_gvt *gvt)
|
|
||||||
{
|
|
||||||
struct intel_vgpu *vgpu;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
mutex_lock(&gvt->lock);
|
|
||||||
idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) {
|
|
||||||
if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK + id,
|
|
||||||
(void *)&gvt->service_request)) {
|
|
||||||
if (vgpu->active)
|
|
||||||
intel_vgpu_emulate_vblank(vgpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&gvt->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gvt_service_thread(void *data)
|
|
||||||
{
|
|
||||||
struct intel_gvt *gvt = (struct intel_gvt *)data;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
gvt_dbg_core("service thread start\n");
|
|
||||||
|
|
||||||
while (!kthread_should_stop()) {
|
|
||||||
ret = wait_event_interruptible(gvt->service_thread_wq,
|
|
||||||
kthread_should_stop() || gvt->service_request);
|
|
||||||
|
|
||||||
if (kthread_should_stop())
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (WARN_ONCE(ret, "service thread is waken up by signal.\n"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
intel_gvt_test_and_emulate_vblank(gvt);
|
|
||||||
|
|
||||||
if (test_bit(INTEL_GVT_REQUEST_SCHED,
|
|
||||||
(void *)&gvt->service_request) ||
|
|
||||||
test_bit(INTEL_GVT_REQUEST_EVENT_SCHED,
|
|
||||||
(void *)&gvt->service_request)) {
|
|
||||||
intel_gvt_schedule(gvt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clean_service_thread(struct intel_gvt *gvt)
|
|
||||||
{
|
|
||||||
kthread_stop(gvt->service_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init_service_thread(struct intel_gvt *gvt)
|
|
||||||
{
|
|
||||||
init_waitqueue_head(&gvt->service_thread_wq);
|
|
||||||
|
|
||||||
gvt->service_thread = kthread_run(gvt_service_thread,
|
|
||||||
gvt, "gvt_service_thread");
|
|
||||||
if (IS_ERR(gvt->service_thread)) {
|
|
||||||
gvt_err("fail to start service thread.\n");
|
|
||||||
return PTR_ERR(gvt->service_thread);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_clean_device - clean a GVT device
|
|
||||||
* @i915: i915 private
|
|
||||||
*
|
|
||||||
* This function is called at the driver unloading stage, to free the
|
|
||||||
* resources owned by a GVT device.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void intel_gvt_clean_device(struct drm_i915_private *i915)
|
|
||||||
{
|
|
||||||
struct intel_gvt *gvt = fetch_and_zero(&i915->gvt);
|
|
||||||
|
|
||||||
if (drm_WARN_ON(&i915->drm, !gvt))
|
|
||||||
return;
|
|
||||||
|
|
||||||
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
|
||||||
intel_gvt_clean_vgpu_types(gvt);
|
|
||||||
|
|
||||||
intel_gvt_debugfs_clean(gvt);
|
|
||||||
clean_service_thread(gvt);
|
|
||||||
intel_gvt_clean_cmd_parser(gvt);
|
|
||||||
intel_gvt_clean_sched_policy(gvt);
|
|
||||||
intel_gvt_clean_workload_scheduler(gvt);
|
|
||||||
intel_gvt_clean_gtt(gvt);
|
|
||||||
intel_gvt_free_firmware(gvt);
|
|
||||||
intel_gvt_clean_mmio_info(gvt);
|
|
||||||
idr_destroy(&gvt->vgpu_idr);
|
|
||||||
|
|
||||||
kfree(i915->gvt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_init_device - initialize a GVT device
|
|
||||||
* @i915: drm i915 private data
|
|
||||||
*
|
|
||||||
* This function is called at the initialization stage, to initialize
|
|
||||||
* necessary GVT components.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
int intel_gvt_init_device(struct drm_i915_private *i915)
|
|
||||||
{
|
|
||||||
struct intel_gvt *gvt;
|
|
||||||
struct intel_vgpu *vgpu;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (drm_WARN_ON(&i915->drm, i915->gvt))
|
|
||||||
return -EEXIST;
|
|
||||||
|
|
||||||
gvt = kzalloc(sizeof(struct intel_gvt), GFP_KERNEL);
|
|
||||||
if (!gvt)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
gvt_dbg_core("init gvt device\n");
|
|
||||||
|
|
||||||
idr_init_base(&gvt->vgpu_idr, 1);
|
|
||||||
spin_lock_init(&gvt->scheduler.mmio_context_lock);
|
|
||||||
mutex_init(&gvt->lock);
|
|
||||||
mutex_init(&gvt->sched_lock);
|
|
||||||
gvt->gt = to_gt(i915);
|
|
||||||
i915->gvt = gvt;
|
|
||||||
|
|
||||||
init_device_info(gvt);
|
|
||||||
|
|
||||||
ret = intel_gvt_setup_mmio_info(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_idr;
|
|
||||||
|
|
||||||
intel_gvt_init_engine_mmio_context(gvt);
|
|
||||||
|
|
||||||
ret = intel_gvt_load_firmware(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_mmio_info;
|
|
||||||
|
|
||||||
ret = intel_gvt_init_irq(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_free_firmware;
|
|
||||||
|
|
||||||
ret = intel_gvt_init_gtt(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_free_firmware;
|
|
||||||
|
|
||||||
ret = intel_gvt_init_workload_scheduler(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_gtt;
|
|
||||||
|
|
||||||
ret = intel_gvt_init_sched_policy(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_workload_scheduler;
|
|
||||||
|
|
||||||
ret = intel_gvt_init_cmd_parser(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_sched_policy;
|
|
||||||
|
|
||||||
ret = init_service_thread(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_cmd_parser;
|
|
||||||
|
|
||||||
ret = intel_gvt_init_vgpu_types(gvt);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_thread;
|
|
||||||
|
|
||||||
vgpu = intel_gvt_create_idle_vgpu(gvt);
|
|
||||||
if (IS_ERR(vgpu)) {
|
|
||||||
ret = PTR_ERR(vgpu);
|
|
||||||
gvt_err("failed to create idle vgpu\n");
|
|
||||||
goto out_clean_types;
|
|
||||||
}
|
|
||||||
gvt->idle_vgpu = vgpu;
|
|
||||||
|
|
||||||
intel_gvt_debugfs_init(gvt);
|
|
||||||
|
|
||||||
gvt_dbg_core("gvt device initialization is done\n");
|
|
||||||
intel_gvt_host.dev = i915->drm.dev;
|
|
||||||
intel_gvt_host.initialized = true;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_clean_types:
|
|
||||||
intel_gvt_clean_vgpu_types(gvt);
|
|
||||||
out_clean_thread:
|
|
||||||
clean_service_thread(gvt);
|
|
||||||
out_clean_cmd_parser:
|
|
||||||
intel_gvt_clean_cmd_parser(gvt);
|
|
||||||
out_clean_sched_policy:
|
|
||||||
intel_gvt_clean_sched_policy(gvt);
|
|
||||||
out_clean_workload_scheduler:
|
|
||||||
intel_gvt_clean_workload_scheduler(gvt);
|
|
||||||
out_clean_gtt:
|
|
||||||
intel_gvt_clean_gtt(gvt);
|
|
||||||
out_free_firmware:
|
|
||||||
intel_gvt_free_firmware(gvt);
|
|
||||||
out_clean_mmio_info:
|
|
||||||
intel_gvt_clean_mmio_info(gvt);
|
|
||||||
out_clean_idr:
|
|
||||||
idr_destroy(&gvt->vgpu_idr);
|
|
||||||
kfree(gvt);
|
|
||||||
i915->gvt = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
intel_gvt_pm_resume(struct intel_gvt *gvt)
|
|
||||||
{
|
|
||||||
intel_gvt_restore_fence(gvt);
|
|
||||||
intel_gvt_restore_mmio(gvt);
|
|
||||||
intel_gvt_restore_ggtt(gvt);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
intel_gvt_register_hypervisor(const struct intel_gvt_mpt *m)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
void *gvt;
|
|
||||||
|
|
||||||
if (!intel_gvt_host.initialized)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (m->type != INTEL_GVT_HYPERVISOR_KVM &&
|
|
||||||
m->type != INTEL_GVT_HYPERVISOR_XEN)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Get a reference for device model module */
|
|
||||||
if (!try_module_get(THIS_MODULE))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
intel_gvt_host.mpt = m;
|
|
||||||
intel_gvt_host.hypervisor_type = m->type;
|
|
||||||
gvt = (void *)kdev_to_i915(intel_gvt_host.dev)->gvt;
|
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_host_init(intel_gvt_host.dev, gvt,
|
|
||||||
&intel_gvt_ops);
|
|
||||||
if (ret < 0) {
|
|
||||||
gvt_err("Failed to init %s hypervisor module\n",
|
|
||||||
supported_hypervisors[intel_gvt_host.hypervisor_type]);
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
gvt_dbg_core("Running with hypervisor %s in host mode\n",
|
|
||||||
supported_hypervisors[intel_gvt_host.hypervisor_type]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(intel_gvt_register_hypervisor);
|
|
||||||
|
|
||||||
void
|
|
||||||
intel_gvt_unregister_hypervisor(void)
|
|
||||||
{
|
|
||||||
void *gvt = (void *)kdev_to_i915(intel_gvt_host.dev)->gvt;
|
|
||||||
intel_gvt_hypervisor_host_exit(intel_gvt_host.dev, gvt);
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(intel_gvt_unregister_hypervisor);
|
|
@ -34,11 +34,13 @@
|
|||||||
#define _GVT_H_
|
#define _GVT_H_
|
||||||
|
|
||||||
#include <uapi/linux/pci_regs.h>
|
#include <uapi/linux/pci_regs.h>
|
||||||
|
#include <linux/kvm_host.h>
|
||||||
|
#include <linux/vfio.h>
|
||||||
|
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
|
#include "intel_gvt.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "hypercall.h"
|
|
||||||
#include "mmio.h"
|
#include "mmio.h"
|
||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
@ -56,15 +58,6 @@
|
|||||||
|
|
||||||
#define GVT_MAX_VGPU 8
|
#define GVT_MAX_VGPU 8
|
||||||
|
|
||||||
struct intel_gvt_host {
|
|
||||||
struct device *dev;
|
|
||||||
bool initialized;
|
|
||||||
int hypervisor_type;
|
|
||||||
const struct intel_gvt_mpt *mpt;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct intel_gvt_host intel_gvt_host;
|
|
||||||
|
|
||||||
/* Describe per-platform limitations. */
|
/* Describe per-platform limitations. */
|
||||||
struct intel_gvt_device_info {
|
struct intel_gvt_device_info {
|
||||||
u32 max_support_vgpus;
|
u32 max_support_vgpus;
|
||||||
@ -176,12 +169,14 @@ struct intel_vgpu_submission {
|
|||||||
} last_ctx[I915_NUM_ENGINES];
|
} last_ctx[I915_NUM_ENGINES];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define KVMGT_DEBUGFS_FILENAME "kvmgt_nr_cache_entries"
|
||||||
|
|
||||||
struct intel_vgpu {
|
struct intel_vgpu {
|
||||||
struct intel_gvt *gvt;
|
struct intel_gvt *gvt;
|
||||||
struct mutex vgpu_lock;
|
struct mutex vgpu_lock;
|
||||||
int id;
|
int id;
|
||||||
unsigned long handle; /* vGPU handle used by hypervisor MPT modules */
|
|
||||||
bool active;
|
bool active;
|
||||||
|
bool attached;
|
||||||
bool pv_notified;
|
bool pv_notified;
|
||||||
bool failsafe;
|
bool failsafe;
|
||||||
unsigned int resetting_eng;
|
unsigned int resetting_eng;
|
||||||
@ -209,21 +204,40 @@ struct intel_vgpu {
|
|||||||
|
|
||||||
struct dentry *debugfs;
|
struct dentry *debugfs;
|
||||||
|
|
||||||
/* Hypervisor-specific device state. */
|
|
||||||
void *vdev;
|
|
||||||
|
|
||||||
struct list_head dmabuf_obj_list_head;
|
struct list_head dmabuf_obj_list_head;
|
||||||
struct mutex dmabuf_lock;
|
struct mutex dmabuf_lock;
|
||||||
struct idr object_idr;
|
struct idr object_idr;
|
||||||
struct intel_vgpu_vblank_timer vblank_timer;
|
struct intel_vgpu_vblank_timer vblank_timer;
|
||||||
|
|
||||||
u32 scan_nonprivbb;
|
u32 scan_nonprivbb;
|
||||||
};
|
|
||||||
|
|
||||||
static inline void *intel_vgpu_vdev(struct intel_vgpu *vgpu)
|
struct vfio_device vfio_device;
|
||||||
{
|
struct vfio_region *region;
|
||||||
return vgpu->vdev;
|
int num_regions;
|
||||||
}
|
struct eventfd_ctx *intx_trigger;
|
||||||
|
struct eventfd_ctx *msi_trigger;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Two caches are used to avoid mapping duplicated pages (eg.
|
||||||
|
* scratch pages). This help to reduce dma setup overhead.
|
||||||
|
*/
|
||||||
|
struct rb_root gfn_cache;
|
||||||
|
struct rb_root dma_addr_cache;
|
||||||
|
unsigned long nr_cache_entries;
|
||||||
|
struct mutex cache_lock;
|
||||||
|
|
||||||
|
struct notifier_block iommu_notifier;
|
||||||
|
struct notifier_block group_notifier;
|
||||||
|
struct kvm *kvm;
|
||||||
|
struct work_struct release_work;
|
||||||
|
atomic_t released;
|
||||||
|
struct vfio_group *vfio_group;
|
||||||
|
|
||||||
|
struct kvm_page_track_notifier_node track_node;
|
||||||
|
#define NR_BKT (1 << 18)
|
||||||
|
struct hlist_head ptable[NR_BKT];
|
||||||
|
#undef NR_BKT
|
||||||
|
};
|
||||||
|
|
||||||
/* validating GM healthy status*/
|
/* validating GM healthy status*/
|
||||||
#define vgpu_is_vm_unhealthy(ret_val) \
|
#define vgpu_is_vm_unhealthy(ret_val) \
|
||||||
@ -272,7 +286,7 @@ struct intel_gvt_mmio {
|
|||||||
/* Value of command write of this reg needs to be patched */
|
/* Value of command write of this reg needs to be patched */
|
||||||
#define F_CMD_WRITE_PATCH (1 << 8)
|
#define F_CMD_WRITE_PATCH (1 << 8)
|
||||||
|
|
||||||
const struct gvt_mmio_block *mmio_block;
|
struct gvt_mmio_block *mmio_block;
|
||||||
unsigned int num_mmio_block;
|
unsigned int num_mmio_block;
|
||||||
|
|
||||||
DECLARE_HASHTABLE(mmio_info_table, INTEL_GVT_MMIO_HASH_BITS);
|
DECLARE_HASHTABLE(mmio_info_table, INTEL_GVT_MMIO_HASH_BITS);
|
||||||
@ -428,7 +442,6 @@ int intel_gvt_load_firmware(struct intel_gvt *gvt);
|
|||||||
#define RING_CTX_SIZE 320
|
#define RING_CTX_SIZE 320
|
||||||
|
|
||||||
struct intel_vgpu_creation_params {
|
struct intel_vgpu_creation_params {
|
||||||
__u64 handle;
|
|
||||||
__u64 low_gm_sz; /* in MB */
|
__u64 low_gm_sz; /* in MB */
|
||||||
__u64 high_gm_sz; /* in MB */
|
__u64 high_gm_sz; /* in MB */
|
||||||
__u64 fence_sz;
|
__u64 fence_sz;
|
||||||
@ -496,6 +509,9 @@ void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu);
|
|||||||
void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu);
|
void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu);
|
||||||
void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu);
|
void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu);
|
||||||
|
|
||||||
|
int intel_gvt_set_opregion(struct intel_vgpu *vgpu);
|
||||||
|
int intel_gvt_set_edid(struct intel_vgpu *vgpu, int port_num);
|
||||||
|
|
||||||
/* validating GM functions */
|
/* validating GM functions */
|
||||||
#define vgpu_gmadr_is_aperture(vgpu, gmadr) \
|
#define vgpu_gmadr_is_aperture(vgpu, gmadr) \
|
||||||
((gmadr >= vgpu_aperture_gmadr_base(vgpu)) && \
|
((gmadr >= vgpu_aperture_gmadr_base(vgpu)) && \
|
||||||
@ -557,30 +573,7 @@ void populate_pvinfo_page(struct intel_vgpu *vgpu);
|
|||||||
|
|
||||||
int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload);
|
int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload);
|
||||||
void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason);
|
void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason);
|
||||||
|
void intel_vgpu_detach_regions(struct intel_vgpu *vgpu);
|
||||||
struct intel_gvt_ops {
|
|
||||||
int (*emulate_cfg_read)(struct intel_vgpu *, unsigned int, void *,
|
|
||||||
unsigned int);
|
|
||||||
int (*emulate_cfg_write)(struct intel_vgpu *, unsigned int, void *,
|
|
||||||
unsigned int);
|
|
||||||
int (*emulate_mmio_read)(struct intel_vgpu *, u64, void *,
|
|
||||||
unsigned int);
|
|
||||||
int (*emulate_mmio_write)(struct intel_vgpu *, u64, void *,
|
|
||||||
unsigned int);
|
|
||||||
struct intel_vgpu *(*vgpu_create)(struct intel_gvt *,
|
|
||||||
struct intel_vgpu_type *);
|
|
||||||
void (*vgpu_destroy)(struct intel_vgpu *vgpu);
|
|
||||||
void (*vgpu_release)(struct intel_vgpu *vgpu);
|
|
||||||
void (*vgpu_reset)(struct intel_vgpu *);
|
|
||||||
void (*vgpu_activate)(struct intel_vgpu *);
|
|
||||||
void (*vgpu_deactivate)(struct intel_vgpu *);
|
|
||||||
int (*vgpu_query_plane)(struct intel_vgpu *vgpu, void *);
|
|
||||||
int (*vgpu_get_dmabuf)(struct intel_vgpu *vgpu, unsigned int);
|
|
||||||
int (*write_protect_handler)(struct intel_vgpu *, u64, void *,
|
|
||||||
unsigned int);
|
|
||||||
void (*emulate_hotplug)(struct intel_vgpu *vgpu, bool connected);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GVT_FAILSAFE_UNSUPPORTED_GUEST,
|
GVT_FAILSAFE_UNSUPPORTED_GUEST,
|
||||||
@ -724,13 +717,54 @@ static inline bool intel_gvt_mmio_is_cmd_write_patch(
|
|||||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_CMD_WRITE_PATCH;
|
return gvt->mmio.mmio_attribute[offset >> 2] & F_CMD_WRITE_PATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* intel_gvt_read_gpa - copy data from GPA to host data buffer
|
||||||
|
* @vgpu: a vGPU
|
||||||
|
* @gpa: guest physical address
|
||||||
|
* @buf: host data buffer
|
||||||
|
* @len: data length
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Zero on success, negative error code if failed.
|
||||||
|
*/
|
||||||
|
static inline int intel_gvt_read_gpa(struct intel_vgpu *vgpu, unsigned long gpa,
|
||||||
|
void *buf, unsigned long len)
|
||||||
|
{
|
||||||
|
if (!vgpu->attached)
|
||||||
|
return -ESRCH;
|
||||||
|
return vfio_dma_rw(vgpu->vfio_group, gpa, buf, len, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* intel_gvt_write_gpa - copy data from host data buffer to GPA
|
||||||
|
* @vgpu: a vGPU
|
||||||
|
* @gpa: guest physical address
|
||||||
|
* @buf: host data buffer
|
||||||
|
* @len: data length
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Zero on success, negative error code if failed.
|
||||||
|
*/
|
||||||
|
static inline int intel_gvt_write_gpa(struct intel_vgpu *vgpu,
|
||||||
|
unsigned long gpa, void *buf, unsigned long len)
|
||||||
|
{
|
||||||
|
if (!vgpu->attached)
|
||||||
|
return -ESRCH;
|
||||||
|
return vfio_dma_rw(vgpu->vfio_group, gpa, buf, len, true);
|
||||||
|
}
|
||||||
|
|
||||||
void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu);
|
void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu);
|
||||||
void intel_gvt_debugfs_init(struct intel_gvt *gvt);
|
void intel_gvt_debugfs_init(struct intel_gvt *gvt);
|
||||||
void intel_gvt_debugfs_clean(struct intel_gvt *gvt);
|
void intel_gvt_debugfs_clean(struct intel_gvt *gvt);
|
||||||
|
|
||||||
int intel_gvt_pm_resume(struct intel_gvt *gvt);
|
int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn);
|
||||||
|
int intel_gvt_page_track_remove(struct intel_vgpu *info, u64 gfn);
|
||||||
|
int intel_gvt_dma_pin_guest_page(struct intel_vgpu *vgpu, dma_addr_t dma_addr);
|
||||||
|
int intel_gvt_dma_map_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
||||||
|
unsigned long size, dma_addr_t *dma_addr);
|
||||||
|
void intel_gvt_dma_unmap_guest_page(struct intel_vgpu *vgpu,
|
||||||
|
dma_addr_t dma_addr);
|
||||||
|
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "mpt.h"
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the next
|
|
||||||
* paragraph) shall be included in all copies or substantial portions of the
|
|
||||||
* Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Eddie Dong <eddie.dong@intel.com>
|
|
||||||
* Dexuan Cui
|
|
||||||
* Jike Song <jike.song@intel.com>
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Zhi Wang <zhi.a.wang@intel.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _GVT_HYPERCALL_H_
|
|
||||||
#define _GVT_HYPERCALL_H_
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
struct device;
|
|
||||||
|
|
||||||
enum hypervisor_type {
|
|
||||||
INTEL_GVT_HYPERVISOR_XEN = 0,
|
|
||||||
INTEL_GVT_HYPERVISOR_KVM,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specific GVT-g MPT modules function collections. Currently GVT-g supports
|
|
||||||
* both Xen and KVM by providing dedicated hypervisor-related MPT modules.
|
|
||||||
*/
|
|
||||||
struct intel_gvt_mpt {
|
|
||||||
enum hypervisor_type type;
|
|
||||||
int (*host_init)(struct device *dev, void *gvt, const void *ops);
|
|
||||||
void (*host_exit)(struct device *dev, void *gvt);
|
|
||||||
int (*attach_vgpu)(void *vgpu, unsigned long *handle);
|
|
||||||
void (*detach_vgpu)(void *vgpu);
|
|
||||||
int (*inject_msi)(unsigned long handle, u32 addr, u16 data);
|
|
||||||
unsigned long (*from_virt_to_mfn)(void *p);
|
|
||||||
int (*enable_page_track)(unsigned long handle, u64 gfn);
|
|
||||||
int (*disable_page_track)(unsigned long handle, u64 gfn);
|
|
||||||
int (*read_gpa)(unsigned long handle, unsigned long gpa, void *buf,
|
|
||||||
unsigned long len);
|
|
||||||
int (*write_gpa)(unsigned long handle, unsigned long gpa, void *buf,
|
|
||||||
unsigned long len);
|
|
||||||
unsigned long (*gfn_to_mfn)(unsigned long handle, unsigned long gfn);
|
|
||||||
|
|
||||||
int (*dma_map_guest_page)(unsigned long handle, unsigned long gfn,
|
|
||||||
unsigned long size, dma_addr_t *dma_addr);
|
|
||||||
void (*dma_unmap_guest_page)(unsigned long handle, dma_addr_t dma_addr);
|
|
||||||
|
|
||||||
int (*dma_pin_guest_page)(unsigned long handle, dma_addr_t dma_addr);
|
|
||||||
|
|
||||||
int (*map_gfn_to_mfn)(unsigned long handle, unsigned long gfn,
|
|
||||||
unsigned long mfn, unsigned int nr, bool map);
|
|
||||||
int (*set_trap_area)(unsigned long handle, u64 start, u64 end,
|
|
||||||
bool map);
|
|
||||||
int (*set_opregion)(void *vgpu);
|
|
||||||
int (*set_edid)(void *vgpu, int port_num);
|
|
||||||
int (*get_vfio_device)(void *vgpu);
|
|
||||||
void (*put_vfio_device)(void *vgpu);
|
|
||||||
bool (*is_valid_gfn)(unsigned long handle, unsigned long gfn);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* _GVT_HYPERCALL_H_ */
|
|
@ -29,6 +29,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/eventfd.h>
|
||||||
|
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include "i915_reg.h"
|
#include "i915_reg.h"
|
||||||
#include "gvt.h"
|
#include "gvt.h"
|
||||||
@ -397,9 +399,45 @@ static void init_irq_map(struct intel_gvt_irq *irq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* =======================vEvent injection===================== */
|
/* =======================vEvent injection===================== */
|
||||||
|
|
||||||
|
#define MSI_CAP_CONTROL(offset) (offset + 2)
|
||||||
|
#define MSI_CAP_ADDRESS(offset) (offset + 4)
|
||||||
|
#define MSI_CAP_DATA(offset) (offset + 8)
|
||||||
|
#define MSI_CAP_EN 0x1
|
||||||
|
|
||||||
static int inject_virtual_interrupt(struct intel_vgpu *vgpu)
|
static int inject_virtual_interrupt(struct intel_vgpu *vgpu)
|
||||||
{
|
{
|
||||||
return intel_gvt_hypervisor_inject_msi(vgpu);
|
unsigned long offset = vgpu->gvt->device_info.msi_cap_offset;
|
||||||
|
u16 control, data;
|
||||||
|
u32 addr;
|
||||||
|
|
||||||
|
control = *(u16 *)(vgpu_cfg_space(vgpu) + MSI_CAP_CONTROL(offset));
|
||||||
|
addr = *(u32 *)(vgpu_cfg_space(vgpu) + MSI_CAP_ADDRESS(offset));
|
||||||
|
data = *(u16 *)(vgpu_cfg_space(vgpu) + MSI_CAP_DATA(offset));
|
||||||
|
|
||||||
|
/* Do not generate MSI if MSIEN is disabled */
|
||||||
|
if (!(control & MSI_CAP_EN))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (WARN(control & GENMASK(15, 1), "only support one MSI format\n"))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
trace_inject_msi(vgpu->id, addr, data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When guest is powered off, msi_trigger is set to NULL, but vgpu's
|
||||||
|
* config and mmio register isn't restored to default during guest
|
||||||
|
* poweroff. If this vgpu is still used in next vm, this vgpu's pipe
|
||||||
|
* may be enabled, then once this vgpu is active, it will get inject
|
||||||
|
* vblank interrupt request. But msi_trigger is null until msi is
|
||||||
|
* enabled by guest. so if msi_trigger is null, success is still
|
||||||
|
* returned and don't inject interrupt into guest.
|
||||||
|
*/
|
||||||
|
if (!vgpu->attached)
|
||||||
|
return -ESRCH;
|
||||||
|
if (vgpu->msi_trigger && eventfd_signal(vgpu->msi_trigger, 1) != 1)
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void propagate_event(struct intel_gvt_irq *irq,
|
static void propagate_event(struct intel_gvt_irq *irq,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -139,7 +139,7 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {
|
if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {
|
||||||
ret = intel_gvt_hypervisor_read_gpa(vgpu, pa, p_data, bytes);
|
ret = intel_gvt_read_gpa(vgpu, pa, p_data, bytes);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, u64 pa,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {
|
if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {
|
||||||
ret = intel_gvt_hypervisor_write_gpa(vgpu, pa, p_data, bytes);
|
ret = intel_gvt_write_gpa(vgpu, pa, p_data, bytes);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,6 @@ struct intel_gvt_mmio_info {
|
|||||||
const struct intel_engine_cs *
|
const struct intel_engine_cs *
|
||||||
intel_gvt_render_mmio_to_engine(struct intel_gvt *gvt, unsigned int reg);
|
intel_gvt_render_mmio_to_engine(struct intel_gvt *gvt, unsigned int reg);
|
||||||
unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt);
|
unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt);
|
||||||
bool intel_gvt_match_device(struct intel_gvt *gvt, unsigned long device);
|
|
||||||
|
|
||||||
int intel_gvt_setup_mmio_info(struct intel_gvt *gvt);
|
int intel_gvt_setup_mmio_info(struct intel_gvt *gvt);
|
||||||
void intel_gvt_clean_mmio_info(struct intel_gvt *gvt);
|
void intel_gvt_clean_mmio_info(struct intel_gvt *gvt);
|
||||||
|
@ -1,400 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the next
|
|
||||||
* paragraph) shall be included in all copies or substantial portions of the
|
|
||||||
* Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Eddie Dong <eddie.dong@intel.com>
|
|
||||||
* Dexuan Cui
|
|
||||||
* Jike Song <jike.song@intel.com>
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Zhi Wang <zhi.a.wang@intel.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _GVT_MPT_H_
|
|
||||||
#define _GVT_MPT_H_
|
|
||||||
|
|
||||||
#include "gvt.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DOC: Hypervisor Service APIs for GVT-g Core Logic
|
|
||||||
*
|
|
||||||
* This is the glue layer between specific hypervisor MPT modules and GVT-g core
|
|
||||||
* logic. Each kind of hypervisor MPT module provides a collection of function
|
|
||||||
* callbacks and will be attached to GVT host when the driver is loading.
|
|
||||||
* GVT-g core logic will call these APIs to request specific services from
|
|
||||||
* hypervisor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_host_init - init GVT-g host side
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_host_init(struct device *dev,
|
|
||||||
void *gvt, const void *ops)
|
|
||||||
{
|
|
||||||
if (!intel_gvt_host.mpt->host_init)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->host_init(dev, gvt, ops);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_host_exit - exit GVT-g host side
|
|
||||||
*/
|
|
||||||
static inline void intel_gvt_hypervisor_host_exit(struct device *dev, void *gvt)
|
|
||||||
{
|
|
||||||
/* optional to provide */
|
|
||||||
if (!intel_gvt_host.mpt->host_exit)
|
|
||||||
return;
|
|
||||||
|
|
||||||
intel_gvt_host.mpt->host_exit(dev, gvt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_attach_vgpu - call hypervisor to initialize vGPU
|
|
||||||
* related stuffs inside hypervisor.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_attach_vgpu(struct intel_vgpu *vgpu)
|
|
||||||
{
|
|
||||||
/* optional to provide */
|
|
||||||
if (!intel_gvt_host.mpt->attach_vgpu)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->attach_vgpu(vgpu, &vgpu->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_detach_vgpu - call hypervisor to release vGPU
|
|
||||||
* related stuffs inside hypervisor.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline void intel_gvt_hypervisor_detach_vgpu(struct intel_vgpu *vgpu)
|
|
||||||
{
|
|
||||||
/* optional to provide */
|
|
||||||
if (!intel_gvt_host.mpt->detach_vgpu)
|
|
||||||
return;
|
|
||||||
|
|
||||||
intel_gvt_host.mpt->detach_vgpu(vgpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MSI_CAP_CONTROL(offset) (offset + 2)
|
|
||||||
#define MSI_CAP_ADDRESS(offset) (offset + 4)
|
|
||||||
#define MSI_CAP_DATA(offset) (offset + 8)
|
|
||||||
#define MSI_CAP_EN 0x1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_inject_msi - inject a MSI interrupt into vGPU
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_inject_msi(struct intel_vgpu *vgpu)
|
|
||||||
{
|
|
||||||
unsigned long offset = vgpu->gvt->device_info.msi_cap_offset;
|
|
||||||
u16 control, data;
|
|
||||||
u32 addr;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
control = *(u16 *)(vgpu_cfg_space(vgpu) + MSI_CAP_CONTROL(offset));
|
|
||||||
addr = *(u32 *)(vgpu_cfg_space(vgpu) + MSI_CAP_ADDRESS(offset));
|
|
||||||
data = *(u16 *)(vgpu_cfg_space(vgpu) + MSI_CAP_DATA(offset));
|
|
||||||
|
|
||||||
/* Do not generate MSI if MSIEN is disable */
|
|
||||||
if (!(control & MSI_CAP_EN))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (WARN(control & GENMASK(15, 1), "only support one MSI format\n"))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
trace_inject_msi(vgpu->id, addr, data);
|
|
||||||
|
|
||||||
ret = intel_gvt_host.mpt->inject_msi(vgpu->handle, addr, data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_set_wp_page - translate a host VA into MFN
|
|
||||||
* @p: host kernel virtual address
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* MFN on success, INTEL_GVT_INVALID_ADDR if failed.
|
|
||||||
*/
|
|
||||||
static inline unsigned long intel_gvt_hypervisor_virt_to_mfn(void *p)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->from_virt_to_mfn(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_enable_page_track - track a guest page
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gfn: the gfn of guest
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_enable_page_track(
|
|
||||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->enable_page_track(vgpu->handle, gfn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_disable_page_track - untrack a guest page
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gfn: the gfn of guest
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_disable_page_track(
|
|
||||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->disable_page_track(vgpu->handle, gfn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_read_gpa - copy data from GPA to host data buffer
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gpa: guest physical address
|
|
||||||
* @buf: host data buffer
|
|
||||||
* @len: data length
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_read_gpa(struct intel_vgpu *vgpu,
|
|
||||||
unsigned long gpa, void *buf, unsigned long len)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->read_gpa(vgpu->handle, gpa, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_write_gpa - copy data from host data buffer to GPA
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gpa: guest physical address
|
|
||||||
* @buf: host data buffer
|
|
||||||
* @len: data length
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_write_gpa(struct intel_vgpu *vgpu,
|
|
||||||
unsigned long gpa, void *buf, unsigned long len)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->write_gpa(vgpu->handle, gpa, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_gfn_to_mfn - translate a GFN to MFN
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gpfn: guest pfn
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* MFN on success, INTEL_GVT_INVALID_ADDR if failed.
|
|
||||||
*/
|
|
||||||
static inline unsigned long intel_gvt_hypervisor_gfn_to_mfn(
|
|
||||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->gfn_to_mfn(vgpu->handle, gfn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_dma_map_guest_page - setup dma map for guest page
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gfn: guest pfn
|
|
||||||
* @size: page size
|
|
||||||
* @dma_addr: retrieve allocated dma addr
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* 0 on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_dma_map_guest_page(
|
|
||||||
struct intel_vgpu *vgpu, unsigned long gfn, unsigned long size,
|
|
||||||
dma_addr_t *dma_addr)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->dma_map_guest_page(vgpu->handle, gfn, size,
|
|
||||||
dma_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_dma_unmap_guest_page - cancel dma map for guest page
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @dma_addr: the mapped dma addr
|
|
||||||
*/
|
|
||||||
static inline void intel_gvt_hypervisor_dma_unmap_guest_page(
|
|
||||||
struct intel_vgpu *vgpu, dma_addr_t dma_addr)
|
|
||||||
{
|
|
||||||
intel_gvt_host.mpt->dma_unmap_guest_page(vgpu->handle, dma_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_dma_pin_guest_page - pin guest dma buf
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @dma_addr: guest dma addr
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* 0 on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
intel_gvt_hypervisor_dma_pin_guest_page(struct intel_vgpu *vgpu,
|
|
||||||
dma_addr_t dma_addr)
|
|
||||||
{
|
|
||||||
return intel_gvt_host.mpt->dma_pin_guest_page(vgpu->handle, dma_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_map_gfn_to_mfn - map a GFN region to MFN
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gfn: guest PFN
|
|
||||||
* @mfn: host PFN
|
|
||||||
* @nr: amount of PFNs
|
|
||||||
* @map: map or unmap
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_map_gfn_to_mfn(
|
|
||||||
struct intel_vgpu *vgpu, unsigned long gfn,
|
|
||||||
unsigned long mfn, unsigned int nr,
|
|
||||||
bool map)
|
|
||||||
{
|
|
||||||
/* a MPT implementation could have MMIO mapped elsewhere */
|
|
||||||
if (!intel_gvt_host.mpt->map_gfn_to_mfn)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->map_gfn_to_mfn(vgpu->handle, gfn, mfn, nr,
|
|
||||||
map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_set_trap_area - Trap a guest PA region
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @start: the beginning of the guest physical address region
|
|
||||||
* @end: the end of the guest physical address region
|
|
||||||
* @map: map or unmap
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_set_trap_area(
|
|
||||||
struct intel_vgpu *vgpu, u64 start, u64 end, bool map)
|
|
||||||
{
|
|
||||||
/* a MPT implementation could have MMIO trapped elsewhere */
|
|
||||||
if (!intel_gvt_host.mpt->set_trap_area)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->set_trap_area(vgpu->handle, start, end, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_set_opregion - Set opregion for guest
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_set_opregion(struct intel_vgpu *vgpu)
|
|
||||||
{
|
|
||||||
if (!intel_gvt_host.mpt->set_opregion)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->set_opregion(vgpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_set_edid - Set EDID region for guest
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @port_num: display port number
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_set_edid(struct intel_vgpu *vgpu,
|
|
||||||
int port_num)
|
|
||||||
{
|
|
||||||
if (!intel_gvt_host.mpt->set_edid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->set_edid(vgpu, port_num);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_get_vfio_device - increase vfio device ref count
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline int intel_gvt_hypervisor_get_vfio_device(struct intel_vgpu *vgpu)
|
|
||||||
{
|
|
||||||
if (!intel_gvt_host.mpt->get_vfio_device)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->get_vfio_device(vgpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_put_vfio_device - decrease vfio device ref count
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Zero on success, negative error code if failed.
|
|
||||||
*/
|
|
||||||
static inline void intel_gvt_hypervisor_put_vfio_device(struct intel_vgpu *vgpu)
|
|
||||||
{
|
|
||||||
if (!intel_gvt_host.mpt->put_vfio_device)
|
|
||||||
return;
|
|
||||||
|
|
||||||
intel_gvt_host.mpt->put_vfio_device(vgpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* intel_gvt_hypervisor_is_valid_gfn - check if a visible gfn
|
|
||||||
* @vgpu: a vGPU
|
|
||||||
* @gfn: guest PFN
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* true on valid gfn, false on not.
|
|
||||||
*/
|
|
||||||
static inline bool intel_gvt_hypervisor_is_valid_gfn(
|
|
||||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
|
||||||
{
|
|
||||||
if (!intel_gvt_host.mpt->is_valid_gfn)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return intel_gvt_host.mpt->is_valid_gfn(vgpu->handle, gfn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int intel_gvt_register_hypervisor(const struct intel_gvt_mpt *);
|
|
||||||
void intel_gvt_unregister_hypervisor(void);
|
|
||||||
|
|
||||||
#endif /* _GVT_MPT_H_ */
|
|
@ -255,33 +255,6 @@ int intel_vgpu_init_opregion(struct intel_vgpu *vgpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map)
|
|
||||||
{
|
|
||||||
u64 mfn;
|
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) {
|
|
||||||
mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu)->va
|
|
||||||
+ i * PAGE_SIZE);
|
|
||||||
if (mfn == INTEL_GVT_INVALID_ADDR) {
|
|
||||||
gvt_vgpu_err("fail to get MFN from VA\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu,
|
|
||||||
vgpu_opregion(vgpu)->gfn[i],
|
|
||||||
mfn, 1, map);
|
|
||||||
if (ret) {
|
|
||||||
gvt_vgpu_err("fail to map GFN to MFN, errno: %d\n",
|
|
||||||
ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vgpu_opregion(vgpu)->mapped = map;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_vgpu_opregion_base_write_handler - Opregion base register write handler
|
* intel_vgpu_opregion_base_write_handler - Opregion base register write handler
|
||||||
*
|
*
|
||||||
@ -294,34 +267,13 @@ static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map)
|
|||||||
int intel_vgpu_opregion_base_write_handler(struct intel_vgpu *vgpu, u32 gpa)
|
int intel_vgpu_opregion_base_write_handler(struct intel_vgpu *vgpu, u32 gpa)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, ret = 0;
|
int i;
|
||||||
|
|
||||||
gvt_dbg_core("emulate opregion from kernel\n");
|
gvt_dbg_core("emulate opregion from kernel\n");
|
||||||
|
|
||||||
switch (intel_gvt_host.hypervisor_type) {
|
for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++)
|
||||||
case INTEL_GVT_HYPERVISOR_KVM:
|
vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i;
|
||||||
for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++)
|
return 0;
|
||||||
vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i;
|
|
||||||
break;
|
|
||||||
case INTEL_GVT_HYPERVISOR_XEN:
|
|
||||||
/**
|
|
||||||
* Wins guest on Xengt will write this register twice: xen
|
|
||||||
* hvmloader and windows graphic driver.
|
|
||||||
*/
|
|
||||||
if (vgpu_opregion(vgpu)->mapped)
|
|
||||||
map_vgpu_opregion(vgpu, false);
|
|
||||||
|
|
||||||
for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++)
|
|
||||||
vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i;
|
|
||||||
|
|
||||||
ret = map_vgpu_opregion(vgpu, true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
gvt_vgpu_err("not supported hypervisor\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -336,12 +288,7 @@ void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu)
|
|||||||
if (!vgpu_opregion(vgpu)->va)
|
if (!vgpu_opregion(vgpu)->va)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) {
|
/* Guest opregion is released by VFIO */
|
||||||
if (vgpu_opregion(vgpu)->mapped)
|
|
||||||
map_vgpu_opregion(vgpu, false);
|
|
||||||
} else if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_KVM) {
|
|
||||||
/* Guest opregion is released by VFIO */
|
|
||||||
}
|
|
||||||
free_pages((unsigned long)vgpu_opregion(vgpu)->va,
|
free_pages((unsigned long)vgpu_opregion(vgpu)->va,
|
||||||
get_order(INTEL_GVT_OPREGION_SIZE));
|
get_order(INTEL_GVT_OPREGION_SIZE));
|
||||||
|
|
||||||
@ -470,39 +417,22 @@ int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci)
|
|||||||
u64 scic_pa = 0, parm_pa = 0;
|
u64 scic_pa = 0, parm_pa = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (intel_gvt_host.hypervisor_type) {
|
scic_pa = (vgpu_opregion(vgpu)->gfn[0] << PAGE_SHIFT) +
|
||||||
case INTEL_GVT_HYPERVISOR_XEN:
|
INTEL_GVT_OPREGION_SCIC;
|
||||||
scic = *((u32 *)vgpu_opregion(vgpu)->va +
|
parm_pa = (vgpu_opregion(vgpu)->gfn[0] << PAGE_SHIFT) +
|
||||||
INTEL_GVT_OPREGION_SCIC);
|
INTEL_GVT_OPREGION_PARM;
|
||||||
parm = *((u32 *)vgpu_opregion(vgpu)->va +
|
ret = intel_gvt_read_gpa(vgpu, scic_pa, &scic, sizeof(scic));
|
||||||
INTEL_GVT_OPREGION_PARM);
|
if (ret) {
|
||||||
break;
|
gvt_vgpu_err("guest opregion read error %d, gpa 0x%llx, len %lu\n",
|
||||||
case INTEL_GVT_HYPERVISOR_KVM:
|
ret, scic_pa, sizeof(scic));
|
||||||
scic_pa = (vgpu_opregion(vgpu)->gfn[0] << PAGE_SHIFT) +
|
return ret;
|
||||||
INTEL_GVT_OPREGION_SCIC;
|
}
|
||||||
parm_pa = (vgpu_opregion(vgpu)->gfn[0] << PAGE_SHIFT) +
|
|
||||||
INTEL_GVT_OPREGION_PARM;
|
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_read_gpa(vgpu, scic_pa,
|
ret = intel_gvt_read_gpa(vgpu, parm_pa, &parm, sizeof(parm));
|
||||||
&scic, sizeof(scic));
|
if (ret) {
|
||||||
if (ret) {
|
gvt_vgpu_err("guest opregion read error %d, gpa 0x%llx, len %lu\n",
|
||||||
gvt_vgpu_err("guest opregion read error %d, gpa 0x%llx, len %lu\n",
|
ret, scic_pa, sizeof(scic));
|
||||||
ret, scic_pa, sizeof(scic));
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_read_gpa(vgpu, parm_pa,
|
|
||||||
&parm, sizeof(parm));
|
|
||||||
if (ret) {
|
|
||||||
gvt_vgpu_err("guest opregion read error %d, gpa 0x%llx, len %lu\n",
|
|
||||||
ret, scic_pa, sizeof(scic));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
gvt_vgpu_err("not supported hypervisor\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(swsci & SWSCI_SCI_SELECT)) {
|
if (!(swsci & SWSCI_SCI_SELECT)) {
|
||||||
@ -535,34 +465,18 @@ int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci)
|
|||||||
parm = 0;
|
parm = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
switch (intel_gvt_host.hypervisor_type) {
|
ret = intel_gvt_write_gpa(vgpu, scic_pa, &scic, sizeof(scic));
|
||||||
case INTEL_GVT_HYPERVISOR_XEN:
|
if (ret) {
|
||||||
*((u32 *)vgpu_opregion(vgpu)->va +
|
gvt_vgpu_err("guest opregion write error %d, gpa 0x%llx, len %lu\n",
|
||||||
INTEL_GVT_OPREGION_SCIC) = scic;
|
ret, scic_pa, sizeof(scic));
|
||||||
*((u32 *)vgpu_opregion(vgpu)->va +
|
return ret;
|
||||||
INTEL_GVT_OPREGION_PARM) = parm;
|
}
|
||||||
break;
|
|
||||||
case INTEL_GVT_HYPERVISOR_KVM:
|
|
||||||
ret = intel_gvt_hypervisor_write_gpa(vgpu, scic_pa,
|
|
||||||
&scic, sizeof(scic));
|
|
||||||
if (ret) {
|
|
||||||
gvt_vgpu_err("guest opregion write error %d, gpa 0x%llx, len %lu\n",
|
|
||||||
ret, scic_pa, sizeof(scic));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_write_gpa(vgpu, parm_pa,
|
ret = intel_gvt_write_gpa(vgpu, parm_pa, &parm, sizeof(parm));
|
||||||
&parm, sizeof(parm));
|
if (ret) {
|
||||||
if (ret) {
|
gvt_vgpu_err("guest opregion write error %d, gpa 0x%llx, len %lu\n",
|
||||||
gvt_vgpu_err("guest opregion write error %d, gpa 0x%llx, len %lu\n",
|
ret, scic_pa, sizeof(scic));
|
||||||
ret, scic_pa, sizeof(scic));
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
gvt_vgpu_err("not supported hypervisor\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -87,7 +87,7 @@ void intel_vgpu_unregister_page_track(struct intel_vgpu *vgpu,
|
|||||||
track = radix_tree_delete(&vgpu->page_track_tree, gfn);
|
track = radix_tree_delete(&vgpu->page_track_tree, gfn);
|
||||||
if (track) {
|
if (track) {
|
||||||
if (track->tracked)
|
if (track->tracked)
|
||||||
intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
|
intel_gvt_page_track_remove(vgpu, gfn);
|
||||||
kfree(track);
|
kfree(track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
|
|||||||
if (track->tracked)
|
if (track->tracked)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_enable_page_track(vgpu, gfn);
|
ret = intel_gvt_page_track_add(vgpu, gfn);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
track->tracked = true;
|
track->tracked = true;
|
||||||
@ -139,7 +139,7 @@ int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
|
|||||||
if (!track->tracked)
|
if (!track->tracked)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
|
ret = intel_gvt_page_track_remove(vgpu, gfn);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
track->tracked = false;
|
track->tracked = false;
|
||||||
@ -172,7 +172,7 @@ int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa,
|
|||||||
|
|
||||||
if (unlikely(vgpu->failsafe)) {
|
if (unlikely(vgpu->failsafe)) {
|
||||||
/* Remove write protection to prevent furture traps. */
|
/* Remove write protection to prevent furture traps. */
|
||||||
intel_vgpu_disable_page_track(vgpu, gpa >> PAGE_SHIFT);
|
intel_gvt_page_track_remove(vgpu, gpa >> PAGE_SHIFT);
|
||||||
} else {
|
} else {
|
||||||
ret = page_track->handler(page_track, gpa, data, bytes);
|
ret = page_track->handler(page_track, gpa, data, bytes);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -132,6 +132,13 @@
|
|||||||
#define RING_GFX_MODE(base) _MMIO((base) + 0x29c)
|
#define RING_GFX_MODE(base) _MMIO((base) + 0x29c)
|
||||||
#define VF_GUARDBAND _MMIO(0x83a4)
|
#define VF_GUARDBAND _MMIO(0x83a4)
|
||||||
|
|
||||||
|
|
||||||
#define BCS_TILE_REGISTER_VAL_OFFSET (0x43*4)
|
#define BCS_TILE_REGISTER_VAL_OFFSET (0x43*4)
|
||||||
|
|
||||||
|
/* XXX FIXME i915 has changed PP_XXX definition */
|
||||||
|
#define PCH_PP_STATUS _MMIO(0xc7200)
|
||||||
|
#define PCH_PP_CONTROL _MMIO(0xc7204)
|
||||||
|
#define PCH_PP_ON_DELAYS _MMIO(0xc7208)
|
||||||
|
#define PCH_PP_OFF_DELAYS _MMIO(0xc720c)
|
||||||
|
#define PCH_PP_DIVISOR _MMIO(0xc7210)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -150,10 +150,10 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
|
|||||||
|
|
||||||
sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
|
sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
|
||||||
#define COPY_REG(name) \
|
#define COPY_REG(name) \
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
|
intel_gvt_read_gpa(vgpu, workload->ring_context_gpa \
|
||||||
+ RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
|
+ RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
|
||||||
#define COPY_REG_MASKED(name) {\
|
#define COPY_REG_MASKED(name) {\
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
|
intel_gvt_read_gpa(vgpu, workload->ring_context_gpa \
|
||||||
+ RING_CTX_OFF(name.val),\
|
+ RING_CTX_OFF(name.val),\
|
||||||
&shadow_ring_context->name.val, 4);\
|
&shadow_ring_context->name.val, 4);\
|
||||||
shadow_ring_context->name.val |= 0xffff << 16;\
|
shadow_ring_context->name.val |= 0xffff << 16;\
|
||||||
@ -167,7 +167,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
|
|||||||
COPY_REG(rcs_indirect_ctx);
|
COPY_REG(rcs_indirect_ctx);
|
||||||
COPY_REG(rcs_indirect_ctx_offset);
|
COPY_REG(rcs_indirect_ctx_offset);
|
||||||
} else if (workload->engine->id == BCS0)
|
} else if (workload->engine->id == BCS0)
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu,
|
intel_gvt_read_gpa(vgpu,
|
||||||
workload->ring_context_gpa +
|
workload->ring_context_gpa +
|
||||||
BCS_TILE_REGISTER_VAL_OFFSET,
|
BCS_TILE_REGISTER_VAL_OFFSET,
|
||||||
(void *)shadow_ring_context +
|
(void *)shadow_ring_context +
|
||||||
@ -178,7 +178,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
|
|||||||
/* don't copy Ring Context (the first 0x50 dwords),
|
/* don't copy Ring Context (the first 0x50 dwords),
|
||||||
* only copy the Engine Context part from guest
|
* only copy the Engine Context part from guest
|
||||||
*/
|
*/
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu,
|
intel_gvt_read_gpa(vgpu,
|
||||||
workload->ring_context_gpa +
|
workload->ring_context_gpa +
|
||||||
RING_CTX_SIZE,
|
RING_CTX_SIZE,
|
||||||
(void *)shadow_ring_context +
|
(void *)shadow_ring_context +
|
||||||
@ -245,7 +245,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
read:
|
read:
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, gpa_base, dst, gpa_size);
|
intel_gvt_read_gpa(vgpu, gpa_base, dst, gpa_size);
|
||||||
gpa_base = context_gpa;
|
gpa_base = context_gpa;
|
||||||
gpa_size = I915_GTT_PAGE_SIZE;
|
gpa_size = I915_GTT_PAGE_SIZE;
|
||||||
dst = context_base + (i << I915_GTT_PAGE_SHIFT);
|
dst = context_base + (i << I915_GTT_PAGE_SHIFT);
|
||||||
@ -911,8 +911,7 @@ static void update_guest_pdps(struct intel_vgpu *vgpu,
|
|||||||
gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
|
gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu,
|
intel_gvt_write_gpa(vgpu, gpa + i * 8, &pdp[7 - i], 4);
|
||||||
gpa + i * 8, &pdp[7 - i], 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __maybe_unused bool
|
static __maybe_unused bool
|
||||||
@ -1007,13 +1006,13 @@ static void update_guest_context(struct intel_vgpu_workload *workload)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
write:
|
write:
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu, gpa_base, src, gpa_size);
|
intel_gvt_write_gpa(vgpu, gpa_base, src, gpa_size);
|
||||||
gpa_base = context_gpa;
|
gpa_base = context_gpa;
|
||||||
gpa_size = I915_GTT_PAGE_SIZE;
|
gpa_size = I915_GTT_PAGE_SIZE;
|
||||||
src = context_base + (i << I915_GTT_PAGE_SHIFT);
|
src = context_base + (i << I915_GTT_PAGE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa +
|
intel_gvt_write_gpa(vgpu, workload->ring_context_gpa +
|
||||||
RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
|
RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
|
||||||
|
|
||||||
shadow_ring_context = (void *) ctx->lrc_reg_state;
|
shadow_ring_context = (void *) ctx->lrc_reg_state;
|
||||||
@ -1028,7 +1027,7 @@ write:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define COPY_REG(name) \
|
#define COPY_REG(name) \
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa + \
|
intel_gvt_write_gpa(vgpu, workload->ring_context_gpa + \
|
||||||
RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
|
RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
|
||||||
|
|
||||||
COPY_REG(ctx_ctrl);
|
COPY_REG(ctx_ctrl);
|
||||||
@ -1036,7 +1035,7 @@ write:
|
|||||||
|
|
||||||
#undef COPY_REG
|
#undef COPY_REG
|
||||||
|
|
||||||
intel_gvt_hypervisor_write_gpa(vgpu,
|
intel_gvt_write_gpa(vgpu,
|
||||||
workload->ring_context_gpa +
|
workload->ring_context_gpa +
|
||||||
sizeof(*shadow_ring_context),
|
sizeof(*shadow_ring_context),
|
||||||
(void *)shadow_ring_context +
|
(void *)shadow_ring_context +
|
||||||
@ -1573,7 +1572,7 @@ static void read_guest_pdps(struct intel_vgpu *vgpu,
|
|||||||
gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
|
gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu,
|
intel_gvt_read_gpa(vgpu,
|
||||||
gpa + i * 8, &pdp[7 - i], 4);
|
gpa + i * 8, &pdp[7 - i], 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1644,10 +1643,10 @@ intel_vgpu_create_workload(struct intel_vgpu *vgpu,
|
|||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(ring_header.val), &head, 4);
|
RING_CTX_OFF(ring_header.val), &head, 4);
|
||||||
|
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(ring_tail.val), &tail, 4);
|
RING_CTX_OFF(ring_tail.val), &tail, 4);
|
||||||
|
|
||||||
guest_head = head;
|
guest_head = head;
|
||||||
@ -1674,11 +1673,11 @@ intel_vgpu_create_workload(struct intel_vgpu *vgpu,
|
|||||||
gvt_dbg_el("ring %s begin a new workload\n", engine->name);
|
gvt_dbg_el("ring %s begin a new workload\n", engine->name);
|
||||||
|
|
||||||
/* record some ring buffer register values for scan and shadow */
|
/* record some ring buffer register values for scan and shadow */
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(rb_start.val), &start, 4);
|
RING_CTX_OFF(rb_start.val), &start, 4);
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(rb_ctrl.val), &ctl, 4);
|
RING_CTX_OFF(rb_ctrl.val), &ctl, 4);
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(ctx_ctrl.val), &ctx_ctl, 4);
|
RING_CTX_OFF(ctx_ctrl.val), &ctx_ctl, 4);
|
||||||
|
|
||||||
if (!intel_gvt_ggtt_validate_range(vgpu, start,
|
if (!intel_gvt_ggtt_validate_range(vgpu, start,
|
||||||
@ -1701,9 +1700,9 @@ intel_vgpu_create_workload(struct intel_vgpu *vgpu,
|
|||||||
workload->rb_ctl = ctl;
|
workload->rb_ctl = ctl;
|
||||||
|
|
||||||
if (engine->id == RCS0) {
|
if (engine->id == RCS0) {
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(bb_per_ctx_ptr.val), &per_ctx, 4);
|
RING_CTX_OFF(bb_per_ctx_ptr.val), &per_ctx, 4);
|
||||||
intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
|
intel_gvt_read_gpa(vgpu, ring_context_gpa +
|
||||||
RING_CTX_OFF(rcs_indirect_ctx.val), &indirect_ctx, 4);
|
RING_CTX_OFF(rcs_indirect_ctx.val), &indirect_ctx, 4);
|
||||||
|
|
||||||
workload->wa_ctx.indirect_ctx.guest_gma =
|
workload->wa_ctx.indirect_ctx.guest_gma =
|
||||||
|
@ -377,7 +377,7 @@ TRACE_EVENT(render_mmio,
|
|||||||
|
|
||||||
/* This part must be out of protection */
|
/* This part must be out of protection */
|
||||||
#undef TRACE_INCLUDE_PATH
|
#undef TRACE_INCLUDE_PATH
|
||||||
#define TRACE_INCLUDE_PATH .
|
|
||||||
#undef TRACE_INCLUDE_FILE
|
#undef TRACE_INCLUDE_FILE
|
||||||
|
#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/i915/gvt
|
||||||
#define TRACE_INCLUDE_FILE trace
|
#define TRACE_INCLUDE_FILE trace
|
||||||
#include <trace/define_trace.h>
|
#include <trace/define_trace.h>
|
||||||
|
@ -293,7 +293,7 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu)
|
|||||||
intel_vgpu_clean_opregion(vgpu);
|
intel_vgpu_clean_opregion(vgpu);
|
||||||
intel_vgpu_reset_ggtt(vgpu, true);
|
intel_vgpu_reset_ggtt(vgpu, true);
|
||||||
intel_vgpu_clean_gtt(vgpu);
|
intel_vgpu_clean_gtt(vgpu);
|
||||||
intel_gvt_hypervisor_detach_vgpu(vgpu);
|
intel_vgpu_detach_regions(vgpu);
|
||||||
intel_vgpu_free_resource(vgpu);
|
intel_vgpu_free_resource(vgpu);
|
||||||
intel_vgpu_clean_mmio(vgpu);
|
intel_vgpu_clean_mmio(vgpu);
|
||||||
intel_vgpu_dmabuf_cleanup(vgpu);
|
intel_vgpu_dmabuf_cleanup(vgpu);
|
||||||
@ -370,8 +370,8 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
|
|||||||
struct intel_vgpu *vgpu;
|
struct intel_vgpu *vgpu;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
gvt_dbg_core("handle %llu low %llu MB high %llu MB fence %llu\n",
|
gvt_dbg_core("low %llu MB high %llu MB fence %llu\n",
|
||||||
param->handle, param->low_gm_sz, param->high_gm_sz,
|
param->low_gm_sz, param->high_gm_sz,
|
||||||
param->fence_sz);
|
param->fence_sz);
|
||||||
|
|
||||||
vgpu = vzalloc(sizeof(*vgpu));
|
vgpu = vzalloc(sizeof(*vgpu));
|
||||||
@ -384,7 +384,6 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
|
|||||||
goto out_free_vgpu;
|
goto out_free_vgpu;
|
||||||
|
|
||||||
vgpu->id = ret;
|
vgpu->id = ret;
|
||||||
vgpu->handle = param->handle;
|
|
||||||
vgpu->gvt = gvt;
|
vgpu->gvt = gvt;
|
||||||
vgpu->sched_ctl.weight = param->weight;
|
vgpu->sched_ctl.weight = param->weight;
|
||||||
mutex_init(&vgpu->vgpu_lock);
|
mutex_init(&vgpu->vgpu_lock);
|
||||||
@ -405,13 +404,9 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
|
|||||||
|
|
||||||
populate_pvinfo_page(vgpu);
|
populate_pvinfo_page(vgpu);
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_attach_vgpu(vgpu);
|
|
||||||
if (ret)
|
|
||||||
goto out_clean_vgpu_resource;
|
|
||||||
|
|
||||||
ret = intel_vgpu_init_gtt(vgpu);
|
ret = intel_vgpu_init_gtt(vgpu);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_detach_hypervisor_vgpu;
|
goto out_clean_vgpu_resource;
|
||||||
|
|
||||||
ret = intel_vgpu_init_opregion(vgpu);
|
ret = intel_vgpu_init_opregion(vgpu);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -431,14 +426,14 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
|
|||||||
|
|
||||||
intel_gvt_debugfs_add_vgpu(vgpu);
|
intel_gvt_debugfs_add_vgpu(vgpu);
|
||||||
|
|
||||||
ret = intel_gvt_hypervisor_set_opregion(vgpu);
|
ret = intel_gvt_set_opregion(vgpu);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_clean_sched_policy;
|
goto out_clean_sched_policy;
|
||||||
|
|
||||||
if (IS_BROADWELL(dev_priv) || IS_BROXTON(dev_priv))
|
if (IS_BROADWELL(dev_priv) || IS_BROXTON(dev_priv))
|
||||||
ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_B);
|
ret = intel_gvt_set_edid(vgpu, PORT_B);
|
||||||
else
|
else
|
||||||
ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_D);
|
ret = intel_gvt_set_edid(vgpu, PORT_D);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_clean_sched_policy;
|
goto out_clean_sched_policy;
|
||||||
|
|
||||||
@ -454,8 +449,6 @@ out_clean_opregion:
|
|||||||
intel_vgpu_clean_opregion(vgpu);
|
intel_vgpu_clean_opregion(vgpu);
|
||||||
out_clean_gtt:
|
out_clean_gtt:
|
||||||
intel_vgpu_clean_gtt(vgpu);
|
intel_vgpu_clean_gtt(vgpu);
|
||||||
out_detach_hypervisor_vgpu:
|
|
||||||
intel_gvt_hypervisor_detach_vgpu(vgpu);
|
|
||||||
out_clean_vgpu_resource:
|
out_clean_vgpu_resource:
|
||||||
intel_vgpu_free_resource(vgpu);
|
intel_vgpu_free_resource(vgpu);
|
||||||
out_clean_vgpu_mmio:
|
out_clean_vgpu_mmio:
|
||||||
@ -483,7 +476,6 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
|
|||||||
struct intel_vgpu_creation_params param;
|
struct intel_vgpu_creation_params param;
|
||||||
struct intel_vgpu *vgpu;
|
struct intel_vgpu *vgpu;
|
||||||
|
|
||||||
param.handle = 0;
|
|
||||||
param.primary = 1;
|
param.primary = 1;
|
||||||
param.low_gm_sz = type->low_gm_size;
|
param.low_gm_sz = type->low_gm_size;
|
||||||
param.high_gm_sz = type->high_gm_size;
|
param.high_gm_sz = type->high_gm_size;
|
||||||
|
@ -465,11 +465,6 @@ static void i915_driver_mmio_release(struct drm_i915_private *dev_priv)
|
|||||||
pci_dev_put(dev_priv->bridge_dev);
|
pci_dev_put(dev_priv->bridge_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_sanitize_options(struct drm_i915_private *dev_priv)
|
|
||||||
{
|
|
||||||
intel_gvt_sanitize_options(dev_priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i915_set_dma_info - set all relevant PCI dma info as configured for the
|
* i915_set_dma_info - set all relevant PCI dma info as configured for the
|
||||||
* platform
|
* platform
|
||||||
@ -563,8 +558,6 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_sanitize_options(dev_priv);
|
|
||||||
|
|
||||||
/* needs to be done before ggtt probe */
|
/* needs to be done before ggtt probe */
|
||||||
intel_dram_edram_detect(dev_priv);
|
intel_dram_edram_detect(dev_priv);
|
||||||
|
|
||||||
|
@ -327,6 +327,7 @@ struct intel_vbt_data {
|
|||||||
bool override_afc_startup;
|
bool override_afc_startup;
|
||||||
u8 override_afc_startup_val;
|
u8 override_afc_startup_val;
|
||||||
|
|
||||||
|
u8 seamless_drrs_min_refresh_rate;
|
||||||
enum drrs_type drrs_type;
|
enum drrs_type drrs_type;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -401,6 +402,9 @@ struct i915_virtual_gpu {
|
|||||||
struct mutex lock; /* serialises sending of g2v_notify command pkts */
|
struct mutex lock; /* serialises sending of g2v_notify command pkts */
|
||||||
bool active;
|
bool active;
|
||||||
u32 caps;
|
u32 caps;
|
||||||
|
u32 *initial_mmio;
|
||||||
|
u8 *initial_cfg_space;
|
||||||
|
struct list_head entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i915_selftest_stash {
|
struct i915_selftest_stash {
|
||||||
@ -1068,9 +1072,11 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
|
|||||||
#define IS_DG2_G12(dev_priv) \
|
#define IS_DG2_G12(dev_priv) \
|
||||||
IS_SUBPLATFORM(dev_priv, INTEL_DG2, INTEL_SUBPLATFORM_G12)
|
IS_SUBPLATFORM(dev_priv, INTEL_DG2, INTEL_SUBPLATFORM_G12)
|
||||||
#define IS_ADLS_RPLS(dev_priv) \
|
#define IS_ADLS_RPLS(dev_priv) \
|
||||||
IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_S, INTEL_SUBPLATFORM_RPL_S)
|
IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_S, INTEL_SUBPLATFORM_RPL)
|
||||||
#define IS_ADLP_N(dev_priv) \
|
#define IS_ADLP_N(dev_priv) \
|
||||||
IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_P, INTEL_SUBPLATFORM_N)
|
IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_P, INTEL_SUBPLATFORM_N)
|
||||||
|
#define IS_ADLP_RPLP(dev_priv) \
|
||||||
|
IS_SUBPLATFORM(dev_priv, INTEL_ALDERLAKE_P, INTEL_SUBPLATFORM_RPL)
|
||||||
#define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \
|
#define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \
|
||||||
(INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00)
|
(INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00)
|
||||||
#define IS_BDW_ULT(dev_priv) \
|
#define IS_BDW_ULT(dev_priv) \
|
||||||
|
@ -1060,7 +1060,6 @@ static const struct intel_device_info xehpsdv_info = {
|
|||||||
BIT(VCS0) | BIT(VCS2) | \
|
BIT(VCS0) | BIT(VCS2) | \
|
||||||
BIT(CCS0) | BIT(CCS1) | BIT(CCS2) | BIT(CCS3)
|
BIT(CCS0) | BIT(CCS1) | BIT(CCS2) | BIT(CCS3)
|
||||||
|
|
||||||
__maybe_unused
|
|
||||||
static const struct intel_device_info dg2_info = {
|
static const struct intel_device_info dg2_info = {
|
||||||
DG2_FEATURES,
|
DG2_FEATURES,
|
||||||
XE_LPD_FEATURES,
|
XE_LPD_FEATURES,
|
||||||
@ -1176,6 +1175,8 @@ static const struct pci_device_id pciidlist[] = {
|
|||||||
INTEL_ADLN_IDS(&adl_p_info),
|
INTEL_ADLN_IDS(&adl_p_info),
|
||||||
INTEL_DG1_IDS(&dg1_info),
|
INTEL_DG1_IDS(&dg1_info),
|
||||||
INTEL_RPLS_IDS(&adl_s_info),
|
INTEL_RPLS_IDS(&adl_s_info),
|
||||||
|
INTEL_RPLP_IDS(&adl_p_info),
|
||||||
|
INTEL_DG2_IDS(&dg2_info),
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||||
|
@ -1404,6 +1404,7 @@
|
|||||||
#define DPFC_HT_MODIFY REG_BIT(31) /* pre-ivb */
|
#define DPFC_HT_MODIFY REG_BIT(31) /* pre-ivb */
|
||||||
#define DPFC_NUKE_ON_ANY_MODIFICATION REG_BIT(23) /* bdw+ */
|
#define DPFC_NUKE_ON_ANY_MODIFICATION REG_BIT(23) /* bdw+ */
|
||||||
#define DPFC_CHICKEN_COMP_DUMMY_PIXEL REG_BIT(14) /* glk+ */
|
#define DPFC_CHICKEN_COMP_DUMMY_PIXEL REG_BIT(14) /* glk+ */
|
||||||
|
#define DPFC_CHICKEN_FORCE_SLB_INVALIDATION REG_BIT(13) /* icl+ */
|
||||||
#define DPFC_DISABLE_DUMMY0 REG_BIT(8) /* ivb+ */
|
#define DPFC_DISABLE_DUMMY0 REG_BIT(8) /* ivb+ */
|
||||||
|
|
||||||
#define GLK_FBC_STRIDE(fbc_id) _MMIO_PIPE((fbc_id), 0x43228, 0x43268)
|
#define GLK_FBC_STRIDE(fbc_id) _MMIO_PIPE((fbc_id), 0x43228, 0x43268)
|
||||||
|
@ -182,8 +182,21 @@ static const u16 subplatform_n_ids[] = {
|
|||||||
INTEL_ADLN_IDS(0),
|
INTEL_ADLN_IDS(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u16 subplatform_rpls_ids[] = {
|
static const u16 subplatform_rpl_ids[] = {
|
||||||
INTEL_RPLS_IDS(0),
|
INTEL_RPLS_IDS(0),
|
||||||
|
INTEL_RPLP_IDS(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u16 subplatform_g10_ids[] = {
|
||||||
|
INTEL_DG2_G10_IDS(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u16 subplatform_g11_ids[] = {
|
||||||
|
INTEL_DG2_G11_IDS(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u16 subplatform_g12_ids[] = {
|
||||||
|
INTEL_DG2_G12_IDS(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool find_devid(u16 id, const u16 *p, unsigned int num)
|
static bool find_devid(u16 id, const u16 *p, unsigned int num)
|
||||||
@ -228,9 +241,18 @@ void intel_device_info_subplatform_init(struct drm_i915_private *i915)
|
|||||||
} else if (find_devid(devid, subplatform_n_ids,
|
} else if (find_devid(devid, subplatform_n_ids,
|
||||||
ARRAY_SIZE(subplatform_n_ids))) {
|
ARRAY_SIZE(subplatform_n_ids))) {
|
||||||
mask = BIT(INTEL_SUBPLATFORM_N);
|
mask = BIT(INTEL_SUBPLATFORM_N);
|
||||||
} else if (find_devid(devid, subplatform_rpls_ids,
|
} else if (find_devid(devid, subplatform_rpl_ids,
|
||||||
ARRAY_SIZE(subplatform_rpls_ids))) {
|
ARRAY_SIZE(subplatform_rpl_ids))) {
|
||||||
mask = BIT(INTEL_SUBPLATFORM_RPL_S);
|
mask = BIT(INTEL_SUBPLATFORM_RPL);
|
||||||
|
} else if (find_devid(devid, subplatform_g10_ids,
|
||||||
|
ARRAY_SIZE(subplatform_g10_ids))) {
|
||||||
|
mask = BIT(INTEL_SUBPLATFORM_G10);
|
||||||
|
} else if (find_devid(devid, subplatform_g11_ids,
|
||||||
|
ARRAY_SIZE(subplatform_g11_ids))) {
|
||||||
|
mask = BIT(INTEL_SUBPLATFORM_G11);
|
||||||
|
} else if (find_devid(devid, subplatform_g12_ids,
|
||||||
|
ARRAY_SIZE(subplatform_g12_ids))) {
|
||||||
|
mask = BIT(INTEL_SUBPLATFORM_G12);
|
||||||
}
|
}
|
||||||
|
|
||||||
GEM_BUG_ON(mask & ~INTEL_SUBPLATFORM_MASK);
|
GEM_BUG_ON(mask & ~INTEL_SUBPLATFORM_MASK);
|
||||||
|
@ -115,11 +115,16 @@ enum intel_platform {
|
|||||||
#define INTEL_SUBPLATFORM_G11 1
|
#define INTEL_SUBPLATFORM_G11 1
|
||||||
#define INTEL_SUBPLATFORM_G12 2
|
#define INTEL_SUBPLATFORM_G12 2
|
||||||
|
|
||||||
/* ADL-S */
|
/* ADL */
|
||||||
#define INTEL_SUBPLATFORM_RPL_S 0
|
#define INTEL_SUBPLATFORM_RPL 0
|
||||||
|
|
||||||
/* ADL-P */
|
/* ADL-P */
|
||||||
#define INTEL_SUBPLATFORM_N 0
|
/*
|
||||||
|
* As #define INTEL_SUBPLATFORM_RPL 0 will apply
|
||||||
|
* here too, SUBPLATFORM_N will have different
|
||||||
|
* bit set
|
||||||
|
*/
|
||||||
|
#define INTEL_SUBPLATFORM_N 1
|
||||||
|
|
||||||
enum intel_ppgtt_type {
|
enum intel_ppgtt_type {
|
||||||
INTEL_PPGTT_NONE = I915_GEM_PPGTT_NONE,
|
INTEL_PPGTT_NONE = I915_GEM_PPGTT_NONE,
|
||||||
|
@ -24,7 +24,10 @@
|
|||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include "i915_vgpu.h"
|
#include "i915_vgpu.h"
|
||||||
#include "intel_gvt.h"
|
#include "intel_gvt.h"
|
||||||
#include "gvt/gvt.h"
|
#include "gem/i915_gem_dmabuf.h"
|
||||||
|
#include "gt/intel_context.h"
|
||||||
|
#include "gt/intel_ring.h"
|
||||||
|
#include "gt/shmem_utils.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: Intel GVT-g host support
|
* DOC: Intel GVT-g host support
|
||||||
@ -41,6 +44,10 @@
|
|||||||
* doc is available on https://01.org/group/2230/documentation-list.
|
* doc is available on https://01.org/group/2230/documentation-list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static LIST_HEAD(intel_gvt_devices);
|
||||||
|
static const struct intel_vgpu_ops *intel_gvt_ops;
|
||||||
|
static DEFINE_MUTEX(intel_gvt_mutex);
|
||||||
|
|
||||||
static bool is_supported_device(struct drm_i915_private *dev_priv)
|
static bool is_supported_device(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
if (IS_BROADWELL(dev_priv))
|
if (IS_BROADWELL(dev_priv))
|
||||||
@ -59,33 +66,163 @@ static bool is_supported_device(struct drm_i915_private *dev_priv)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void free_initial_hw_state(struct drm_i915_private *dev_priv)
|
||||||
* intel_gvt_sanitize_options - sanitize GVT related options
|
|
||||||
* @dev_priv: drm i915 private data
|
|
||||||
*
|
|
||||||
* This function is called at the i915 options sanitize stage.
|
|
||||||
*/
|
|
||||||
void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv)
|
|
||||||
{
|
{
|
||||||
if (!dev_priv->params.enable_gvt)
|
struct i915_virtual_gpu *vgpu = &dev_priv->vgpu;
|
||||||
|
|
||||||
|
vfree(vgpu->initial_mmio);
|
||||||
|
vgpu->initial_mmio = NULL;
|
||||||
|
|
||||||
|
kfree(vgpu->initial_cfg_space);
|
||||||
|
vgpu->initial_cfg_space = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_mmio(struct intel_gvt_mmio_table_iter *iter, u32 offset,
|
||||||
|
u32 size)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = iter->i915;
|
||||||
|
u32 *mmio, i;
|
||||||
|
|
||||||
|
for (i = offset; i < offset + size; i += 4) {
|
||||||
|
mmio = iter->data + i;
|
||||||
|
*mmio = intel_uncore_read_notrace(to_gt(dev_priv)->uncore,
|
||||||
|
_MMIO(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_mmio(struct intel_gvt_mmio_table_iter *iter,
|
||||||
|
u32 offset, u32 size)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!IS_ALIGNED(offset, 4)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
save_mmio(iter, offset, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int save_initial_hw_state(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
|
||||||
|
struct i915_virtual_gpu *vgpu = &dev_priv->vgpu;
|
||||||
|
struct intel_gvt_mmio_table_iter iter;
|
||||||
|
void *mem;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
mem = kzalloc(PCI_CFG_SPACE_EXP_SIZE, GFP_KERNEL);
|
||||||
|
if (!mem)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
vgpu->initial_cfg_space = mem;
|
||||||
|
|
||||||
|
for (i = 0; i < PCI_CFG_SPACE_EXP_SIZE; i += 4)
|
||||||
|
pci_read_config_dword(pdev, i, mem + i);
|
||||||
|
|
||||||
|
mem = vzalloc(2 * SZ_1M);
|
||||||
|
if (!mem) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_mmio;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgpu->initial_mmio = mem;
|
||||||
|
|
||||||
|
iter.i915 = dev_priv;
|
||||||
|
iter.data = vgpu->initial_mmio;
|
||||||
|
iter.handle_mmio_cb = handle_mmio;
|
||||||
|
|
||||||
|
ret = intel_gvt_iterate_mmio_table(&iter);
|
||||||
|
if (ret)
|
||||||
|
goto err_iterate;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_iterate:
|
||||||
|
vfree(vgpu->initial_mmio);
|
||||||
|
vgpu->initial_mmio = NULL;
|
||||||
|
err_mmio:
|
||||||
|
kfree(vgpu->initial_cfg_space);
|
||||||
|
vgpu->initial_cfg_space = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_gvt_init_device(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
if (!dev_priv->params.enable_gvt) {
|
||||||
|
drm_dbg(&dev_priv->drm,
|
||||||
|
"GVT-g is disabled by kernel params\n");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (intel_vgpu_active(dev_priv)) {
|
if (intel_vgpu_active(dev_priv)) {
|
||||||
drm_info(&dev_priv->drm, "GVT-g is disabled for guest\n");
|
drm_info(&dev_priv->drm, "GVT-g is disabled for guest\n");
|
||||||
goto bail;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_supported_device(dev_priv)) {
|
if (!is_supported_device(dev_priv)) {
|
||||||
drm_info(&dev_priv->drm,
|
drm_info(&dev_priv->drm,
|
||||||
"Unsupported device. GVT-g is disabled\n");
|
"Unsupported device. GVT-g is disabled\n");
|
||||||
goto bail;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
if (intel_uc_wants_guc_submission(&to_gt(dev_priv)->uc)) {
|
||||||
bail:
|
drm_err(&dev_priv->drm,
|
||||||
dev_priv->params.enable_gvt = 0;
|
"Graphics virtualization is not yet supported with GuC submission\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save_initial_hw_state(dev_priv)) {
|
||||||
|
drm_dbg(&dev_priv->drm, "Failed to save initial HW state\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intel_gvt_ops->init_device(dev_priv))
|
||||||
|
drm_dbg(&dev_priv->drm, "Fail to init GVT device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
if (dev_priv->gvt)
|
||||||
|
intel_gvt_ops->clean_device(dev_priv);
|
||||||
|
free_initial_hw_state(dev_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int intel_gvt_set_ops(const struct intel_vgpu_ops *ops)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv;
|
||||||
|
|
||||||
|
mutex_lock(&intel_gvt_mutex);
|
||||||
|
if (intel_gvt_ops) {
|
||||||
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
intel_gvt_ops = ops;
|
||||||
|
|
||||||
|
list_for_each_entry(dev_priv, &intel_gvt_devices, vgpu.entry)
|
||||||
|
intel_gvt_init_device(dev_priv);
|
||||||
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_gvt_set_ops, I915_GVT);
|
||||||
|
|
||||||
|
void intel_gvt_clear_ops(const struct intel_vgpu_ops *ops)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv;
|
||||||
|
|
||||||
|
mutex_lock(&intel_gvt_mutex);
|
||||||
|
if (intel_gvt_ops != ops) {
|
||||||
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(dev_priv, &intel_gvt_devices, vgpu.entry)
|
||||||
|
intel_gvt_clean_device(dev_priv);
|
||||||
|
|
||||||
|
intel_gvt_ops = NULL;
|
||||||
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_gvt_clear_ops, I915_GVT);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_gvt_init - initialize GVT components
|
* intel_gvt_init - initialize GVT components
|
||||||
* @dev_priv: drm i915 private data
|
* @dev_priv: drm i915 private data
|
||||||
@ -98,39 +235,16 @@ bail:
|
|||||||
*/
|
*/
|
||||||
int intel_gvt_init(struct drm_i915_private *dev_priv)
|
int intel_gvt_init(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (i915_inject_probe_failure(dev_priv))
|
if (i915_inject_probe_failure(dev_priv))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!dev_priv->params.enable_gvt) {
|
mutex_lock(&intel_gvt_mutex);
|
||||||
drm_dbg(&dev_priv->drm,
|
list_add_tail(&dev_priv->vgpu.entry, &intel_gvt_devices);
|
||||||
"GVT-g is disabled by kernel params\n");
|
if (intel_gvt_ops)
|
||||||
return 0;
|
intel_gvt_init_device(dev_priv);
|
||||||
}
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
|
|
||||||
if (intel_uc_wants_guc_submission(&to_gt(dev_priv)->uc)) {
|
|
||||||
drm_err(&dev_priv->drm,
|
|
||||||
"i915 GVT-g loading failed due to Graphics virtualization is not yet supported with GuC submission\n");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = intel_gvt_init_device(dev_priv);
|
|
||||||
if (ret) {
|
|
||||||
drm_dbg(&dev_priv->drm, "Fail to init GVT device\n");
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bail:
|
|
||||||
dev_priv->params.enable_gvt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool intel_gvt_active(struct drm_i915_private *dev_priv)
|
|
||||||
{
|
|
||||||
return dev_priv->gvt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,10 +257,10 @@ static inline bool intel_gvt_active(struct drm_i915_private *dev_priv)
|
|||||||
*/
|
*/
|
||||||
void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)
|
void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
if (!intel_gvt_active(dev_priv))
|
mutex_lock(&intel_gvt_mutex);
|
||||||
return;
|
|
||||||
|
|
||||||
intel_gvt_clean_device(dev_priv);
|
intel_gvt_clean_device(dev_priv);
|
||||||
|
list_del(&dev_priv->vgpu.entry);
|
||||||
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,6 +273,50 @@ void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)
|
|||||||
*/
|
*/
|
||||||
void intel_gvt_resume(struct drm_i915_private *dev_priv)
|
void intel_gvt_resume(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
if (intel_gvt_active(dev_priv))
|
mutex_lock(&intel_gvt_mutex);
|
||||||
intel_gvt_pm_resume(dev_priv->gvt);
|
if (dev_priv->gvt)
|
||||||
|
intel_gvt_ops->pm_resume(dev_priv);
|
||||||
|
mutex_unlock(&intel_gvt_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exported here so that the exports only get created when GVT support is
|
||||||
|
* actually enabled.
|
||||||
|
*/
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_object_alloc, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_object_create_shmem, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_object_init, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_object_ggtt_pin_ww, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_object_pin_map, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_object_set_to_cpu_domain, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(__i915_gem_object_flush_map, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(__i915_gem_object_set_pages, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_gtt_insert, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_prime_export, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_ww_ctx_init, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_ww_ctx_backoff, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_gem_ww_ctx_fini, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_ppgtt_create, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_request_add, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_request_create, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_request_wait, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_reserve_fence, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_unreserve_fence, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_vm_release, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(_i915_vma_move_to_active, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_context_create, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(__intel_context_do_pin, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(__intel_context_do_unpin, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_ring_begin, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_runtime_pm_get, I915_GVT);
|
||||||
|
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_runtime_pm_put, I915_GVT);
|
||||||
|
#endif
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_runtime_pm_put_unchecked, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_uncore_forcewake_for_reg, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_uncore_forcewake_get, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(intel_uncore_forcewake_put, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(shmem_pin_map, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(shmem_unpin_map, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(__px_dma, I915_GVT);
|
||||||
|
EXPORT_SYMBOL_NS_GPL(i915_fence_ops, I915_GVT);
|
||||||
|
@ -24,16 +24,34 @@
|
|||||||
#ifndef _INTEL_GVT_H_
|
#ifndef _INTEL_GVT_H_
|
||||||
#define _INTEL_GVT_H_
|
#define _INTEL_GVT_H_
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_I915_GVT
|
#ifdef CONFIG_DRM_I915_GVT
|
||||||
|
|
||||||
|
struct intel_gvt_mmio_table_iter {
|
||||||
|
struct drm_i915_private *i915;
|
||||||
|
void *data;
|
||||||
|
int (*handle_mmio_cb)(struct intel_gvt_mmio_table_iter *iter,
|
||||||
|
u32 offset, u32 size);
|
||||||
|
};
|
||||||
|
|
||||||
int intel_gvt_init(struct drm_i915_private *dev_priv);
|
int intel_gvt_init(struct drm_i915_private *dev_priv);
|
||||||
void intel_gvt_driver_remove(struct drm_i915_private *dev_priv);
|
void intel_gvt_driver_remove(struct drm_i915_private *dev_priv);
|
||||||
int intel_gvt_init_device(struct drm_i915_private *dev_priv);
|
|
||||||
void intel_gvt_clean_device(struct drm_i915_private *dev_priv);
|
|
||||||
int intel_gvt_init_host(void);
|
int intel_gvt_init_host(void);
|
||||||
void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv);
|
|
||||||
void intel_gvt_resume(struct drm_i915_private *dev_priv);
|
void intel_gvt_resume(struct drm_i915_private *dev_priv);
|
||||||
|
int intel_gvt_iterate_mmio_table(struct intel_gvt_mmio_table_iter *iter);
|
||||||
|
|
||||||
|
struct intel_vgpu_ops {
|
||||||
|
int (*init_device)(struct drm_i915_private *dev_priv);
|
||||||
|
void (*clean_device)(struct drm_i915_private *dev_priv);
|
||||||
|
void (*pm_resume)(struct drm_i915_private *i915);
|
||||||
|
};
|
||||||
|
|
||||||
|
int intel_gvt_set_ops(const struct intel_vgpu_ops *ops);
|
||||||
|
void intel_gvt_clear_ops(const struct intel_vgpu_ops *ops);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static inline int intel_gvt_init(struct drm_i915_private *dev_priv)
|
static inline int intel_gvt_init(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
@ -44,12 +62,16 @@ static inline void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void intel_gvt_sanitize_options(struct drm_i915_private *dev_priv)
|
static inline void intel_gvt_resume(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void intel_gvt_resume(struct drm_i915_private *dev_priv)
|
struct intel_gvt_mmio_table_iter {
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int intel_gvt_iterate_mmio_table(struct intel_gvt_mmio_table_iter *iter)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
1292
drivers/gpu/drm/i915/intel_gvt_mmio_table.c
Normal file
1292
drivers/gpu/drm/i915/intel_gvt_mmio_table.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -5475,6 +5475,25 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
blocks = fixed16_to_u32_round_up(selected_result) + 1;
|
blocks = fixed16_to_u32_round_up(selected_result) + 1;
|
||||||
|
/*
|
||||||
|
* Lets have blocks at minimum equivalent to plane_blocks_per_line
|
||||||
|
* as there will be at minimum one line for lines configuration. This
|
||||||
|
* is a work around for FIFO underruns observed with resolutions like
|
||||||
|
* 4k 60 Hz in single channel DRAM configurations.
|
||||||
|
*
|
||||||
|
* As per the Bspec 49325, if the ddb allocation can hold at least
|
||||||
|
* one plane_blocks_per_line, we should have selected method2 in
|
||||||
|
* the above logic. Assuming that modern versions have enough dbuf
|
||||||
|
* and method2 guarantees blocks equivalent to at least 1 line,
|
||||||
|
* select the blocks as plane_blocks_per_line.
|
||||||
|
*
|
||||||
|
* TODO: Revisit the logic when we have better understanding on DRAM
|
||||||
|
* channels' impact on the level 0 memory latency and the relevant
|
||||||
|
* wm calculations.
|
||||||
|
*/
|
||||||
|
if (skl_wm_has_lines(dev_priv, level))
|
||||||
|
blocks = max(blocks,
|
||||||
|
fixed16_to_u32_round_up(wp->plane_blocks_per_line));
|
||||||
lines = div_round_up_fixed16(selected_result,
|
lines = div_round_up_fixed16(selected_result,
|
||||||
wp->plane_blocks_per_line);
|
wp->plane_blocks_per_line);
|
||||||
|
|
||||||
|
@ -656,17 +656,12 @@ struct mdev_driver vfio_ccw_mdev_driver = {
|
|||||||
},
|
},
|
||||||
.probe = vfio_ccw_mdev_probe,
|
.probe = vfio_ccw_mdev_probe,
|
||||||
.remove = vfio_ccw_mdev_remove,
|
.remove = vfio_ccw_mdev_remove,
|
||||||
};
|
|
||||||
|
|
||||||
static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.device_driver = &vfio_ccw_mdev_driver,
|
|
||||||
.supported_type_groups = mdev_type_groups,
|
.supported_type_groups = mdev_type_groups,
|
||||||
};
|
};
|
||||||
|
|
||||||
int vfio_ccw_mdev_reg(struct subchannel *sch)
|
int vfio_ccw_mdev_reg(struct subchannel *sch)
|
||||||
{
|
{
|
||||||
return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops);
|
return mdev_register_device(&sch->dev, &vfio_ccw_mdev_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfio_ccw_mdev_unreg(struct subchannel *sch)
|
void vfio_ccw_mdev_unreg(struct subchannel *sch)
|
||||||
|
@ -1496,12 +1496,7 @@ static struct mdev_driver vfio_ap_matrix_driver = {
|
|||||||
},
|
},
|
||||||
.probe = vfio_ap_mdev_probe,
|
.probe = vfio_ap_mdev_probe,
|
||||||
.remove = vfio_ap_mdev_remove,
|
.remove = vfio_ap_mdev_remove,
|
||||||
};
|
.supported_type_groups = vfio_ap_mdev_type_groups,
|
||||||
|
|
||||||
static const struct mdev_parent_ops vfio_ap_matrix_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.device_driver = &vfio_ap_matrix_driver,
|
|
||||||
.supported_type_groups = vfio_ap_mdev_type_groups,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int vfio_ap_mdev_register(void)
|
int vfio_ap_mdev_register(void)
|
||||||
@ -1514,7 +1509,7 @@ int vfio_ap_mdev_register(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mdev_register_device(&matrix_dev->device, &vfio_ap_matrix_ops);
|
ret = mdev_register_device(&matrix_dev->device, &vfio_ap_matrix_driver);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_driver;
|
goto err_driver;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o vfio_mdev.o
|
mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o
|
||||||
|
|
||||||
obj-$(CONFIG_VFIO_MDEV) += mdev.o
|
obj-$(CONFIG_VFIO_MDEV) += mdev.o
|
||||||
|
@ -89,17 +89,10 @@ void mdev_release_parent(struct kref *kref)
|
|||||||
static void mdev_device_remove_common(struct mdev_device *mdev)
|
static void mdev_device_remove_common(struct mdev_device *mdev)
|
||||||
{
|
{
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
struct mdev_parent *parent = mdev->type->parent;
|
||||||
int ret;
|
|
||||||
|
|
||||||
mdev_remove_sysfs_files(mdev);
|
mdev_remove_sysfs_files(mdev);
|
||||||
device_del(&mdev->dev);
|
device_del(&mdev->dev);
|
||||||
lockdep_assert_held(&parent->unreg_sem);
|
lockdep_assert_held(&parent->unreg_sem);
|
||||||
if (parent->ops->remove) {
|
|
||||||
ret = parent->ops->remove(mdev);
|
|
||||||
if (ret)
|
|
||||||
dev_err(&mdev->dev, "Remove failed: err=%d\n", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Balances with device_initialize() */
|
/* Balances with device_initialize() */
|
||||||
put_device(&mdev->dev);
|
put_device(&mdev->dev);
|
||||||
}
|
}
|
||||||
@ -116,12 +109,12 @@ static int mdev_device_remove_cb(struct device *dev, void *data)
|
|||||||
/*
|
/*
|
||||||
* mdev_register_device : Register a device
|
* mdev_register_device : Register a device
|
||||||
* @dev: device structure representing parent device.
|
* @dev: device structure representing parent device.
|
||||||
* @ops: Parent device operation structure to be registered.
|
* @mdev_driver: Device driver to bind to the newly created mdev
|
||||||
*
|
*
|
||||||
* Add device to list of registered parent devices.
|
* Add device to list of registered parent devices.
|
||||||
* Returns a negative value on error, otherwise 0.
|
* Returns a negative value on error, otherwise 0.
|
||||||
*/
|
*/
|
||||||
int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
|
int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct mdev_parent *parent;
|
struct mdev_parent *parent;
|
||||||
@ -129,9 +122,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
|
|||||||
char *envp[] = { env_string, NULL };
|
char *envp[] = { env_string, NULL };
|
||||||
|
|
||||||
/* check for mandatory ops */
|
/* check for mandatory ops */
|
||||||
if (!ops || !ops->supported_type_groups)
|
if (!mdev_driver->supported_type_groups)
|
||||||
return -EINVAL;
|
|
||||||
if (!ops->device_driver && (!ops->create || !ops->remove))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dev = get_device(dev);
|
dev = get_device(dev);
|
||||||
@ -158,7 +149,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
|
|||||||
init_rwsem(&parent->unreg_sem);
|
init_rwsem(&parent->unreg_sem);
|
||||||
|
|
||||||
parent->dev = dev;
|
parent->dev = dev;
|
||||||
parent->ops = ops;
|
parent->mdev_driver = mdev_driver;
|
||||||
|
|
||||||
if (!mdev_bus_compat_class) {
|
if (!mdev_bus_compat_class) {
|
||||||
mdev_bus_compat_class = class_compat_register("mdev_bus");
|
mdev_bus_compat_class = class_compat_register("mdev_bus");
|
||||||
@ -256,7 +247,7 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
|
|||||||
int ret;
|
int ret;
|
||||||
struct mdev_device *mdev, *tmp;
|
struct mdev_device *mdev, *tmp;
|
||||||
struct mdev_parent *parent = type->parent;
|
struct mdev_parent *parent = type->parent;
|
||||||
struct mdev_driver *drv = parent->ops->device_driver;
|
struct mdev_driver *drv = parent->mdev_driver;
|
||||||
|
|
||||||
mutex_lock(&mdev_list_lock);
|
mutex_lock(&mdev_list_lock);
|
||||||
|
|
||||||
@ -278,7 +269,7 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
|
|||||||
mdev->dev.parent = parent->dev;
|
mdev->dev.parent = parent->dev;
|
||||||
mdev->dev.bus = &mdev_bus_type;
|
mdev->dev.bus = &mdev_bus_type;
|
||||||
mdev->dev.release = mdev_device_release;
|
mdev->dev.release = mdev_device_release;
|
||||||
mdev->dev.groups = parent->ops->mdev_attr_groups;
|
mdev->dev.groups = mdev_device_groups;
|
||||||
mdev->type = type;
|
mdev->type = type;
|
||||||
/* Pairs with the put in mdev_device_release() */
|
/* Pairs with the put in mdev_device_release() */
|
||||||
kobject_get(&type->kobj);
|
kobject_get(&type->kobj);
|
||||||
@ -297,18 +288,10 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
|
|||||||
goto out_put_device;
|
goto out_put_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent->ops->create) {
|
|
||||||
ret = parent->ops->create(mdev);
|
|
||||||
if (ret)
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = device_add(&mdev->dev);
|
ret = device_add(&mdev->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_remove;
|
goto out_unlock;
|
||||||
|
|
||||||
if (!drv)
|
|
||||||
drv = &vfio_mdev_driver;
|
|
||||||
ret = device_driver_attach(&drv->driver, &mdev->dev);
|
ret = device_driver_attach(&drv->driver, &mdev->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_del;
|
goto out_del;
|
||||||
@ -325,9 +308,6 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
|
|||||||
|
|
||||||
out_del:
|
out_del:
|
||||||
device_del(&mdev->dev);
|
device_del(&mdev->dev);
|
||||||
out_remove:
|
|
||||||
if (parent->ops->remove)
|
|
||||||
parent->ops->remove(mdev);
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
up_read(&parent->unreg_sem);
|
up_read(&parent->unreg_sem);
|
||||||
out_put_device:
|
out_put_device:
|
||||||
@ -370,28 +350,14 @@ int mdev_device_remove(struct mdev_device *mdev)
|
|||||||
|
|
||||||
static int __init mdev_init(void)
|
static int __init mdev_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
return bus_register(&mdev_bus_type);
|
||||||
|
|
||||||
rc = mdev_bus_register();
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
rc = mdev_register_driver(&vfio_mdev_driver);
|
|
||||||
if (rc)
|
|
||||||
goto err_bus;
|
|
||||||
return 0;
|
|
||||||
err_bus:
|
|
||||||
mdev_bus_unregister();
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit mdev_exit(void)
|
static void __exit mdev_exit(void)
|
||||||
{
|
{
|
||||||
mdev_unregister_driver(&vfio_mdev_driver);
|
|
||||||
|
|
||||||
if (mdev_bus_compat_class)
|
if (mdev_bus_compat_class)
|
||||||
class_compat_unregister(mdev_bus_compat_class);
|
class_compat_unregister(mdev_bus_compat_class);
|
||||||
|
bus_unregister(&mdev_bus_type);
|
||||||
mdev_bus_unregister();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(mdev_init)
|
subsys_initcall(mdev_init)
|
||||||
|
@ -74,13 +74,3 @@ void mdev_unregister_driver(struct mdev_driver *drv)
|
|||||||
driver_unregister(&drv->driver);
|
driver_unregister(&drv->driver);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mdev_unregister_driver);
|
EXPORT_SYMBOL(mdev_unregister_driver);
|
||||||
|
|
||||||
int mdev_bus_register(void)
|
|
||||||
{
|
|
||||||
return bus_register(&mdev_bus_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mdev_bus_unregister(void)
|
|
||||||
{
|
|
||||||
bus_unregister(&mdev_bus_type);
|
|
||||||
}
|
|
||||||
|
@ -15,7 +15,7 @@ void mdev_bus_unregister(void);
|
|||||||
|
|
||||||
struct mdev_parent {
|
struct mdev_parent {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
const struct mdev_parent_ops *ops;
|
struct mdev_driver *mdev_driver;
|
||||||
struct kref ref;
|
struct kref ref;
|
||||||
struct list_head next;
|
struct list_head next;
|
||||||
struct kset *mdev_types_kset;
|
struct kset *mdev_types_kset;
|
||||||
@ -32,13 +32,13 @@ struct mdev_type {
|
|||||||
unsigned int type_group_id;
|
unsigned int type_group_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const struct attribute_group *mdev_device_groups[];
|
||||||
|
|
||||||
#define to_mdev_type_attr(_attr) \
|
#define to_mdev_type_attr(_attr) \
|
||||||
container_of(_attr, struct mdev_type_attribute, attr)
|
container_of(_attr, struct mdev_type_attribute, attr)
|
||||||
#define to_mdev_type(_kobj) \
|
#define to_mdev_type(_kobj) \
|
||||||
container_of(_kobj, struct mdev_type, kobj)
|
container_of(_kobj, struct mdev_type, kobj)
|
||||||
|
|
||||||
extern struct mdev_driver vfio_mdev_driver;
|
|
||||||
|
|
||||||
int parent_create_sysfs_files(struct mdev_parent *parent);
|
int parent_create_sysfs_files(struct mdev_parent *parent);
|
||||||
void parent_remove_sysfs_files(struct mdev_parent *parent);
|
void parent_remove_sysfs_files(struct mdev_parent *parent);
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
|
|||||||
{
|
{
|
||||||
struct mdev_type *type;
|
struct mdev_type *type;
|
||||||
struct attribute_group *group =
|
struct attribute_group *group =
|
||||||
parent->ops->supported_type_groups[type_group_id];
|
parent->mdev_driver->supported_type_groups[type_group_id];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!group->name) {
|
if (!group->name) {
|
||||||
@ -154,7 +154,7 @@ attr_create_failed:
|
|||||||
static void remove_mdev_supported_type(struct mdev_type *type)
|
static void remove_mdev_supported_type(struct mdev_type *type)
|
||||||
{
|
{
|
||||||
struct attribute_group *group =
|
struct attribute_group *group =
|
||||||
type->parent->ops->supported_type_groups[type->type_group_id];
|
type->parent->mdev_driver->supported_type_groups[type->type_group_id];
|
||||||
|
|
||||||
sysfs_remove_files(&type->kobj,
|
sysfs_remove_files(&type->kobj,
|
||||||
(const struct attribute **)group->attrs);
|
(const struct attribute **)group->attrs);
|
||||||
@ -168,7 +168,7 @@ static int add_mdev_supported_type_groups(struct mdev_parent *parent)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; parent->ops->supported_type_groups[i]; i++) {
|
for (i = 0; parent->mdev_driver->supported_type_groups[i]; i++) {
|
||||||
struct mdev_type *type;
|
struct mdev_type *type;
|
||||||
|
|
||||||
type = add_mdev_supported_type(parent, i);
|
type = add_mdev_supported_type(parent, i);
|
||||||
@ -197,7 +197,6 @@ void parent_remove_sysfs_files(struct mdev_parent *parent)
|
|||||||
remove_mdev_supported_type(type);
|
remove_mdev_supported_type(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
sysfs_remove_groups(&parent->dev->kobj, parent->ops->dev_attr_groups);
|
|
||||||
kset_unregister(parent->mdev_types_kset);
|
kset_unregister(parent->mdev_types_kset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,17 +212,10 @@ int parent_create_sysfs_files(struct mdev_parent *parent)
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&parent->type_list);
|
INIT_LIST_HEAD(&parent->type_list);
|
||||||
|
|
||||||
ret = sysfs_create_groups(&parent->dev->kobj,
|
|
||||||
parent->ops->dev_attr_groups);
|
|
||||||
if (ret)
|
|
||||||
goto create_err;
|
|
||||||
|
|
||||||
ret = add_mdev_supported_type_groups(parent);
|
ret = add_mdev_supported_type_groups(parent);
|
||||||
if (ret)
|
if (ret)
|
||||||
sysfs_remove_groups(&parent->dev->kobj,
|
goto create_err;
|
||||||
parent->ops->dev_attr_groups);
|
return 0;
|
||||||
else
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
create_err:
|
create_err:
|
||||||
kset_unregister(parent->mdev_types_kset);
|
kset_unregister(parent->mdev_types_kset);
|
||||||
@ -252,11 +244,20 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
|
|||||||
|
|
||||||
static DEVICE_ATTR_WO(remove);
|
static DEVICE_ATTR_WO(remove);
|
||||||
|
|
||||||
static const struct attribute *mdev_device_attrs[] = {
|
static struct attribute *mdev_device_attrs[] = {
|
||||||
&dev_attr_remove.attr,
|
&dev_attr_remove.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group mdev_device_group = {
|
||||||
|
.attrs = mdev_device_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct attribute_group *mdev_device_groups[] = {
|
||||||
|
&mdev_device_group,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
int mdev_create_sysfs_files(struct mdev_device *mdev)
|
int mdev_create_sysfs_files(struct mdev_device *mdev)
|
||||||
{
|
{
|
||||||
struct mdev_type *type = mdev->type;
|
struct mdev_type *type = mdev->type;
|
||||||
@ -270,15 +271,8 @@ int mdev_create_sysfs_files(struct mdev_device *mdev)
|
|||||||
ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");
|
ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");
|
||||||
if (ret)
|
if (ret)
|
||||||
goto type_link_failed;
|
goto type_link_failed;
|
||||||
|
|
||||||
ret = sysfs_create_files(kobj, mdev_device_attrs);
|
|
||||||
if (ret)
|
|
||||||
goto create_files_failed;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
create_files_failed:
|
|
||||||
sysfs_remove_link(kobj, "mdev_type");
|
|
||||||
type_link_failed:
|
type_link_failed:
|
||||||
sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
|
sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
|
||||||
return ret;
|
return ret;
|
||||||
@ -288,7 +282,6 @@ void mdev_remove_sysfs_files(struct mdev_device *mdev)
|
|||||||
{
|
{
|
||||||
struct kobject *kobj = &mdev->dev.kobj;
|
struct kobject *kobj = &mdev->dev.kobj;
|
||||||
|
|
||||||
sysfs_remove_files(kobj, mdev_device_attrs);
|
|
||||||
sysfs_remove_link(kobj, "mdev_type");
|
sysfs_remove_link(kobj, "mdev_type");
|
||||||
sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
|
sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
|
||||||
}
|
}
|
||||||
|
@ -1,152 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
/*
|
|
||||||
* VFIO based driver for Mediated device
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
* Author: Neo Jia <cjia@nvidia.com>
|
|
||||||
* Kirti Wankhede <kwankhede@nvidia.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/vfio.h>
|
|
||||||
#include <linux/mdev.h>
|
|
||||||
|
|
||||||
#include "mdev_private.h"
|
|
||||||
|
|
||||||
static int vfio_mdev_open_device(struct vfio_device *core_vdev)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (unlikely(!parent->ops->open_device))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return parent->ops->open_device(mdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfio_mdev_close_device(struct vfio_device *core_vdev)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (likely(parent->ops->close_device))
|
|
||||||
parent->ops->close_device(mdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long vfio_mdev_unlocked_ioctl(struct vfio_device *core_vdev,
|
|
||||||
unsigned int cmd, unsigned long arg)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (unlikely(!parent->ops->ioctl))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return parent->ops->ioctl(mdev, cmd, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t vfio_mdev_read(struct vfio_device *core_vdev, char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (unlikely(!parent->ops->read))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return parent->ops->read(mdev, buf, count, ppos);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t vfio_mdev_write(struct vfio_device *core_vdev,
|
|
||||||
const char __user *buf, size_t count,
|
|
||||||
loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (unlikely(!parent->ops->write))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return parent->ops->write(mdev, buf, count, ppos);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vfio_mdev_mmap(struct vfio_device *core_vdev,
|
|
||||||
struct vm_area_struct *vma)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (unlikely(!parent->ops->mmap))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return parent->ops->mmap(mdev, vma);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfio_mdev_request(struct vfio_device *core_vdev, unsigned int count)
|
|
||||||
{
|
|
||||||
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
|
|
||||||
struct mdev_parent *parent = mdev->type->parent;
|
|
||||||
|
|
||||||
if (parent->ops->request)
|
|
||||||
parent->ops->request(mdev, count);
|
|
||||||
else if (count == 0)
|
|
||||||
dev_notice(mdev_dev(mdev),
|
|
||||||
"No mdev vendor driver request callback support, blocked until released by user\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct vfio_device_ops vfio_mdev_dev_ops = {
|
|
||||||
.name = "vfio-mdev",
|
|
||||||
.open_device = vfio_mdev_open_device,
|
|
||||||
.close_device = vfio_mdev_close_device,
|
|
||||||
.ioctl = vfio_mdev_unlocked_ioctl,
|
|
||||||
.read = vfio_mdev_read,
|
|
||||||
.write = vfio_mdev_write,
|
|
||||||
.mmap = vfio_mdev_mmap,
|
|
||||||
.request = vfio_mdev_request,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int vfio_mdev_probe(struct mdev_device *mdev)
|
|
||||||
{
|
|
||||||
struct vfio_device *vdev;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
|
|
||||||
if (!vdev)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
vfio_init_group_dev(vdev, &mdev->dev, &vfio_mdev_dev_ops);
|
|
||||||
ret = vfio_register_emulated_iommu_dev(vdev);
|
|
||||||
if (ret)
|
|
||||||
goto out_uninit;
|
|
||||||
|
|
||||||
dev_set_drvdata(&mdev->dev, vdev);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_uninit:
|
|
||||||
vfio_uninit_group_dev(vdev);
|
|
||||||
kfree(vdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfio_mdev_remove(struct mdev_device *mdev)
|
|
||||||
{
|
|
||||||
struct vfio_device *vdev = dev_get_drvdata(&mdev->dev);
|
|
||||||
|
|
||||||
vfio_unregister_group_dev(vdev);
|
|
||||||
vfio_uninit_group_dev(vdev);
|
|
||||||
kfree(vdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mdev_driver vfio_mdev_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "vfio_mdev",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.mod_name = KBUILD_MODNAME,
|
|
||||||
},
|
|
||||||
.probe = vfio_mdev_probe,
|
|
||||||
.remove = vfio_mdev_remove,
|
|
||||||
};
|
|
@ -683,4 +683,35 @@
|
|||||||
INTEL_VGA_DEVICE(0xA78A, info), \
|
INTEL_VGA_DEVICE(0xA78A, info), \
|
||||||
INTEL_VGA_DEVICE(0xA78B, info)
|
INTEL_VGA_DEVICE(0xA78B, info)
|
||||||
|
|
||||||
|
/* RPL-P */
|
||||||
|
#define INTEL_RPLP_IDS(info) \
|
||||||
|
INTEL_VGA_DEVICE(0xA720, info), \
|
||||||
|
INTEL_VGA_DEVICE(0xA721, info), \
|
||||||
|
INTEL_VGA_DEVICE(0xA7A0, info), \
|
||||||
|
INTEL_VGA_DEVICE(0xA7A1, info), \
|
||||||
|
INTEL_VGA_DEVICE(0xA7A8, info), \
|
||||||
|
INTEL_VGA_DEVICE(0xA7A9, info)
|
||||||
|
|
||||||
|
/* DG2 */
|
||||||
|
#define INTEL_DG2_G10_IDS(info) \
|
||||||
|
INTEL_VGA_DEVICE(0x5690, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x5691, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x5692, info)
|
||||||
|
|
||||||
|
#define INTEL_DG2_G11_IDS(info) \
|
||||||
|
INTEL_VGA_DEVICE(0x5693, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x5694, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x5695, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x56B0, info)
|
||||||
|
|
||||||
|
#define INTEL_DG2_G12_IDS(info) \
|
||||||
|
INTEL_VGA_DEVICE(0x5696, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x5697, info), \
|
||||||
|
INTEL_VGA_DEVICE(0x56B2, info)
|
||||||
|
|
||||||
|
#define INTEL_DG2_IDS(info) \
|
||||||
|
INTEL_DG2_G10_IDS(info), \
|
||||||
|
INTEL_DG2_G11_IDS(info), \
|
||||||
|
INTEL_DG2_G12_IDS(info)
|
||||||
|
|
||||||
#endif /* _I915_PCIIDS_H */
|
#endif /* _I915_PCIIDS_H */
|
||||||
|
@ -15,7 +15,6 @@ struct mdev_type;
|
|||||||
struct mdev_device {
|
struct mdev_device {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
guid_t uuid;
|
guid_t uuid;
|
||||||
void *driver_data;
|
|
||||||
struct list_head next;
|
struct list_head next;
|
||||||
struct mdev_type *type;
|
struct mdev_type *type;
|
||||||
bool active;
|
bool active;
|
||||||
@ -30,74 +29,6 @@ unsigned int mdev_get_type_group_id(struct mdev_device *mdev);
|
|||||||
unsigned int mtype_get_type_group_id(struct mdev_type *mtype);
|
unsigned int mtype_get_type_group_id(struct mdev_type *mtype);
|
||||||
struct device *mtype_get_parent_dev(struct mdev_type *mtype);
|
struct device *mtype_get_parent_dev(struct mdev_type *mtype);
|
||||||
|
|
||||||
/**
|
|
||||||
* struct mdev_parent_ops - Structure to be registered for each parent device to
|
|
||||||
* register the device to mdev module.
|
|
||||||
*
|
|
||||||
* @owner: The module owner.
|
|
||||||
* @device_driver: Which device driver to probe() on newly created devices
|
|
||||||
* @dev_attr_groups: Attributes of the parent device.
|
|
||||||
* @mdev_attr_groups: Attributes of the mediated device.
|
|
||||||
* @supported_type_groups: Attributes to define supported types. It is mandatory
|
|
||||||
* to provide supported types.
|
|
||||||
* @create: Called to allocate basic resources in parent device's
|
|
||||||
* driver for a particular mediated device. It is
|
|
||||||
* mandatory to provide create ops.
|
|
||||||
* @mdev: mdev_device structure on of mediated device
|
|
||||||
* that is being created
|
|
||||||
* Returns integer: success (0) or error (< 0)
|
|
||||||
* @remove: Called to free resources in parent device's driver for
|
|
||||||
* a mediated device. It is mandatory to provide 'remove'
|
|
||||||
* ops.
|
|
||||||
* @mdev: mdev_device device structure which is being
|
|
||||||
* destroyed
|
|
||||||
* Returns integer: success (0) or error (< 0)
|
|
||||||
* @read: Read emulation callback
|
|
||||||
* @mdev: mediated device structure
|
|
||||||
* @buf: read buffer
|
|
||||||
* @count: number of bytes to read
|
|
||||||
* @ppos: address.
|
|
||||||
* Retuns number on bytes read on success or error.
|
|
||||||
* @write: Write emulation callback
|
|
||||||
* @mdev: mediated device structure
|
|
||||||
* @buf: write buffer
|
|
||||||
* @count: number of bytes to be written
|
|
||||||
* @ppos: address.
|
|
||||||
* Retuns number on bytes written on success or error.
|
|
||||||
* @ioctl: IOCTL callback
|
|
||||||
* @mdev: mediated device structure
|
|
||||||
* @cmd: ioctl command
|
|
||||||
* @arg: arguments to ioctl
|
|
||||||
* @mmap: mmap callback
|
|
||||||
* @mdev: mediated device structure
|
|
||||||
* @vma: vma structure
|
|
||||||
* @request: request callback to release device
|
|
||||||
* @mdev: mediated device structure
|
|
||||||
* @count: request sequence number
|
|
||||||
* Parent device that support mediated device should be registered with mdev
|
|
||||||
* module with mdev_parent_ops structure.
|
|
||||||
**/
|
|
||||||
struct mdev_parent_ops {
|
|
||||||
struct module *owner;
|
|
||||||
struct mdev_driver *device_driver;
|
|
||||||
const struct attribute_group **dev_attr_groups;
|
|
||||||
const struct attribute_group **mdev_attr_groups;
|
|
||||||
struct attribute_group **supported_type_groups;
|
|
||||||
|
|
||||||
int (*create)(struct mdev_device *mdev);
|
|
||||||
int (*remove)(struct mdev_device *mdev);
|
|
||||||
int (*open_device)(struct mdev_device *mdev);
|
|
||||||
void (*close_device)(struct mdev_device *mdev);
|
|
||||||
ssize_t (*read)(struct mdev_device *mdev, char __user *buf,
|
|
||||||
size_t count, loff_t *ppos);
|
|
||||||
ssize_t (*write)(struct mdev_device *mdev, const char __user *buf,
|
|
||||||
size_t count, loff_t *ppos);
|
|
||||||
long (*ioctl)(struct mdev_device *mdev, unsigned int cmd,
|
|
||||||
unsigned long arg);
|
|
||||||
int (*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma);
|
|
||||||
void (*request)(struct mdev_device *mdev, unsigned int count);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* interface for exporting mdev supported type attributes */
|
/* interface for exporting mdev supported type attributes */
|
||||||
struct mdev_type_attribute {
|
struct mdev_type_attribute {
|
||||||
struct attribute attr;
|
struct attribute attr;
|
||||||
@ -122,23 +53,18 @@ struct mdev_type_attribute mdev_type_attr_##_name = \
|
|||||||
* struct mdev_driver - Mediated device driver
|
* struct mdev_driver - Mediated device driver
|
||||||
* @probe: called when new device created
|
* @probe: called when new device created
|
||||||
* @remove: called when device removed
|
* @remove: called when device removed
|
||||||
|
* @supported_type_groups: Attributes to define supported types. It is mandatory
|
||||||
|
* to provide supported types.
|
||||||
* @driver: device driver structure
|
* @driver: device driver structure
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
struct mdev_driver {
|
struct mdev_driver {
|
||||||
int (*probe)(struct mdev_device *dev);
|
int (*probe)(struct mdev_device *dev);
|
||||||
void (*remove)(struct mdev_device *dev);
|
void (*remove)(struct mdev_device *dev);
|
||||||
|
struct attribute_group **supported_type_groups;
|
||||||
struct device_driver driver;
|
struct device_driver driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void *mdev_get_drvdata(struct mdev_device *mdev)
|
|
||||||
{
|
|
||||||
return mdev->driver_data;
|
|
||||||
}
|
|
||||||
static inline void mdev_set_drvdata(struct mdev_device *mdev, void *data)
|
|
||||||
{
|
|
||||||
mdev->driver_data = data;
|
|
||||||
}
|
|
||||||
static inline const guid_t *mdev_uuid(struct mdev_device *mdev)
|
static inline const guid_t *mdev_uuid(struct mdev_device *mdev)
|
||||||
{
|
{
|
||||||
return &mdev->uuid;
|
return &mdev->uuid;
|
||||||
@ -146,7 +72,7 @@ static inline const guid_t *mdev_uuid(struct mdev_device *mdev)
|
|||||||
|
|
||||||
extern struct bus_type mdev_bus_type;
|
extern struct bus_type mdev_bus_type;
|
||||||
|
|
||||||
int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops);
|
int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver);
|
||||||
void mdev_unregister_device(struct device *dev);
|
void mdev_unregister_device(struct device *dev);
|
||||||
|
|
||||||
int mdev_register_driver(struct mdev_driver *drv);
|
int mdev_register_driver(struct mdev_driver *drv);
|
||||||
|
@ -1412,12 +1412,7 @@ static struct mdev_driver mbochs_driver = {
|
|||||||
},
|
},
|
||||||
.probe = mbochs_probe,
|
.probe = mbochs_probe,
|
||||||
.remove = mbochs_remove,
|
.remove = mbochs_remove,
|
||||||
};
|
.supported_type_groups = mdev_type_groups,
|
||||||
|
|
||||||
static const struct mdev_parent_ops mdev_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.device_driver = &mbochs_driver,
|
|
||||||
.supported_type_groups = mdev_type_groups,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations vd_fops = {
|
static const struct file_operations vd_fops = {
|
||||||
@ -1462,7 +1457,7 @@ static int __init mbochs_dev_init(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_class;
|
goto err_class;
|
||||||
|
|
||||||
ret = mdev_register_device(&mbochs_dev, &mdev_fops);
|
ret = mdev_register_device(&mbochs_dev, &mbochs_driver);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_device;
|
goto err_device;
|
||||||
|
|
||||||
|
@ -723,12 +723,7 @@ static struct mdev_driver mdpy_driver = {
|
|||||||
},
|
},
|
||||||
.probe = mdpy_probe,
|
.probe = mdpy_probe,
|
||||||
.remove = mdpy_remove,
|
.remove = mdpy_remove,
|
||||||
};
|
.supported_type_groups = mdev_type_groups,
|
||||||
|
|
||||||
static const struct mdev_parent_ops mdev_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.device_driver = &mdpy_driver,
|
|
||||||
.supported_type_groups = mdev_type_groups,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations vd_fops = {
|
static const struct file_operations vd_fops = {
|
||||||
@ -771,7 +766,7 @@ static int __init mdpy_dev_init(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_class;
|
goto err_class;
|
||||||
|
|
||||||
ret = mdev_register_device(&mdpy_dev, &mdev_fops);
|
ret = mdev_register_device(&mdpy_dev, &mdpy_driver);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_device;
|
goto err_device;
|
||||||
|
|
||||||
|
@ -1207,38 +1207,11 @@ static long mtty_ioctl(struct vfio_device *vdev, unsigned int cmd,
|
|||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
|
||||||
sample_mtty_dev_show(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "This is phy device\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(sample_mtty_dev);
|
|
||||||
|
|
||||||
static struct attribute *mtty_dev_attrs[] = {
|
|
||||||
&dev_attr_sample_mtty_dev.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group mtty_dev_group = {
|
|
||||||
.name = "mtty_dev",
|
|
||||||
.attrs = mtty_dev_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group *mtty_dev_groups[] = {
|
|
||||||
&mtty_dev_group,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
sample_mdev_dev_show(struct device *dev, struct device_attribute *attr,
|
sample_mdev_dev_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (mdev_from_dev(dev))
|
return sprintf(buf, "This is MDEV %s\n", dev_name(dev));
|
||||||
return sprintf(buf, "This is MDEV %s\n", dev_name(dev));
|
|
||||||
|
|
||||||
return sprintf(buf, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(sample_mdev_dev);
|
static DEVICE_ATTR_RO(sample_mdev_dev);
|
||||||
@ -1328,13 +1301,7 @@ static struct mdev_driver mtty_driver = {
|
|||||||
},
|
},
|
||||||
.probe = mtty_probe,
|
.probe = mtty_probe,
|
||||||
.remove = mtty_remove,
|
.remove = mtty_remove,
|
||||||
};
|
.supported_type_groups = mdev_type_groups,
|
||||||
|
|
||||||
static const struct mdev_parent_ops mdev_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.device_driver = &mtty_driver,
|
|
||||||
.dev_attr_groups = mtty_dev_groups,
|
|
||||||
.supported_type_groups = mdev_type_groups,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mtty_device_release(struct device *dev)
|
static void mtty_device_release(struct device *dev)
|
||||||
@ -1385,7 +1352,7 @@ static int __init mtty_dev_init(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_class;
|
goto err_class;
|
||||||
|
|
||||||
ret = mdev_register_device(&mtty_dev.dev, &mdev_fops);
|
ret = mdev_register_device(&mtty_dev.dev, &mtty_driver);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_device;
|
goto err_device;
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user