2013-07-20 03:36:52 +08:00
|
|
|
/*
|
|
|
|
* Copyright © 2013 Intel Corporation
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2019-04-05 19:00:15 +08:00
|
|
|
#include <linux/pm_runtime.h>
|
|
|
|
#include <asm/iosf_mbi.h>
|
|
|
|
|
2013-07-20 03:36:52 +08:00
|
|
|
#include "i915_drv.h"
|
2015-02-10 19:05:47 +08:00
|
|
|
#include "i915_vgpu.h"
|
2019-04-05 19:00:15 +08:00
|
|
|
#include "intel_drv.h"
|
|
|
|
#include "intel_pm.h"
|
2015-01-16 17:34:35 +08:00
|
|
|
|
2015-08-23 20:22:47 +08:00
|
|
|
#define FORCEWAKE_ACK_TIMEOUT_MS 50
|
2017-05-02 22:03:44 +08:00
|
|
|
#define GT_FIFO_TIMEOUT_MS 10
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
#define __raw_posting_read(...) ((void)__raw_uncore_read32(__VA_ARGS__))
|
2013-07-20 03:36:53 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static const char * const forcewake_domain_names[] = {
|
|
|
|
"render",
|
|
|
|
"blitter",
|
|
|
|
"media",
|
2018-03-03 00:15:01 +08:00
|
|
|
"vdbox0",
|
|
|
|
"vdbox1",
|
|
|
|
"vdbox2",
|
|
|
|
"vdbox3",
|
|
|
|
"vebox0",
|
|
|
|
"vebox1",
|
2015-01-19 22:20:43 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const char *
|
2015-01-16 17:34:41 +08:00
|
|
|
intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
2015-08-22 01:45:28 +08:00
|
|
|
BUILD_BUG_ON(ARRAY_SIZE(forcewake_domain_names) != FW_DOMAIN_ID_COUNT);
|
2015-01-19 22:20:43 +08:00
|
|
|
|
|
|
|
if (id >= 0 && id < FW_DOMAIN_ID_COUNT)
|
|
|
|
return forcewake_domain_names[id];
|
|
|
|
|
|
|
|
WARN_ON(id);
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
#define fw_ack(d) readl((d)->reg_ack)
|
2019-03-20 20:27:32 +08:00
|
|
|
#define fw_set(d, val) writel(_MASKED_BIT_ENABLE((val)), (d)->reg_set)
|
|
|
|
#define fw_clear(d, val) writel(_MASKED_BIT_DISABLE((val)), (d)->reg_set)
|
2019-03-16 18:00:45 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static inline void
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_reset(const struct intel_uncore_forcewake_domain *d)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
/*
|
|
|
|
* We don't really know if the powerwell for the forcewake domain we are
|
|
|
|
* trying to reset here does exist at this point (engines could be fused
|
|
|
|
* off in ICL+), so no waiting for acks
|
|
|
|
*/
|
2019-03-20 20:27:32 +08:00
|
|
|
/* WaRsClearFWBitsAtReset:bdw,skl */
|
|
|
|
fw_clear(d, 0xffff);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static inline void
|
|
|
|
fw_domain_arm_timer(struct intel_uncore_forcewake_domain *d)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
d->wake_count++;
|
|
|
|
hrtimer_start_range_ns(&d->timer,
|
2016-12-25 19:30:41 +08:00
|
|
|
NSEC_PER_MSEC,
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
NSEC_PER_MSEC,
|
|
|
|
HRTIMER_MODE_REL);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2017-11-02 17:48:36 +08:00
|
|
|
static inline int
|
2019-03-16 18:00:45 +08:00
|
|
|
__wait_for_ack(const struct intel_uncore_forcewake_domain *d,
|
2017-11-02 17:48:36 +08:00
|
|
|
const u32 ack,
|
|
|
|
const u32 value)
|
|
|
|
{
|
2019-03-16 18:00:45 +08:00
|
|
|
return wait_for_atomic((fw_ack(d) & ack) == value,
|
2017-11-02 17:48:36 +08:00
|
|
|
FORCEWAKE_ACK_TIMEOUT_MS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
2019-03-16 18:00:45 +08:00
|
|
|
wait_ack_clear(const struct intel_uncore_forcewake_domain *d,
|
2017-11-02 17:48:36 +08:00
|
|
|
const u32 ack)
|
|
|
|
{
|
2019-03-16 18:00:45 +08:00
|
|
|
return __wait_for_ack(d, ack, 0);
|
2017-11-02 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
2019-03-16 18:00:45 +08:00
|
|
|
wait_ack_set(const struct intel_uncore_forcewake_domain *d,
|
2017-11-02 17:48:36 +08:00
|
|
|
const u32 ack)
|
|
|
|
{
|
2019-03-16 18:00:45 +08:00
|
|
|
return __wait_for_ack(d, ack, ack);
|
2017-11-02 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static inline void
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_clear(const struct intel_uncore_forcewake_domain *d)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
2019-05-08 19:52:45 +08:00
|
|
|
if (wait_ack_clear(d, FORCEWAKE_KERNEL)) {
|
2015-01-19 22:20:43 +08:00
|
|
|
DRM_ERROR("%s: timed out waiting for forcewake ack to clear.\n",
|
|
|
|
intel_uncore_forcewake_domain_to_str(d->id));
|
2019-05-08 19:52:45 +08:00
|
|
|
add_taint_for_CI(TAINT_WARN); /* CI now unreliable */
|
|
|
|
}
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2017-11-02 17:48:36 +08:00
|
|
|
enum ack_type {
|
|
|
|
ACK_CLEAR = 0,
|
|
|
|
ACK_SET
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_with_fallback(const struct intel_uncore_forcewake_domain *d,
|
2017-11-02 17:48:36 +08:00
|
|
|
const enum ack_type type)
|
|
|
|
{
|
|
|
|
const u32 ack_bit = FORCEWAKE_KERNEL;
|
|
|
|
const u32 value = type == ACK_SET ? ack_bit : 0;
|
|
|
|
unsigned int pass;
|
|
|
|
bool ack_detected;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There is a possibility of driver's wake request colliding
|
|
|
|
* with hardware's own wake requests and that can cause
|
|
|
|
* hardware to not deliver the driver's ack message.
|
|
|
|
*
|
|
|
|
* Use a fallback bit toggle to kick the gpu state machine
|
|
|
|
* in the hope that the original ack will be delivered along with
|
|
|
|
* the fallback ack.
|
|
|
|
*
|
2018-05-09 05:29:23 +08:00
|
|
|
* This workaround is described in HSDES #1604254524 and it's known as:
|
|
|
|
* WaRsForcewakeAddDelayForAck:skl,bxt,kbl,glk,cfl,cnl,icl
|
|
|
|
* although the name is a bit misleading.
|
2017-11-02 17:48:36 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
pass = 1;
|
|
|
|
do {
|
2019-03-16 18:00:45 +08:00
|
|
|
wait_ack_clear(d, FORCEWAKE_KERNEL_FALLBACK);
|
2017-11-02 17:48:36 +08:00
|
|
|
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_set(d, FORCEWAKE_KERNEL_FALLBACK);
|
2017-11-02 17:48:36 +08:00
|
|
|
/* Give gt some time to relax before the polling frenzy */
|
|
|
|
udelay(10 * pass);
|
2019-03-16 18:00:45 +08:00
|
|
|
wait_ack_set(d, FORCEWAKE_KERNEL_FALLBACK);
|
2017-11-02 17:48:36 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
ack_detected = (fw_ack(d) & ack_bit) == value;
|
2017-11-02 17:48:36 +08:00
|
|
|
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_clear(d, FORCEWAKE_KERNEL_FALLBACK);
|
2017-11-02 17:48:36 +08:00
|
|
|
} while (!ack_detected && pass++ < 10);
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("%s had to use fallback to %s ack, 0x%x (passes %u)\n",
|
|
|
|
intel_uncore_forcewake_domain_to_str(d->id),
|
|
|
|
type == ACK_SET ? "set" : "clear",
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_ack(d),
|
2017-11-02 17:48:36 +08:00
|
|
|
pass);
|
|
|
|
|
|
|
|
return ack_detected ? 0 : -ETIMEDOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_clear_fallback(const struct intel_uncore_forcewake_domain *d)
|
2017-11-02 17:48:36 +08:00
|
|
|
{
|
2019-03-16 18:00:45 +08:00
|
|
|
if (likely(!wait_ack_clear(d, FORCEWAKE_KERNEL)))
|
2017-11-02 17:48:36 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
if (fw_domain_wait_ack_with_fallback(d, ACK_CLEAR))
|
|
|
|
fw_domain_wait_ack_clear(d);
|
2017-11-02 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static inline void
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_get(const struct intel_uncore_forcewake_domain *d)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_set(d, FORCEWAKE_KERNEL);
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static inline void
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_set(const struct intel_uncore_forcewake_domain *d)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
2019-05-08 19:52:45 +08:00
|
|
|
if (wait_ack_set(d, FORCEWAKE_KERNEL)) {
|
2015-01-19 22:20:43 +08:00
|
|
|
DRM_ERROR("%s: timed out waiting for forcewake ack request.\n",
|
|
|
|
intel_uncore_forcewake_domain_to_str(d->id));
|
2019-05-08 19:52:45 +08:00
|
|
|
add_taint_for_CI(TAINT_WARN); /* CI now unreliable */
|
|
|
|
}
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2017-11-02 17:48:36 +08:00
|
|
|
static inline void
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_set_fallback(const struct intel_uncore_forcewake_domain *d)
|
2017-11-02 17:48:36 +08:00
|
|
|
{
|
2019-03-16 18:00:45 +08:00
|
|
|
if (likely(!wait_ack_set(d, FORCEWAKE_KERNEL)))
|
2017-11-02 17:48:36 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
if (fw_domain_wait_ack_with_fallback(d, ACK_SET))
|
|
|
|
fw_domain_wait_ack_set(d);
|
2017-11-02 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static inline void
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_put(const struct intel_uncore_forcewake_domain *d)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_clear(d, FORCEWAKE_KERNEL);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static void
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains_get(struct intel_uncore *uncore, enum forcewake_domains fw_domains)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
2015-01-19 22:20:43 +08:00
|
|
|
struct intel_uncore_forcewake_domain *d;
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
GEM_BUG_ON(fw_domains & ~uncore->fw_domains);
|
2017-03-23 18:19:41 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(d, fw_domains, uncore, tmp) {
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_clear(d);
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_get(d);
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
2016-04-08 00:04:34 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(d, fw_domains, uncore, tmp)
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_set(d);
|
2017-11-02 17:48:36 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
uncore->fw_domains_active |= fw_domains;
|
2017-11-02 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains_get_with_fallback(struct intel_uncore *uncore,
|
2017-11-02 17:48:36 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *d;
|
|
|
|
unsigned int tmp;
|
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
GEM_BUG_ON(fw_domains & ~uncore->fw_domains);
|
2017-11-02 17:48:36 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(d, fw_domains, uncore, tmp) {
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_clear_fallback(d);
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_get(d);
|
2017-11-02 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(d, fw_domains, uncore, tmp)
|
2019-03-16 18:00:45 +08:00
|
|
|
fw_domain_wait_ack_set_fallback(d);
|
2017-03-10 17:32:49 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
uncore->fw_domains_active |= fw_domains;
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static void
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains_put(struct intel_uncore *uncore, enum forcewake_domains fw_domains)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *d;
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
GEM_BUG_ON(fw_domains & ~uncore->fw_domains);
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(d, fw_domains, uncore, tmp)
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_put(d);
|
2017-03-10 17:32:49 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
uncore->fw_domains_active &= ~fw_domains;
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
static void
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains_reset(struct intel_uncore *uncore,
|
2017-03-23 18:19:38 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *d;
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
2015-01-19 22:20:43 +08:00
|
|
|
|
2017-03-23 18:19:41 +08:00
|
|
|
if (!fw_domains)
|
2015-02-05 23:45:42 +08:00
|
|
|
return;
|
2015-01-28 20:43:24 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
GEM_BUG_ON(fw_domains & ~uncore->fw_domains);
|
2017-03-23 18:19:41 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(d, fw_domains, uncore, tmp)
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_reset(d);
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:41 +08:00
|
|
|
static inline u32 gt_thread_status(struct intel_uncore *uncore)
|
2018-07-20 19:11:02 +08:00
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
val = __raw_uncore_read32(uncore, GEN6_GT_THREAD_STATUS_REG);
|
2018-07-20 19:11:02 +08:00
|
|
|
val &= GEN6_GT_THREAD_STATUS_CORE_MASK;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:41 +08:00
|
|
|
static void __gen6_gt_wait_for_thread_c0(struct intel_uncore *uncore)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
2018-07-20 19:11:02 +08:00
|
|
|
/*
|
|
|
|
* w/a for a sporadic read returning 0 by waiting for the GT
|
2015-01-19 22:20:43 +08:00
|
|
|
* thread to wake up.
|
|
|
|
*/
|
2019-03-20 02:35:41 +08:00
|
|
|
WARN_ONCE(wait_for_atomic_us(gt_thread_status(uncore) == 0, 5000),
|
2018-07-20 19:11:02 +08:00
|
|
|
"GT thread status wait timed out\n");
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
static void fw_domains_get_with_thread_status(struct intel_uncore *uncore,
|
2015-01-16 17:34:41 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains_get(uncore, fw_domains);
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
/* WaRsForcewakeWaitTC0:snb,ivb,hsw,bdw,vlv */
|
2019-03-20 02:35:41 +08:00
|
|
|
__gen6_gt_wait_for_thread_c0(uncore);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:41 +08:00
|
|
|
static inline u32 fifo_free_entries(struct intel_uncore *uncore)
|
2014-12-11 02:12:12 +08:00
|
|
|
{
|
2019-03-26 05:49:32 +08:00
|
|
|
u32 count = __raw_uncore_read32(uncore, GTFIFOCTL);
|
2014-12-11 02:12:12 +08:00
|
|
|
|
|
|
|
return count & GT_FIFO_FREE_ENTRIES_MASK;
|
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:41 +08:00
|
|
|
static void __gen6_gt_wait_for_fifo(struct intel_uncore *uncore)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
2017-05-02 22:03:44 +08:00
|
|
|
u32 n;
|
2013-07-20 03:36:52 +08:00
|
|
|
|
drm/i915/vlv: Update Wait for FIFO and wait for 20 free entries. v3
On VLV, FIFO will be shared by both SW and HW. So, we read the
free entries through register and update dev_priv variable
and wait for only 20 entries to be free
From Deepak's follow-up mail explaining why vlv is special:
"On SB, Out of 64 FIFO Entries, 20 Entries will be used by HW and
remaining 44 will be used by the SW,. I think due to this reason, we
have a threshold of 20 Entries."
"On VLV, HW and SW can access all 64 fifo entries, I don't think
having a threshold of 20 Entries is mandatory on VLV. Also, since both
SW and HW can access all 64 Entries. I think on VLV, we need to update
the fifo_count before waiting for the FIFO."
v2: Apply mask when we read the number of free FIFO entries (Ville).
v3: Mask applied after reading the register (Deepak).
Signed-off-by: Deepak S <deepak.s@intel.com>
[danvet: Add further explanation from Deepak to commit message.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-11-29 18:26:30 +08:00
|
|
|
/* On VLV, FIFO will be shared by both SW and HW.
|
|
|
|
* So, we need to read the FREE_ENTRIES everytime */
|
2019-03-20 02:35:41 +08:00
|
|
|
if (IS_VALLEYVIEW(uncore_to_i915(uncore)))
|
|
|
|
n = fifo_free_entries(uncore);
|
2017-05-02 22:03:44 +08:00
|
|
|
else
|
2019-03-20 02:35:39 +08:00
|
|
|
n = uncore->fifo_count;
|
2017-05-02 22:03:44 +08:00
|
|
|
|
|
|
|
if (n <= GT_FIFO_NUM_RESERVED_ENTRIES) {
|
2019-03-20 02:35:41 +08:00
|
|
|
if (wait_for_atomic((n = fifo_free_entries(uncore)) >
|
2017-05-02 22:03:44 +08:00
|
|
|
GT_FIFO_NUM_RESERVED_ENTRIES,
|
|
|
|
GT_FIFO_TIMEOUT_MS)) {
|
|
|
|
DRM_DEBUG("GT_FIFO timeout, entries: %u\n", n);
|
|
|
|
return;
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
uncore->fifo_count = n - 1;
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
static enum hrtimer_restart
|
|
|
|
intel_uncore_fw_release_timer(struct hrtimer *timer)
|
2014-11-05 01:07:04 +08:00
|
|
|
{
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
struct intel_uncore_forcewake_domain *domain =
|
|
|
|
container_of(timer, struct intel_uncore_forcewake_domain, timer);
|
2019-03-20 02:35:35 +08:00
|
|
|
struct intel_uncore *uncore = forcewake_domain_to_uncore(domain);
|
2015-01-16 17:34:37 +08:00
|
|
|
unsigned long irqflags;
|
2014-11-05 01:07:04 +08:00
|
|
|
|
2019-03-26 05:49:35 +08:00
|
|
|
assert_rpm_device_not_suspended(uncore->rpm);
|
2014-11-05 01:07:04 +08:00
|
|
|
|
2017-05-26 21:22:09 +08:00
|
|
|
if (xchg(&domain->active, false))
|
|
|
|
return HRTIMER_RESTART;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_lock_irqsave(&uncore->lock, irqflags);
|
2015-01-16 17:34:37 +08:00
|
|
|
if (WARN_ON(domain->wake_count == 0))
|
|
|
|
domain->wake_count++;
|
|
|
|
|
2017-03-10 17:32:49 +08:00
|
|
|
if (--domain->wake_count == 0)
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->funcs.force_wake_put(uncore, domain->mask);
|
2015-01-16 17:34:37 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags);
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
|
|
|
|
return HRTIMER_NORESTART;
|
2014-11-05 01:07:04 +08:00
|
|
|
}
|
|
|
|
|
2017-10-19 19:16:20 +08:00
|
|
|
/* Note callers must have acquired the PUNIT->PMIC bus, before calling this. */
|
2018-08-09 05:08:42 +08:00
|
|
|
static unsigned int
|
2019-03-20 02:35:35 +08:00
|
|
|
intel_uncore_forcewake_reset(struct intel_uncore *uncore)
|
2014-11-05 01:07:04 +08:00
|
|
|
{
|
2015-01-16 17:34:41 +08:00
|
|
|
unsigned long irqflags;
|
2015-01-16 17:34:37 +08:00
|
|
|
struct intel_uncore_forcewake_domain *domain;
|
2015-01-16 17:34:41 +08:00
|
|
|
int retry_count = 100;
|
2016-10-04 16:29:17 +08:00
|
|
|
enum forcewake_domains fw, active_domains;
|
2014-11-05 01:07:04 +08:00
|
|
|
|
2017-10-19 19:16:20 +08:00
|
|
|
iosf_mbi_assert_punit_acquired();
|
|
|
|
|
2015-01-16 17:34:37 +08:00
|
|
|
/* Hold uncore.lock across reset to prevent any register access
|
|
|
|
* with forcewake not set correctly. Wait until all pending
|
|
|
|
* timers are run before holding.
|
|
|
|
*/
|
|
|
|
while (1) {
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
|
|
|
|
2015-01-16 17:34:37 +08:00
|
|
|
active_domains = 0;
|
2014-11-05 01:07:04 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain(domain, uncore, tmp) {
|
2017-05-26 21:22:09 +08:00
|
|
|
smp_store_mb(domain->active, false);
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
if (hrtimer_cancel(&domain->timer) == 0)
|
2015-01-16 17:34:37 +08:00
|
|
|
continue;
|
2014-11-05 01:07:04 +08:00
|
|
|
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
intel_uncore_fw_release_timer(&domain->timer);
|
2015-01-16 17:34:37 +08:00
|
|
|
}
|
2013-08-26 20:46:09 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_lock_irqsave(&uncore->lock, irqflags);
|
2014-02-22 00:52:25 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain(domain, uncore, tmp) {
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
if (hrtimer_active(&domain->timer))
|
2016-04-08 00:04:33 +08:00
|
|
|
active_domains |= domain->mask;
|
2015-01-16 17:34:37 +08:00
|
|
|
}
|
2014-03-16 03:20:29 +08:00
|
|
|
|
2015-01-16 17:34:37 +08:00
|
|
|
if (active_domains == 0)
|
|
|
|
break;
|
2013-08-26 20:46:09 +08:00
|
|
|
|
2015-01-16 17:34:37 +08:00
|
|
|
if (--retry_count == 0) {
|
|
|
|
DRM_ERROR("Timed out waiting for forcewake timers to finish\n");
|
|
|
|
break;
|
|
|
|
}
|
2014-03-13 20:00:29 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags);
|
2015-01-16 17:34:37 +08:00
|
|
|
cond_resched();
|
|
|
|
}
|
2014-03-13 20:00:29 +08:00
|
|
|
|
2015-01-16 17:34:37 +08:00
|
|
|
WARN_ON(active_domains);
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
fw = uncore->fw_domains_active;
|
2015-01-16 17:34:37 +08:00
|
|
|
if (fw)
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->funcs.force_wake_put(uncore, fw);
|
2013-11-16 23:00:09 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains_reset(uncore, uncore->fw_domains);
|
|
|
|
assert_forcewakes_inactive(uncore);
|
2015-01-16 17:34:37 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags);
|
2018-08-09 05:08:42 +08:00
|
|
|
|
|
|
|
return fw; /* track the lost user forcewake domains */
|
2013-11-16 23:00:09 +08:00
|
|
|
}
|
|
|
|
|
2015-12-16 01:24:47 +08:00
|
|
|
static bool
|
2019-03-20 02:35:41 +08:00
|
|
|
fpga_check_for_unclaimed_mmio(struct intel_uncore *uncore)
|
2015-12-16 01:24:47 +08:00
|
|
|
{
|
|
|
|
u32 dbg;
|
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
dbg = __raw_uncore_read32(uncore, FPGA_DBG);
|
2015-12-16 01:24:47 +08:00
|
|
|
if (likely(!(dbg & FPGA_DBG_RM_NOCLAIM)))
|
|
|
|
return false;
|
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write32(uncore, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
|
2015-12-16 01:24:47 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-16 01:45:42 +08:00
|
|
|
static bool
|
2019-03-20 02:35:41 +08:00
|
|
|
vlv_check_for_unclaimed_mmio(struct intel_uncore *uncore)
|
2015-12-16 01:45:42 +08:00
|
|
|
{
|
|
|
|
u32 cer;
|
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
cer = __raw_uncore_read32(uncore, CLAIM_ER);
|
2015-12-16 01:45:42 +08:00
|
|
|
if (likely(!(cer & (CLAIM_ER_OVERFLOW | CLAIM_ER_CTR_MASK))))
|
|
|
|
return false;
|
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write32(uncore, CLAIM_ER, CLAIM_ER_CLR);
|
2015-12-16 01:45:42 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-06 23:39:42 +08:00
|
|
|
static bool
|
2019-03-20 02:35:41 +08:00
|
|
|
gen6_check_for_fifo_debug(struct intel_uncore *uncore)
|
2017-04-06 23:39:42 +08:00
|
|
|
{
|
|
|
|
u32 fifodbg;
|
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
fifodbg = __raw_uncore_read32(uncore, GTFIFODBG);
|
2017-04-06 23:39:42 +08:00
|
|
|
|
|
|
|
if (unlikely(fifodbg)) {
|
|
|
|
DRM_DEBUG_DRIVER("GTFIFODBG = 0x08%x\n", fifodbg);
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write32(uncore, GTFIFODBG, fifodbg);
|
2017-04-06 23:39:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return fifodbg;
|
|
|
|
}
|
|
|
|
|
2015-12-16 01:45:42 +08:00
|
|
|
static bool
|
2019-03-26 05:49:34 +08:00
|
|
|
check_for_unclaimed_mmio(struct intel_uncore *uncore)
|
2015-12-16 01:45:42 +08:00
|
|
|
{
|
2017-04-06 23:39:42 +08:00
|
|
|
bool ret = false;
|
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
if (intel_uncore_has_fpga_dbg_unclaimed(uncore))
|
2019-03-20 02:35:41 +08:00
|
|
|
ret |= fpga_check_for_unclaimed_mmio(uncore);
|
2015-12-16 01:45:42 +08:00
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
if (intel_uncore_has_dbg_unclaimed(uncore))
|
2019-03-20 02:35:41 +08:00
|
|
|
ret |= vlv_check_for_unclaimed_mmio(uncore);
|
2017-04-06 23:39:42 +08:00
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
if (intel_uncore_has_fifo(uncore))
|
2019-03-20 02:35:41 +08:00
|
|
|
ret |= gen6_check_for_fifo_debug(uncore);
|
2015-12-16 01:45:42 +08:00
|
|
|
|
2017-04-06 23:39:42 +08:00
|
|
|
return ret;
|
2015-12-16 01:45:42 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
static void __intel_uncore_early_sanitize(struct intel_uncore *uncore,
|
2018-08-09 05:08:42 +08:00
|
|
|
unsigned int restore_forcewake)
|
2015-01-28 20:43:24 +08:00
|
|
|
{
|
2015-12-16 01:24:47 +08:00
|
|
|
/* clear out unclaimed reg detection bit */
|
2019-03-26 05:49:34 +08:00
|
|
|
if (check_for_unclaimed_mmio(uncore))
|
2015-12-16 01:24:47 +08:00
|
|
|
DRM_DEBUG("unclaimed mmio detected on uncore init, clearing\n");
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2015-04-16 11:21:28 +08:00
|
|
|
/* WaDisableShadowRegForCpd:chv */
|
2019-03-26 05:49:34 +08:00
|
|
|
if (IS_CHERRYVIEW(uncore_to_i915(uncore))) {
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write32(uncore, GTFIFOCTL,
|
|
|
|
__raw_uncore_read32(uncore, GTFIFOCTL) |
|
|
|
|
GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL |
|
|
|
|
GT_FIFO_CTL_RC6_POLICY_STALL);
|
2015-04-16 11:21:28 +08:00
|
|
|
}
|
|
|
|
|
2017-10-19 19:16:20 +08:00
|
|
|
iosf_mbi_punit_acquire();
|
2019-03-20 02:35:37 +08:00
|
|
|
intel_uncore_forcewake_reset(uncore);
|
2018-08-09 05:08:42 +08:00
|
|
|
if (restore_forcewake) {
|
2019-03-20 02:35:37 +08:00
|
|
|
spin_lock_irq(&uncore->lock);
|
|
|
|
uncore->funcs.force_wake_get(uncore, restore_forcewake);
|
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
if (intel_uncore_has_fifo(uncore))
|
2019-03-20 02:35:41 +08:00
|
|
|
uncore->fifo_count = fifo_free_entries(uncore);
|
2019-03-20 02:35:37 +08:00
|
|
|
spin_unlock_irq(&uncore->lock);
|
2018-08-09 05:08:42 +08:00
|
|
|
}
|
2017-10-19 19:16:20 +08:00
|
|
|
iosf_mbi_punit_release();
|
2013-08-23 21:52:30 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
void intel_uncore_suspend(struct intel_uncore *uncore)
|
2014-10-24 00:23:21 +08:00
|
|
|
{
|
2017-10-19 19:16:20 +08:00
|
|
|
iosf_mbi_punit_acquire();
|
|
|
|
iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
|
2019-03-20 02:35:37 +08:00
|
|
|
&uncore->pmic_bus_access_nb);
|
|
|
|
uncore->fw_domains_saved = intel_uncore_forcewake_reset(uncore);
|
2017-10-19 19:16:20 +08:00
|
|
|
iosf_mbi_punit_release();
|
2017-02-10 18:28:01 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
void intel_uncore_resume_early(struct intel_uncore *uncore)
|
2017-02-10 18:28:01 +08:00
|
|
|
{
|
2018-08-09 05:08:42 +08:00
|
|
|
unsigned int restore_forcewake;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
restore_forcewake = fetch_and_zero(&uncore->fw_domains_saved);
|
|
|
|
__intel_uncore_early_sanitize(uncore, restore_forcewake);
|
2018-08-09 05:08:42 +08:00
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
iosf_mbi_register_pmic_bus_access_notifier(&uncore->pmic_bus_access_nb);
|
2014-10-24 00:23:21 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
void intel_uncore_runtime_resume(struct intel_uncore *uncore)
|
2017-11-14 21:55:17 +08:00
|
|
|
{
|
2019-03-20 02:35:37 +08:00
|
|
|
iosf_mbi_register_pmic_bus_access_notifier(&uncore->pmic_bus_access_nb);
|
2017-11-14 21:55:17 +08:00
|
|
|
}
|
|
|
|
|
2016-05-10 21:10:04 +08:00
|
|
|
void intel_uncore_sanitize(struct drm_i915_private *dev_priv)
|
2013-08-23 21:52:30 +08:00
|
|
|
{
|
2013-07-20 03:36:52 +08:00
|
|
|
/* BIOS often leaves RC6 enabled, but disable it for hw init */
|
2016-07-22 04:16:19 +08:00
|
|
|
intel_sanitize_gt_powersave(dev_priv);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
static void __intel_uncore_forcewake_get(struct intel_uncore *uncore,
|
2015-04-07 23:21:02 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *domain;
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
2015-04-07 23:21:02 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains &= uncore->fw_domains;
|
2015-04-07 23:21:02 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) {
|
2017-05-26 21:22:09 +08:00
|
|
|
if (domain->wake_count++) {
|
2016-04-08 00:04:33 +08:00
|
|
|
fw_domains &= ~domain->mask;
|
2017-05-26 21:22:09 +08:00
|
|
|
domain->active = true;
|
|
|
|
}
|
|
|
|
}
|
2015-04-07 23:21:02 +08:00
|
|
|
|
2017-03-10 17:32:49 +08:00
|
|
|
if (fw_domains)
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->funcs.force_wake_get(uncore, fw_domains);
|
2015-04-07 23:21:02 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 17:34:40 +08:00
|
|
|
/**
|
|
|
|
* intel_uncore_forcewake_get - grab forcewake domain references
|
2019-03-20 02:35:36 +08:00
|
|
|
* @uncore: the intel_uncore structure
|
2015-01-16 17:34:40 +08:00
|
|
|
* @fw_domains: forcewake domains to get reference on
|
|
|
|
*
|
|
|
|
* This function can be used get GT's forcewake domain references.
|
|
|
|
* Normal register access will handle the forcewake domains automatically.
|
|
|
|
* However if some sequence requires the GT to not power down a particular
|
|
|
|
* forcewake domains this function should be called at the beginning of the
|
|
|
|
* sequence. And subsequently the reference should be dropped by symmetric
|
|
|
|
* call to intel_unforce_forcewake_put(). Usually caller wants all the domains
|
|
|
|
* to be kept awake so the @fw_domains would be then FORCEWAKE_ALL.
|
2013-07-20 03:36:52 +08:00
|
|
|
*/
|
2019-03-20 02:35:36 +08:00
|
|
|
void intel_uncore_forcewake_get(struct intel_uncore *uncore,
|
2015-01-16 17:34:41 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
|
|
|
unsigned long irqflags;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
if (!uncore->funcs.force_wake_get)
|
2013-10-06 08:57:11 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-26 05:49:35 +08:00
|
|
|
__assert_rpm_wakelock_held(uncore->rpm);
|
2013-11-28 04:21:54 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_lock_irqsave(&uncore->lock, irqflags);
|
|
|
|
__intel_uncore_forcewake_get(uncore, fw_domains);
|
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2017-09-07 21:44:41 +08:00
|
|
|
/**
|
|
|
|
* intel_uncore_forcewake_user_get - claim forcewake on behalf of userspace
|
2019-03-20 02:35:36 +08:00
|
|
|
* @uncore: the intel_uncore structure
|
2017-09-07 21:44:41 +08:00
|
|
|
*
|
|
|
|
* This function is a wrapper around intel_uncore_forcewake_get() to acquire
|
|
|
|
* the GT powerwell and in the process disable our debugging for the
|
|
|
|
* duration of userspace's bypass.
|
|
|
|
*/
|
2019-03-20 02:35:36 +08:00
|
|
|
void intel_uncore_forcewake_user_get(struct intel_uncore *uncore)
|
2017-09-07 21:44:41 +08:00
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_lock_irq(&uncore->lock);
|
|
|
|
if (!uncore->user_forcewake.count++) {
|
2019-03-20 02:35:36 +08:00
|
|
|
intel_uncore_forcewake_get__locked(uncore, FORCEWAKE_ALL);
|
2017-09-07 21:44:41 +08:00
|
|
|
|
|
|
|
/* Save and disable mmio debugging for the user bypass */
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->user_forcewake.saved_mmio_check =
|
|
|
|
uncore->unclaimed_mmio_check;
|
|
|
|
uncore->user_forcewake.saved_mmio_debug =
|
2017-09-20 03:38:44 +08:00
|
|
|
i915_modparams.mmio_debug;
|
2017-09-07 21:44:41 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->unclaimed_mmio_check = 0;
|
2017-09-20 03:38:44 +08:00
|
|
|
i915_modparams.mmio_debug = 0;
|
2017-09-07 21:44:41 +08:00
|
|
|
}
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_unlock_irq(&uncore->lock);
|
2017-09-07 21:44:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_uncore_forcewake_user_put - release forcewake on behalf of userspace
|
2019-03-20 02:35:36 +08:00
|
|
|
* @uncore: the intel_uncore structure
|
2017-09-07 21:44:41 +08:00
|
|
|
*
|
|
|
|
* This function complements intel_uncore_forcewake_user_get() and releases
|
|
|
|
* the GT powerwell taken on behalf of the userspace bypass.
|
|
|
|
*/
|
2019-03-20 02:35:36 +08:00
|
|
|
void intel_uncore_forcewake_user_put(struct intel_uncore *uncore)
|
2017-09-07 21:44:41 +08:00
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_lock_irq(&uncore->lock);
|
|
|
|
if (!--uncore->user_forcewake.count) {
|
2019-03-26 05:49:34 +08:00
|
|
|
if (intel_uncore_unclaimed_mmio(uncore))
|
|
|
|
dev_info(uncore_to_i915(uncore)->drm.dev,
|
2017-09-07 21:44:41 +08:00
|
|
|
"Invalid mmio detected during user access\n");
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->unclaimed_mmio_check =
|
|
|
|
uncore->user_forcewake.saved_mmio_check;
|
2017-09-20 03:38:44 +08:00
|
|
|
i915_modparams.mmio_debug =
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->user_forcewake.saved_mmio_debug;
|
2017-09-07 21:44:41 +08:00
|
|
|
|
2019-03-20 02:35:36 +08:00
|
|
|
intel_uncore_forcewake_put__locked(uncore, FORCEWAKE_ALL);
|
2017-09-07 21:44:41 +08:00
|
|
|
}
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_unlock_irq(&uncore->lock);
|
2017-09-07 21:44:41 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 17:34:40 +08:00
|
|
|
/**
|
2015-04-07 23:21:02 +08:00
|
|
|
* intel_uncore_forcewake_get__locked - grab forcewake domain references
|
2019-03-20 02:35:36 +08:00
|
|
|
* @uncore: the intel_uncore structure
|
2015-04-07 23:21:02 +08:00
|
|
|
* @fw_domains: forcewake domains to get reference on
|
2015-01-16 17:34:40 +08:00
|
|
|
*
|
2015-04-07 23:21:02 +08:00
|
|
|
* See intel_uncore_forcewake_get(). This variant places the onus
|
|
|
|
* on the caller to explicitly handle the dev_priv->uncore.lock spinlock.
|
2013-07-20 03:36:52 +08:00
|
|
|
*/
|
2019-03-20 02:35:36 +08:00
|
|
|
void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore,
|
2015-04-07 23:21:02 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
lockdep_assert_held(&uncore->lock);
|
|
|
|
|
|
|
|
if (!uncore->funcs.force_wake_get)
|
2015-04-07 23:21:02 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
__intel_uncore_forcewake_get(uncore, fw_domains);
|
2015-04-07 23:21:02 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
|
2015-04-07 23:21:02 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
2015-01-16 17:34:37 +08:00
|
|
|
struct intel_uncore_forcewake_domain *domain;
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains &= uncore->fw_domains;
|
2015-01-16 17:34:37 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) {
|
2015-01-16 17:34:37 +08:00
|
|
|
if (WARN_ON(domain->wake_count == 0))
|
|
|
|
continue;
|
|
|
|
|
2017-05-26 21:22:09 +08:00
|
|
|
if (--domain->wake_count) {
|
|
|
|
domain->active = true;
|
2015-01-16 17:34:37 +08:00
|
|
|
continue;
|
2017-05-26 21:22:09 +08:00
|
|
|
}
|
2015-01-16 17:34:37 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
fw_domain_arm_timer(domain);
|
2013-08-26 20:46:09 +08:00
|
|
|
}
|
2015-04-07 23:21:02 +08:00
|
|
|
}
|
2015-01-16 17:34:34 +08:00
|
|
|
|
2015-04-07 23:21:02 +08:00
|
|
|
/**
|
|
|
|
* intel_uncore_forcewake_put - release a forcewake domain reference
|
2019-03-20 02:35:36 +08:00
|
|
|
* @uncore: the intel_uncore structure
|
2015-04-07 23:21:02 +08:00
|
|
|
* @fw_domains: forcewake domains to put references
|
|
|
|
*
|
|
|
|
* This function drops the device-level forcewakes for specified
|
|
|
|
* domains obtained by intel_uncore_forcewake_get().
|
|
|
|
*/
|
2019-03-20 02:35:36 +08:00
|
|
|
void intel_uncore_forcewake_put(struct intel_uncore *uncore,
|
2015-04-07 23:21:02 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
|
|
|
unsigned long irqflags;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
if (!uncore->funcs.force_wake_put)
|
2015-04-07 23:21:02 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
spin_lock_irqsave(&uncore->lock, irqflags);
|
|
|
|
__intel_uncore_forcewake_put(uncore, fw_domains);
|
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2015-04-07 23:21:02 +08:00
|
|
|
/**
|
|
|
|
* intel_uncore_forcewake_put__locked - grab forcewake domain references
|
2019-03-20 02:35:36 +08:00
|
|
|
* @uncore: the intel_uncore structure
|
2015-04-07 23:21:02 +08:00
|
|
|
* @fw_domains: forcewake domains to get reference on
|
|
|
|
*
|
|
|
|
* See intel_uncore_forcewake_put(). This variant places the onus
|
|
|
|
* on the caller to explicitly handle the dev_priv->uncore.lock spinlock.
|
|
|
|
*/
|
2019-03-20 02:35:36 +08:00
|
|
|
void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore,
|
2015-04-07 23:21:02 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
lockdep_assert_held(&uncore->lock);
|
|
|
|
|
|
|
|
if (!uncore->funcs.force_wake_put)
|
2015-04-07 23:21:02 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
__intel_uncore_forcewake_put(uncore, fw_domains);
|
2015-04-07 23:21:02 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
void assert_forcewakes_inactive(struct intel_uncore *uncore)
|
2014-02-22 00:52:26 +08:00
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
if (!uncore->funcs.force_wake_get)
|
2014-02-22 00:52:26 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
WARN(uncore->fw_domains_active,
|
2017-10-09 19:03:01 +08:00
|
|
|
"Expected all fw_domains to be inactive, but %08x are still on\n",
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->fw_domains_active);
|
2017-10-09 19:03:01 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
void assert_forcewakes_active(struct intel_uncore *uncore,
|
2017-10-09 19:03:01 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
2019-03-20 02:35:35 +08:00
|
|
|
if (!uncore->funcs.force_wake_get)
|
2017-10-09 19:03:01 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-26 05:49:35 +08:00
|
|
|
__assert_rpm_wakelock_held(uncore->rpm);
|
2017-10-09 19:03:01 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains &= uncore->fw_domains;
|
|
|
|
WARN(fw_domains & ~uncore->fw_domains_active,
|
2017-10-09 19:03:01 +08:00
|
|
|
"Expected %08x fw_domains to be active, but %08x are off\n",
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains, fw_domains & ~uncore->fw_domains_active);
|
2014-02-22 00:52:26 +08:00
|
|
|
}
|
|
|
|
|
2013-07-20 03:36:52 +08:00
|
|
|
/* We give fast paths for the really cool registers */
|
2015-10-22 20:34:57 +08:00
|
|
|
#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000)
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
#define GEN11_NEEDS_FORCE_WAKE(reg) \
|
|
|
|
((reg) < 0x40000 || ((reg) >= 0x1c0000 && (reg) < 0x1dc000))
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
#define __gen6_reg_read_fw_domains(uncore, offset) \
|
2016-04-12 21:37:29 +08:00
|
|
|
({ \
|
|
|
|
enum forcewake_domains __fwd; \
|
|
|
|
if (NEEDS_FORCE_WAKE(offset)) \
|
|
|
|
__fwd = FORCEWAKE_RENDER; \
|
|
|
|
else \
|
|
|
|
__fwd = 0; \
|
|
|
|
__fwd; \
|
|
|
|
})
|
|
|
|
|
2016-10-04 16:29:29 +08:00
|
|
|
static int fw_range_cmp(u32 offset, const struct intel_forcewake_range *entry)
|
2016-10-04 16:29:21 +08:00
|
|
|
{
|
|
|
|
if (offset < entry->start)
|
|
|
|
return -1;
|
|
|
|
else if (offset > entry->end)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-04 16:29:29 +08:00
|
|
|
/* Copied and "macroized" from lib/bsearch.c */
|
|
|
|
#define BSEARCH(key, base, num, cmp) ({ \
|
|
|
|
unsigned int start__ = 0, end__ = (num); \
|
|
|
|
typeof(base) result__ = NULL; \
|
|
|
|
while (start__ < end__) { \
|
|
|
|
unsigned int mid__ = start__ + (end__ - start__) / 2; \
|
|
|
|
int ret__ = (cmp)((key), (base) + mid__); \
|
|
|
|
if (ret__ < 0) { \
|
|
|
|
end__ = mid__; \
|
|
|
|
} else if (ret__ > 0) { \
|
|
|
|
start__ = mid__ + 1; \
|
|
|
|
} else { \
|
|
|
|
result__ = (base) + mid__; \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
result__; \
|
|
|
|
})
|
|
|
|
|
2016-10-04 16:29:19 +08:00
|
|
|
static enum forcewake_domains
|
2019-03-20 02:35:38 +08:00
|
|
|
find_fw_domain(struct intel_uncore *uncore, u32 offset)
|
2016-10-04 16:29:19 +08:00
|
|
|
{
|
2016-10-04 16:29:29 +08:00
|
|
|
const struct intel_forcewake_range *entry;
|
2016-10-04 16:29:19 +08:00
|
|
|
|
2016-10-04 16:29:29 +08:00
|
|
|
entry = BSEARCH(offset,
|
2019-03-20 02:35:38 +08:00
|
|
|
uncore->fw_domains_table,
|
|
|
|
uncore->fw_domains_table_entries,
|
2016-10-04 16:29:21 +08:00
|
|
|
fw_range_cmp);
|
2014-03-29 00:54:26 +08:00
|
|
|
|
2016-12-07 22:22:39 +08:00
|
|
|
if (!entry)
|
|
|
|
return 0;
|
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
/*
|
|
|
|
* The list of FW domains depends on the SKU in gen11+ so we
|
|
|
|
* can't determine it statically. We use FORCEWAKE_ALL and
|
|
|
|
* translate it here to the list of available domains.
|
|
|
|
*/
|
|
|
|
if (entry->domains == FORCEWAKE_ALL)
|
2019-03-20 02:35:38 +08:00
|
|
|
return uncore->fw_domains;
|
2018-03-03 00:15:01 +08:00
|
|
|
|
2019-03-20 02:35:38 +08:00
|
|
|
WARN(entry->domains & ~uncore->fw_domains,
|
2016-12-07 22:22:39 +08:00
|
|
|
"Uninitialized forcewake domain(s) 0x%x accessed at 0x%x\n",
|
2019-03-20 02:35:38 +08:00
|
|
|
entry->domains & ~uncore->fw_domains, offset);
|
2016-12-07 22:22:39 +08:00
|
|
|
|
|
|
|
return entry->domains;
|
2016-10-04 16:29:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define GEN_FW_RANGE(s, e, d) \
|
|
|
|
{ .start = (s), .end = (e), .domains = (d) }
|
2014-05-23 23:30:16 +08:00
|
|
|
|
2016-10-04 16:29:24 +08:00
|
|
|
#define HAS_FWTABLE(dev_priv) \
|
2017-07-06 09:00:31 +08:00
|
|
|
(INTEL_GEN(dev_priv) >= 9 || \
|
2016-10-04 16:29:24 +08:00
|
|
|
IS_CHERRYVIEW(dev_priv) || \
|
|
|
|
IS_VALLEYVIEW(dev_priv))
|
|
|
|
|
2016-10-04 16:29:20 +08:00
|
|
|
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
|
2016-10-04 16:29:19 +08:00
|
|
|
static const struct intel_forcewake_range __vlv_fw_ranges[] = {
|
|
|
|
GEN_FW_RANGE(0x2000, 0x3fff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x5000, 0x7fff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0xb000, 0x11fff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x12000, 0x13fff, FORCEWAKE_MEDIA),
|
|
|
|
GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x2e000, 0x2ffff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_MEDIA),
|
|
|
|
};
|
2014-05-23 23:30:16 +08:00
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
#define __fwtable_reg_read_fw_domains(uncore, offset) \
|
2016-04-12 21:37:29 +08:00
|
|
|
({ \
|
|
|
|
enum forcewake_domains __fwd = 0; \
|
2016-10-04 16:29:22 +08:00
|
|
|
if (NEEDS_FORCE_WAKE((offset))) \
|
2019-03-20 02:35:39 +08:00
|
|
|
__fwd = find_fw_domain(uncore, offset); \
|
2016-04-12 21:37:29 +08:00
|
|
|
__fwd; \
|
|
|
|
})
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
#define __gen11_fwtable_reg_read_fw_domains(uncore, offset) \
|
2018-03-03 00:15:01 +08:00
|
|
|
({ \
|
|
|
|
enum forcewake_domains __fwd = 0; \
|
|
|
|
if (GEN11_NEEDS_FORCE_WAKE((offset))) \
|
2019-03-20 02:35:39 +08:00
|
|
|
__fwd = find_fw_domain(uncore, offset); \
|
2018-03-03 00:15:01 +08:00
|
|
|
__fwd; \
|
|
|
|
})
|
|
|
|
|
2016-10-04 16:29:27 +08:00
|
|
|
/* *Must* be sorted by offset! See intel_shadow_table_check(). */
|
2016-04-12 21:37:29 +08:00
|
|
|
static const i915_reg_t gen8_shadowed_regs[] = {
|
2016-10-04 16:29:27 +08:00
|
|
|
RING_TAIL(RENDER_RING_BASE), /* 0x2000 (base) */
|
|
|
|
GEN6_RPNSWREQ, /* 0xA008 */
|
|
|
|
GEN6_RC_VIDEO_FREQ, /* 0xA00C */
|
|
|
|
RING_TAIL(GEN6_BSD_RING_BASE), /* 0x12000 (base) */
|
|
|
|
RING_TAIL(VEBOX_RING_BASE), /* 0x1a000 (base) */
|
|
|
|
RING_TAIL(BLT_RING_BASE), /* 0x22000 (base) */
|
2016-04-12 21:37:29 +08:00
|
|
|
/* TODO: Other registers are not yet used */
|
|
|
|
};
|
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
static const i915_reg_t gen11_shadowed_regs[] = {
|
|
|
|
RING_TAIL(RENDER_RING_BASE), /* 0x2000 (base) */
|
|
|
|
GEN6_RPNSWREQ, /* 0xA008 */
|
|
|
|
GEN6_RC_VIDEO_FREQ, /* 0xA00C */
|
|
|
|
RING_TAIL(BLT_RING_BASE), /* 0x22000 (base) */
|
|
|
|
RING_TAIL(GEN11_BSD_RING_BASE), /* 0x1C0000 (base) */
|
|
|
|
RING_TAIL(GEN11_BSD2_RING_BASE), /* 0x1C4000 (base) */
|
|
|
|
RING_TAIL(GEN11_VEBOX_RING_BASE), /* 0x1C8000 (base) */
|
|
|
|
RING_TAIL(GEN11_BSD3_RING_BASE), /* 0x1D0000 (base) */
|
|
|
|
RING_TAIL(GEN11_BSD4_RING_BASE), /* 0x1D4000 (base) */
|
|
|
|
RING_TAIL(GEN11_VEBOX2_RING_BASE), /* 0x1D8000 (base) */
|
|
|
|
/* TODO: Other registers are not yet used */
|
|
|
|
};
|
|
|
|
|
2016-10-04 16:29:29 +08:00
|
|
|
static int mmio_reg_cmp(u32 key, const i915_reg_t *reg)
|
2016-10-04 16:29:28 +08:00
|
|
|
{
|
2016-10-04 16:29:29 +08:00
|
|
|
u32 offset = i915_mmio_reg_offset(*reg);
|
2016-10-04 16:29:28 +08:00
|
|
|
|
2016-10-04 16:29:29 +08:00
|
|
|
if (key < offset)
|
2016-10-04 16:29:28 +08:00
|
|
|
return -1;
|
2016-10-04 16:29:29 +08:00
|
|
|
else if (key > offset)
|
2016-10-04 16:29:28 +08:00
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
#define __is_genX_shadowed(x) \
|
|
|
|
static bool is_gen##x##_shadowed(u32 offset) \
|
|
|
|
{ \
|
|
|
|
const i915_reg_t *regs = gen##x##_shadowed_regs; \
|
|
|
|
return BSEARCH(offset, regs, ARRAY_SIZE(gen##x##_shadowed_regs), \
|
|
|
|
mmio_reg_cmp); \
|
2016-04-12 21:37:29 +08:00
|
|
|
}
|
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
__is_genX_shadowed(8)
|
|
|
|
__is_genX_shadowed(11)
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
#define __gen8_reg_write_fw_domains(uncore, offset) \
|
2016-04-12 21:37:29 +08:00
|
|
|
({ \
|
|
|
|
enum forcewake_domains __fwd; \
|
|
|
|
if (NEEDS_FORCE_WAKE(offset) && !is_gen8_shadowed(offset)) \
|
|
|
|
__fwd = FORCEWAKE_RENDER; \
|
|
|
|
else \
|
|
|
|
__fwd = 0; \
|
|
|
|
__fwd; \
|
|
|
|
})
|
|
|
|
|
2016-10-04 16:29:20 +08:00
|
|
|
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
|
2016-10-04 16:29:19 +08:00
|
|
|
static const struct intel_forcewake_range __chv_fw_ranges[] = {
|
|
|
|
GEN_FW_RANGE(0x2000, 0x3fff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x4000, 0x4fff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x8000, 0x82ff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x8500, 0x85ff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x8800, 0x88ff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x9000, 0xafff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
|
|
|
|
GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0xd000, 0xd7ff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0xe000, 0xe7ff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0xf000, 0xffff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x12000, 0x13fff, FORCEWAKE_MEDIA),
|
|
|
|
GEN_FW_RANGE(0x1a000, 0x1bfff, FORCEWAKE_MEDIA),
|
|
|
|
GEN_FW_RANGE(0x1e800, 0x1e9ff, FORCEWAKE_MEDIA),
|
|
|
|
GEN_FW_RANGE(0x30000, 0x37fff, FORCEWAKE_MEDIA),
|
|
|
|
};
|
2014-03-29 00:54:26 +08:00
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
#define __fwtable_reg_write_fw_domains(uncore, offset) \
|
2016-04-12 21:37:29 +08:00
|
|
|
({ \
|
|
|
|
enum forcewake_domains __fwd = 0; \
|
2016-10-04 16:29:22 +08:00
|
|
|
if (NEEDS_FORCE_WAKE((offset)) && !is_gen8_shadowed(offset)) \
|
2019-03-20 02:35:39 +08:00
|
|
|
__fwd = find_fw_domain(uncore, offset); \
|
2016-04-12 21:37:29 +08:00
|
|
|
__fwd; \
|
|
|
|
})
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
#define __gen11_fwtable_reg_write_fw_domains(uncore, offset) \
|
2018-03-03 00:15:01 +08:00
|
|
|
({ \
|
|
|
|
enum forcewake_domains __fwd = 0; \
|
|
|
|
if (GEN11_NEEDS_FORCE_WAKE((offset)) && !is_gen11_shadowed(offset)) \
|
2019-03-20 02:35:39 +08:00
|
|
|
__fwd = find_fw_domain(uncore, offset); \
|
2018-03-03 00:15:01 +08:00
|
|
|
__fwd; \
|
|
|
|
})
|
|
|
|
|
2016-10-04 16:29:20 +08:00
|
|
|
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
|
2016-10-04 16:29:19 +08:00
|
|
|
static const struct intel_forcewake_range __gen9_fw_ranges[] = {
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */
|
|
|
|
GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x8000, 0x812f, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x8130, 0x813f, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x8500, 0x87ff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x8800, 0x89ff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x8a00, 0x8bff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_RENDER | FORCEWAKE_MEDIA),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
|
2016-11-17 17:02:43 +08:00
|
|
|
GEN_FW_RANGE(0xb480, 0xcfff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0xd000, 0xd7ff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0xd800, 0xdfff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0xe900, 0x11fff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x12000, 0x13fff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x14000, 0x19fff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x1a000, 0x1e9ff, FORCEWAKE_MEDIA),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x1ea00, 0x243ff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:20 +08:00
|
|
|
GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER),
|
2016-10-04 16:29:22 +08:00
|
|
|
GEN_FW_RANGE(0x24800, 0x2ffff, FORCEWAKE_BLITTER),
|
2016-10-04 16:29:19 +08:00
|
|
|
GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_MEDIA),
|
|
|
|
};
|
2016-04-12 21:37:29 +08:00
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
|
|
|
|
static const struct intel_forcewake_range __gen11_fw_ranges[] = {
|
|
|
|
GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */
|
|
|
|
GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x8500, 0x8bff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_ALL),
|
|
|
|
GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0xb480, 0xdfff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0xe900, 0x243ff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER),
|
|
|
|
GEN_FW_RANGE(0x24800, 0x3ffff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x40000, 0x1bffff, 0),
|
|
|
|
GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0),
|
|
|
|
GEN_FW_RANGE(0x1c4000, 0x1c7fff, FORCEWAKE_MEDIA_VDBOX1),
|
|
|
|
GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0),
|
|
|
|
GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_BLITTER),
|
|
|
|
GEN_FW_RANGE(0x1d0000, 0x1d3fff, FORCEWAKE_MEDIA_VDBOX2),
|
|
|
|
GEN_FW_RANGE(0x1d4000, 0x1d7fff, FORCEWAKE_MEDIA_VDBOX3),
|
|
|
|
GEN_FW_RANGE(0x1d8000, 0x1dbfff, FORCEWAKE_MEDIA_VEBOX1)
|
|
|
|
};
|
|
|
|
|
2013-07-20 03:36:52 +08:00
|
|
|
static void
|
2019-03-20 02:35:41 +08:00
|
|
|
ilk_dummy_write(struct intel_uncore *uncore)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
|
|
|
/* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up
|
|
|
|
* the chip from rc6 before touching it for real. MI_MODE is masked,
|
|
|
|
* hence harmless to write 0 into. */
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write32(uncore, MI_MODE, 0);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-03-26 05:49:34 +08:00
|
|
|
__unclaimed_reg_debug(struct intel_uncore *uncore,
|
2016-01-08 21:51:19 +08:00
|
|
|
const i915_reg_t reg,
|
|
|
|
const bool read,
|
|
|
|
const bool before)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
2019-03-26 05:49:34 +08:00
|
|
|
if (WARN(check_for_unclaimed_mmio(uncore) && !before,
|
2016-10-03 20:45:14 +08:00
|
|
|
"Unclaimed %s register 0x%x\n",
|
|
|
|
read ? "read from" : "write to",
|
2015-12-15 22:25:10 +08:00
|
|
|
i915_mmio_reg_offset(reg)))
|
2017-09-20 03:38:44 +08:00
|
|
|
/* Only report the first N failures */
|
|
|
|
i915_modparams.mmio_debug--;
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2016-01-08 21:51:19 +08:00
|
|
|
static inline void
|
2019-03-26 05:49:34 +08:00
|
|
|
unclaimed_reg_debug(struct intel_uncore *uncore,
|
2016-01-08 21:51:19 +08:00
|
|
|
const i915_reg_t reg,
|
|
|
|
const bool read,
|
|
|
|
const bool before)
|
|
|
|
{
|
2017-09-20 03:38:44 +08:00
|
|
|
if (likely(!i915_modparams.mmio_debug))
|
2016-01-08 21:51:19 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
__unclaimed_reg_debug(uncore, reg, read, before);
|
2016-01-08 21:51:19 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
#define GEN2_READ_HEADER(x) \
|
2013-10-05 12:24:53 +08:00
|
|
|
u##x val = 0; \
|
2019-03-26 05:49:35 +08:00
|
|
|
__assert_rpm_wakelock_held(uncore->rpm);
|
2013-10-05 12:24:53 +08:00
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
#define GEN2_READ_FOOTER \
|
2013-10-05 12:24:53 +08:00
|
|
|
trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
|
|
|
|
return val
|
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
#define __gen2_read(x) \
|
2013-10-05 12:22:51 +08:00
|
|
|
static u##x \
|
2019-03-26 05:49:36 +08:00
|
|
|
gen2_read##x(struct intel_uncore *uncore, i915_reg_t reg, bool trace) { \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_READ_HEADER(x); \
|
2019-03-26 05:49:32 +08:00
|
|
|
val = __raw_uncore_read##x(uncore, reg); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_READ_FOOTER; \
|
2013-10-05 12:22:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define __gen5_read(x) \
|
|
|
|
static u##x \
|
2019-03-26 05:49:36 +08:00
|
|
|
gen5_read##x(struct intel_uncore *uncore, i915_reg_t reg, bool trace) { \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_READ_HEADER(x); \
|
2019-03-20 02:35:41 +08:00
|
|
|
ilk_dummy_write(uncore); \
|
2019-03-26 05:49:32 +08:00
|
|
|
val = __raw_uncore_read##x(uncore, reg); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_READ_FOOTER; \
|
2013-10-05 12:22:53 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
__gen5_read(8)
|
|
|
|
__gen5_read(16)
|
|
|
|
__gen5_read(32)
|
|
|
|
__gen5_read(64)
|
|
|
|
__gen2_read(8)
|
|
|
|
__gen2_read(16)
|
|
|
|
__gen2_read(32)
|
|
|
|
__gen2_read(64)
|
|
|
|
|
|
|
|
#undef __gen5_read
|
|
|
|
#undef __gen2_read
|
|
|
|
|
|
|
|
#undef GEN2_READ_FOOTER
|
|
|
|
#undef GEN2_READ_HEADER
|
|
|
|
|
|
|
|
#define GEN6_READ_HEADER(x) \
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 21:33:26 +08:00
|
|
|
u32 offset = i915_mmio_reg_offset(reg); \
|
2015-01-16 17:34:36 +08:00
|
|
|
unsigned long irqflags; \
|
|
|
|
u##x val = 0; \
|
2019-03-26 05:49:35 +08:00
|
|
|
__assert_rpm_wakelock_held(uncore->rpm); \
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_lock_irqsave(&uncore->lock, irqflags); \
|
2019-03-26 05:49:34 +08:00
|
|
|
unclaimed_reg_debug(uncore, reg, true, true)
|
2015-01-16 17:34:36 +08:00
|
|
|
|
|
|
|
#define GEN6_READ_FOOTER \
|
2019-03-26 05:49:34 +08:00
|
|
|
unclaimed_reg_debug(uncore, reg, true, false); \
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags); \
|
2015-01-16 17:34:36 +08:00
|
|
|
trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
|
|
|
|
return val
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
static noinline void ___force_wake_auto(struct intel_uncore *uncore,
|
2016-10-04 16:29:18 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
2015-01-16 17:34:37 +08:00
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *domain;
|
2017-03-23 18:19:41 +08:00
|
|
|
unsigned int tmp;
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
GEM_BUG_ON(fw_domains & ~uncore->fw_domains);
|
2015-01-16 17:34:37 +08:00
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
for_each_fw_domain_masked(domain, fw_domains, uncore, tmp)
|
2016-10-04 16:29:18 +08:00
|
|
|
fw_domain_arm_timer(domain);
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
uncore->funcs.force_wake_get(uncore, fw_domains);
|
2016-10-04 16:29:18 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:35 +08:00
|
|
|
static inline void __force_wake_auto(struct intel_uncore *uncore,
|
2016-10-04 16:29:18 +08:00
|
|
|
enum forcewake_domains fw_domains)
|
|
|
|
{
|
2015-01-16 17:34:37 +08:00
|
|
|
if (WARN_ON(!fw_domains))
|
|
|
|
return;
|
|
|
|
|
2016-10-04 16:29:17 +08:00
|
|
|
/* Turn on all requested but inactive supported forcewake domains. */
|
2019-03-20 02:35:35 +08:00
|
|
|
fw_domains &= uncore->fw_domains;
|
|
|
|
fw_domains &= ~uncore->fw_domains_active;
|
2015-01-16 17:34:37 +08:00
|
|
|
|
2016-10-04 16:29:18 +08:00
|
|
|
if (fw_domains)
|
2019-03-20 02:35:35 +08:00
|
|
|
___force_wake_auto(uncore, fw_domains);
|
2015-01-16 17:34:37 +08:00
|
|
|
}
|
|
|
|
|
2017-02-04 09:23:29 +08:00
|
|
|
#define __gen_read(func, x) \
|
2013-10-05 12:22:53 +08:00
|
|
|
static u##x \
|
2019-03-26 05:49:36 +08:00
|
|
|
func##_read##x(struct intel_uncore *uncore, i915_reg_t reg, bool trace) { \
|
2016-04-12 21:37:29 +08:00
|
|
|
enum forcewake_domains fw_engine; \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN6_READ_HEADER(x); \
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_engine = __##func##_reg_read_fw_domains(uncore, offset); \
|
2015-10-22 20:34:59 +08:00
|
|
|
if (fw_engine) \
|
2019-03-20 02:35:39 +08:00
|
|
|
__force_wake_auto(uncore, fw_engine); \
|
2019-03-26 05:49:32 +08:00
|
|
|
val = __raw_uncore_read##x(uncore, reg); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN6_READ_FOOTER; \
|
2013-11-23 17:25:43 +08:00
|
|
|
}
|
2017-02-04 09:23:29 +08:00
|
|
|
#define __gen6_read(x) __gen_read(gen6, x)
|
|
|
|
#define __fwtable_read(x) __gen_read(fwtable, x)
|
2018-03-03 00:15:01 +08:00
|
|
|
#define __gen11_fwtable_read(x) __gen_read(gen11_fwtable, x)
|
2013-11-23 17:25:43 +08:00
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
__gen11_fwtable_read(8)
|
|
|
|
__gen11_fwtable_read(16)
|
|
|
|
__gen11_fwtable_read(32)
|
|
|
|
__gen11_fwtable_read(64)
|
2016-10-04 16:29:25 +08:00
|
|
|
__fwtable_read(8)
|
|
|
|
__fwtable_read(16)
|
|
|
|
__fwtable_read(32)
|
|
|
|
__fwtable_read(64)
|
2013-10-05 12:22:53 +08:00
|
|
|
__gen6_read(8)
|
|
|
|
__gen6_read(16)
|
|
|
|
__gen6_read(32)
|
|
|
|
__gen6_read(64)
|
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
#undef __gen11_fwtable_read
|
2016-10-04 16:29:25 +08:00
|
|
|
#undef __fwtable_read
|
2013-10-05 12:22:53 +08:00
|
|
|
#undef __gen6_read
|
2015-01-16 17:34:36 +08:00
|
|
|
#undef GEN6_READ_FOOTER
|
|
|
|
#undef GEN6_READ_HEADER
|
2013-10-05 12:24:53 +08:00
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
#define GEN2_WRITE_HEADER \
|
2013-10-05 12:24:53 +08:00
|
|
|
trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
|
2019-03-26 05:49:35 +08:00
|
|
|
__assert_rpm_wakelock_held(uncore->rpm); \
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
#define GEN2_WRITE_FOOTER
|
2013-12-02 20:23:02 +08:00
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
#define __gen2_write(x) \
|
2013-10-05 12:22:51 +08:00
|
|
|
static void \
|
2019-03-26 05:49:36 +08:00
|
|
|
gen2_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_WRITE_HEADER; \
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write##x(uncore, reg, val); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_WRITE_FOOTER; \
|
2013-10-05 12:22:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define __gen5_write(x) \
|
|
|
|
static void \
|
2019-03-26 05:49:36 +08:00
|
|
|
gen5_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_WRITE_HEADER; \
|
2019-03-20 02:35:41 +08:00
|
|
|
ilk_dummy_write(uncore); \
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write##x(uncore, reg, val); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN2_WRITE_FOOTER; \
|
2013-10-05 12:22:54 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 17:34:36 +08:00
|
|
|
__gen5_write(8)
|
|
|
|
__gen5_write(16)
|
|
|
|
__gen5_write(32)
|
|
|
|
__gen2_write(8)
|
|
|
|
__gen2_write(16)
|
|
|
|
__gen2_write(32)
|
|
|
|
|
|
|
|
#undef __gen5_write
|
|
|
|
#undef __gen2_write
|
|
|
|
|
|
|
|
#undef GEN2_WRITE_FOOTER
|
|
|
|
#undef GEN2_WRITE_HEADER
|
|
|
|
|
|
|
|
#define GEN6_WRITE_HEADER \
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 21:33:26 +08:00
|
|
|
u32 offset = i915_mmio_reg_offset(reg); \
|
2015-01-16 17:34:36 +08:00
|
|
|
unsigned long irqflags; \
|
|
|
|
trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
|
2019-03-26 05:49:35 +08:00
|
|
|
__assert_rpm_wakelock_held(uncore->rpm); \
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_lock_irqsave(&uncore->lock, irqflags); \
|
2019-03-26 05:49:34 +08:00
|
|
|
unclaimed_reg_debug(uncore, reg, false, true)
|
2015-01-16 17:34:36 +08:00
|
|
|
|
|
|
|
#define GEN6_WRITE_FOOTER \
|
2019-03-26 05:49:34 +08:00
|
|
|
unclaimed_reg_debug(uncore, reg, false, false); \
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_unlock_irqrestore(&uncore->lock, irqflags)
|
2015-01-16 17:34:36 +08:00
|
|
|
|
2013-10-05 12:22:54 +08:00
|
|
|
#define __gen6_write(x) \
|
|
|
|
static void \
|
2019-03-26 05:49:36 +08:00
|
|
|
gen6_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN6_WRITE_HEADER; \
|
2017-04-06 23:39:42 +08:00
|
|
|
if (NEEDS_FORCE_WAKE(offset)) \
|
2019-03-20 02:35:41 +08:00
|
|
|
__gen6_gt_wait_for_fifo(uncore); \
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write##x(uncore, reg, val); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN6_WRITE_FOOTER; \
|
2013-10-05 12:22:54 +08:00
|
|
|
}
|
|
|
|
|
2017-02-04 09:23:29 +08:00
|
|
|
#define __gen_write(func, x) \
|
drm/i915/bdw: Handle forcewake for writes on gen8
GEN8 removes the GT FIFO which we've all come to know and love. Instead
it offers a wider range of optimized registers which always keep a
shadowed copy, and are fed to the GPU when it wakes.
How this is implemented in hardware is still somewhat of a mystery. As
far as I can tell, the basic design is as follows:
If the register is not optimized, you must use the old forcewake
mechanism to bring the GT out of sleep. [1]
If register is in the optimized list the write will signal that the
GT should begin to come out of whatever sleep state it is in.
While the GT is coming out of sleep, the requested write will be stored
in an intermediate shadow register.
Do to the fact that the implementation details are not clear, I see
several risks:
1. Order is not preserved as it is with GT FIFO. If we issue multiple
writes to optimized registers, where order matters, we may need to
serialize it with forcewake.
2. The optimized registers have only 1 shadowed slot, meaning if we
issue multiple writes to the same register, and those values need to
reach the GPU in order, forcewake will be required.
[1] We could implement a SW queue the way the GT FIFO used to work if
desired.
NOTE: Compile tested only until we get real silicon.
v2:
- Use a default case to make future platforms also work.
- Get rid of IS_BROADWELL since that's not yet defined, but we want to
MMIO as soon as possible.
v3: Apply suggestions from Mika's review:
- s/optimized/shadowed/
- invert the logic of the helper so that it does what it says (the
code itself was correct, just confusing to read).
v4:
- Squash in lost break.
Signed-off-by: Ben Widawsky <ben@bwidawsk.net> (v1)
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-11-03 12:07:00 +08:00
|
|
|
static void \
|
2019-03-26 05:49:36 +08:00
|
|
|
func##_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \
|
2016-04-12 21:37:29 +08:00
|
|
|
enum forcewake_domains fw_engine; \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN6_WRITE_HEADER; \
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_engine = __##func##_reg_write_fw_domains(uncore, offset); \
|
2015-10-22 20:34:59 +08:00
|
|
|
if (fw_engine) \
|
2019-03-20 02:35:39 +08:00
|
|
|
__force_wake_auto(uncore, fw_engine); \
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write##x(uncore, reg, val); \
|
2015-01-16 17:34:36 +08:00
|
|
|
GEN6_WRITE_FOOTER; \
|
2014-05-23 23:30:16 +08:00
|
|
|
}
|
2017-02-04 09:23:29 +08:00
|
|
|
#define __gen8_write(x) __gen_write(gen8, x)
|
|
|
|
#define __fwtable_write(x) __gen_write(fwtable, x)
|
2018-03-03 00:15:01 +08:00
|
|
|
#define __gen11_fwtable_write(x) __gen_write(gen11_fwtable, x)
|
2014-05-23 23:30:16 +08:00
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
__gen11_fwtable_write(8)
|
|
|
|
__gen11_fwtable_write(16)
|
|
|
|
__gen11_fwtable_write(32)
|
2016-10-04 16:29:26 +08:00
|
|
|
__fwtable_write(8)
|
|
|
|
__fwtable_write(16)
|
|
|
|
__fwtable_write(32)
|
drm/i915/bdw: Handle forcewake for writes on gen8
GEN8 removes the GT FIFO which we've all come to know and love. Instead
it offers a wider range of optimized registers which always keep a
shadowed copy, and are fed to the GPU when it wakes.
How this is implemented in hardware is still somewhat of a mystery. As
far as I can tell, the basic design is as follows:
If the register is not optimized, you must use the old forcewake
mechanism to bring the GT out of sleep. [1]
If register is in the optimized list the write will signal that the
GT should begin to come out of whatever sleep state it is in.
While the GT is coming out of sleep, the requested write will be stored
in an intermediate shadow register.
Do to the fact that the implementation details are not clear, I see
several risks:
1. Order is not preserved as it is with GT FIFO. If we issue multiple
writes to optimized registers, where order matters, we may need to
serialize it with forcewake.
2. The optimized registers have only 1 shadowed slot, meaning if we
issue multiple writes to the same register, and those values need to
reach the GPU in order, forcewake will be required.
[1] We could implement a SW queue the way the GT FIFO used to work if
desired.
NOTE: Compile tested only until we get real silicon.
v2:
- Use a default case to make future platforms also work.
- Get rid of IS_BROADWELL since that's not yet defined, but we want to
MMIO as soon as possible.
v3: Apply suggestions from Mika's review:
- s/optimized/shadowed/
- invert the logic of the helper so that it does what it says (the
code itself was correct, just confusing to read).
v4:
- Squash in lost break.
Signed-off-by: Ben Widawsky <ben@bwidawsk.net> (v1)
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-11-03 12:07:00 +08:00
|
|
|
__gen8_write(8)
|
|
|
|
__gen8_write(16)
|
|
|
|
__gen8_write(32)
|
2013-10-05 12:22:54 +08:00
|
|
|
__gen6_write(8)
|
|
|
|
__gen6_write(16)
|
|
|
|
__gen6_write(32)
|
|
|
|
|
2018-03-03 00:15:01 +08:00
|
|
|
#undef __gen11_fwtable_write
|
2016-10-04 16:29:26 +08:00
|
|
|
#undef __fwtable_write
|
drm/i915/bdw: Handle forcewake for writes on gen8
GEN8 removes the GT FIFO which we've all come to know and love. Instead
it offers a wider range of optimized registers which always keep a
shadowed copy, and are fed to the GPU when it wakes.
How this is implemented in hardware is still somewhat of a mystery. As
far as I can tell, the basic design is as follows:
If the register is not optimized, you must use the old forcewake
mechanism to bring the GT out of sleep. [1]
If register is in the optimized list the write will signal that the
GT should begin to come out of whatever sleep state it is in.
While the GT is coming out of sleep, the requested write will be stored
in an intermediate shadow register.
Do to the fact that the implementation details are not clear, I see
several risks:
1. Order is not preserved as it is with GT FIFO. If we issue multiple
writes to optimized registers, where order matters, we may need to
serialize it with forcewake.
2. The optimized registers have only 1 shadowed slot, meaning if we
issue multiple writes to the same register, and those values need to
reach the GPU in order, forcewake will be required.
[1] We could implement a SW queue the way the GT FIFO used to work if
desired.
NOTE: Compile tested only until we get real silicon.
v2:
- Use a default case to make future platforms also work.
- Get rid of IS_BROADWELL since that's not yet defined, but we want to
MMIO as soon as possible.
v3: Apply suggestions from Mika's review:
- s/optimized/shadowed/
- invert the logic of the helper so that it does what it says (the
code itself was correct, just confusing to read).
v4:
- Squash in lost break.
Signed-off-by: Ben Widawsky <ben@bwidawsk.net> (v1)
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-11-03 12:07:00 +08:00
|
|
|
#undef __gen8_write
|
2013-10-05 12:22:54 +08:00
|
|
|
#undef __gen6_write
|
2015-01-16 17:34:36 +08:00
|
|
|
#undef GEN6_WRITE_FOOTER
|
|
|
|
#undef GEN6_WRITE_HEADER
|
2013-07-20 03:36:52 +08:00
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
#define ASSIGN_WRITE_MMIO_VFUNCS(uncore, x) \
|
2014-10-23 15:28:24 +08:00
|
|
|
do { \
|
2019-03-20 02:35:37 +08:00
|
|
|
(uncore)->funcs.mmio_writeb = x##_write8; \
|
|
|
|
(uncore)->funcs.mmio_writew = x##_write16; \
|
|
|
|
(uncore)->funcs.mmio_writel = x##_write32; \
|
2014-10-23 15:28:24 +08:00
|
|
|
} while (0)
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
#define ASSIGN_READ_MMIO_VFUNCS(uncore, x) \
|
2014-10-23 15:28:24 +08:00
|
|
|
do { \
|
2019-03-20 02:35:37 +08:00
|
|
|
(uncore)->funcs.mmio_readb = x##_read8; \
|
|
|
|
(uncore)->funcs.mmio_readw = x##_read16; \
|
|
|
|
(uncore)->funcs.mmio_readl = x##_read32; \
|
|
|
|
(uncore)->funcs.mmio_readq = x##_read64; \
|
2014-10-23 15:28:24 +08:00
|
|
|
} while (0)
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
static void fw_domain_init(struct intel_uncore *uncore,
|
2015-01-16 17:34:41 +08:00
|
|
|
enum forcewake_domain_id domain_id,
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 21:33:26 +08:00
|
|
|
i915_reg_t reg_set,
|
|
|
|
i915_reg_t reg_ack)
|
2015-01-19 22:20:43 +08:00
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *d;
|
|
|
|
|
|
|
|
if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
|
|
|
|
return;
|
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
d = &uncore->fw_domain[domain_id];
|
2015-01-19 22:20:43 +08:00
|
|
|
|
|
|
|
WARN_ON(d->wake_count);
|
|
|
|
|
2017-03-23 18:19:43 +08:00
|
|
|
WARN_ON(!i915_mmio_reg_valid(reg_set));
|
|
|
|
WARN_ON(!i915_mmio_reg_valid(reg_ack));
|
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
d->wake_count = 0;
|
2019-03-20 02:35:40 +08:00
|
|
|
d->reg_set = uncore->regs + i915_mmio_reg_offset(reg_set);
|
|
|
|
d->reg_ack = uncore->regs + i915_mmio_reg_offset(reg_ack);
|
2015-01-19 22:20:43 +08:00
|
|
|
|
|
|
|
d->id = domain_id;
|
|
|
|
|
2016-04-08 00:04:33 +08:00
|
|
|
BUILD_BUG_ON(FORCEWAKE_RENDER != (1 << FW_DOMAIN_ID_RENDER));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_BLITTER != (1 << FW_DOMAIN_ID_BLITTER));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA != (1 << FW_DOMAIN_ID_MEDIA));
|
2018-03-03 00:15:01 +08:00
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX0));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX1));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX2 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX2));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX3 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX3));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX0));
|
|
|
|
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX1));
|
|
|
|
|
2016-04-08 00:04:33 +08:00
|
|
|
|
2017-03-23 18:19:41 +08:00
|
|
|
d->mask = BIT(domain_id);
|
2016-04-08 00:04:33 +08:00
|
|
|
|
drm/i915: Use consistent forcewake auto-release timeout across kernel configs
Because it is based on jiffies, current implementation releases the
forcewake at any time between straight away and between 1ms and 10ms,
depending on the kernel configuration (CONFIG_HZ).
This is probably not what has been desired, since the dynamics of keeping
parts of the GPU awake should not be correlated with this kernel
configuration parameter.
Change the auto-release mechanism to use hrtimers and set the timeout to
1ms with a 1ms of slack. This should make the GPU power consistent
across kernel configs, and timer slack should enable some timer coalescing
where multiple force-wake domains exist, or with unrelated timers.
For GlBench/T-Rex this decreases the number of forcewake releases from
~480 to ~300 per second, and for a heavy combined OGL/OCL test from
~670 to ~360 (HZ=1000 kernel).
Even though this reduction can be attributed to the average release period
extending from 0-1ms to 1-2ms, as discussed above, it will make the
forcewake timeout consistent for different CONFIG_HZ values.
Real life measurements with the above workload has shown that, with this
patch, both manage to auto-release the forcewake between 2-4 times per
10ms, even though the number of forcewake gets is dramatically different.
T-Rex requests between 5-10 explicit gets and 5-10 implict gets in each
10ms period, while the OGL/OCL test requests 250 and 380 times in the same
period.
The two data points together suggest that the nature of the forwake
accesses is bursty and that further changes and potential timeout
extensions, or moving the start of timeout from the first to the last
automatic forcewake grab, should be carefully measured for power and
performance effects.
v2:
* Commit spelling. (Dave Gordon)
* More discussion on numbers in the commit. (Chris Wilson)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
2016-04-08 00:04:32 +08:00
|
|
|
hrtimer_init(&d->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
|
|
d->timer.function = intel_uncore_fw_release_timer;
|
2015-01-19 22:20:43 +08:00
|
|
|
|
2019-03-16 18:00:45 +08:00
|
|
|
uncore->fw_domains |= BIT(domain_id);
|
2015-01-28 20:43:24 +08:00
|
|
|
|
2019-03-20 20:27:32 +08:00
|
|
|
fw_domain_reset(d);
|
2015-01-19 22:20:43 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
static void fw_domain_fini(struct intel_uncore *uncore,
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
enum forcewake_domain_id domain_id)
|
|
|
|
{
|
|
|
|
struct intel_uncore_forcewake_domain *d;
|
|
|
|
|
|
|
|
if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
|
|
|
|
return;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
d = &uncore->fw_domain[domain_id];
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
|
|
|
|
WARN_ON(d->wake_count);
|
|
|
|
WARN_ON(hrtimer_cancel(&d->timer));
|
|
|
|
memset(d, 0, sizeof(*d));
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->fw_domains &= ~BIT(domain_id);
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
|
2013-10-05 12:22:51 +08:00
|
|
|
{
|
2019-03-20 02:35:37 +08:00
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
|
|
|
|
2019-03-26 05:49:33 +08:00
|
|
|
if (!intel_uncore_has_forcewake(uncore))
|
2015-02-05 23:45:42 +08:00
|
|
|
return;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
if (INTEL_GEN(i915) >= 11) {
|
2018-03-03 00:15:01 +08:00
|
|
|
int i;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_get =
|
2018-05-09 05:29:23 +08:00
|
|
|
fw_domains_get_with_fallback;
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_put = fw_domains_put;
|
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2018-03-03 00:15:01 +08:00
|
|
|
FORCEWAKE_RENDER_GEN9,
|
|
|
|
FORCEWAKE_ACK_RENDER_GEN9);
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
|
2018-03-03 00:15:01 +08:00
|
|
|
FORCEWAKE_BLITTER_GEN9,
|
|
|
|
FORCEWAKE_ACK_BLITTER_GEN9);
|
|
|
|
for (i = 0; i < I915_MAX_VCS; i++) {
|
2019-03-20 02:35:37 +08:00
|
|
|
if (!HAS_ENGINE(i915, _VCS(i)))
|
2018-03-03 00:15:01 +08:00
|
|
|
continue;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA_VDBOX0 + i,
|
2018-03-03 00:15:01 +08:00
|
|
|
FORCEWAKE_MEDIA_VDBOX_GEN11(i),
|
|
|
|
FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(i));
|
|
|
|
}
|
|
|
|
for (i = 0; i < I915_MAX_VECS; i++) {
|
2019-03-20 02:35:37 +08:00
|
|
|
if (!HAS_ENGINE(i915, _VECS(i)))
|
2018-03-03 00:15:01 +08:00
|
|
|
continue;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA_VEBOX0 + i,
|
2018-03-03 00:15:01 +08:00
|
|
|
FORCEWAKE_MEDIA_VEBOX_GEN11(i),
|
|
|
|
FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
|
|
|
|
}
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_GEN_RANGE(i915, 9, 10)) {
|
|
|
|
uncore->funcs.force_wake_get =
|
2017-11-02 17:48:36 +08:00
|
|
|
fw_domains_get_with_fallback;
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_put = fw_domains_put;
|
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_RENDER_GEN9,
|
|
|
|
FORCEWAKE_ACK_RENDER_GEN9);
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_BLITTER_GEN9,
|
|
|
|
FORCEWAKE_ACK_BLITTER_GEN9);
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
|
|
|
|
uncore->funcs.force_wake_get = fw_domains_get;
|
|
|
|
uncore->funcs.force_wake_put = fw_domains_put;
|
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
|
|
|
|
uncore->funcs.force_wake_get =
|
2015-01-19 22:20:43 +08:00
|
|
|
fw_domains_get_with_thread_status;
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_put = fw_domains_put;
|
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_IVYBRIDGE(i915)) {
|
2013-10-05 12:22:51 +08:00
|
|
|
u32 ecobus;
|
|
|
|
|
|
|
|
/* IVB configs may use multi-threaded forcewake */
|
|
|
|
|
|
|
|
/* A small trick here - if the bios hasn't configured
|
|
|
|
* MT forcewake, and if the device is in RC6, then
|
|
|
|
* force_wake_mt_get will not wake the device and the
|
|
|
|
* ECOBUS read will return zero. Which will be
|
|
|
|
* (correctly) interpreted by the test below as MT
|
|
|
|
* forcewake being disabled.
|
|
|
|
*/
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_get =
|
2015-01-19 22:20:43 +08:00
|
|
|
fw_domains_get_with_thread_status;
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_put = fw_domains_put;
|
2015-01-19 22:20:43 +08:00
|
|
|
|
2015-01-28 20:43:24 +08:00
|
|
|
/* We need to init first for ECOBUS access and then
|
|
|
|
* determine later if we want to reinit, in case of MT access is
|
2015-02-28 00:11:09 +08:00
|
|
|
* not working. In this stage we don't know which flavour this
|
|
|
|
* ivb is, so it is better to reset also the gen6 fw registers
|
|
|
|
* before the ecobus check.
|
2015-01-28 20:43:24 +08:00
|
|
|
*/
|
2015-02-28 00:11:09 +08:00
|
|
|
|
2019-03-26 05:49:32 +08:00
|
|
|
__raw_uncore_write32(uncore, FORCEWAKE, 0);
|
2019-03-20 02:35:41 +08:00
|
|
|
__raw_posting_read(uncore, ECOBUS);
|
2015-02-28 00:11:09 +08:00
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE_MT, FORCEWAKE_MT_ACK);
|
2015-01-28 20:43:24 +08:00
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
spin_lock_irq(&uncore->lock);
|
|
|
|
fw_domains_get_with_thread_status(uncore, FORCEWAKE_RENDER);
|
2019-03-26 05:49:32 +08:00
|
|
|
ecobus = __raw_uncore_read32(uncore, ECOBUS);
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domains_put(uncore, FORCEWAKE_RENDER);
|
|
|
|
spin_unlock_irq(&uncore->lock);
|
2013-10-05 12:22:51 +08:00
|
|
|
|
2015-01-19 22:20:43 +08:00
|
|
|
if (!(ecobus & FORCEWAKE_MT_ENABLE)) {
|
2013-10-05 12:22:51 +08:00
|
|
|
DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
|
|
|
|
DRM_INFO("when using vblank-synced partial screen updates.\n");
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE, FORCEWAKE_ACK);
|
2013-10-05 12:22:51 +08:00
|
|
|
}
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_GEN(i915, 6)) {
|
|
|
|
uncore->funcs.force_wake_get =
|
2015-01-19 22:20:43 +08:00
|
|
|
fw_domains_get_with_thread_status;
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->funcs.force_wake_put = fw_domains_put;
|
|
|
|
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
|
2015-01-19 22:20:43 +08:00
|
|
|
FORCEWAKE, FORCEWAKE_ACK);
|
2013-10-05 12:22:51 +08:00
|
|
|
}
|
2015-02-05 23:45:42 +08:00
|
|
|
|
|
|
|
/* All future platforms are expected to require complex power gating */
|
2019-03-20 02:35:37 +08:00
|
|
|
WARN_ON(uncore->fw_domains == 0);
|
2015-01-28 20:43:24 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
#define ASSIGN_FW_DOMAINS_TABLE(uncore, d) \
|
2016-10-04 16:29:23 +08:00
|
|
|
{ \
|
2019-03-20 02:35:37 +08:00
|
|
|
(uncore)->fw_domains_table = \
|
2016-10-04 16:29:23 +08:00
|
|
|
(struct intel_forcewake_range *)(d); \
|
2019-03-20 02:35:37 +08:00
|
|
|
(uncore)->fw_domains_table_entries = ARRAY_SIZE((d)); \
|
2016-10-04 16:29:23 +08:00
|
|
|
}
|
|
|
|
|
2017-02-10 18:28:02 +08:00
|
|
|
static int i915_pmic_bus_access_notifier(struct notifier_block *nb,
|
|
|
|
unsigned long action, void *data)
|
|
|
|
{
|
|
|
|
struct drm_i915_private *dev_priv = container_of(nb,
|
|
|
|
struct drm_i915_private, uncore.pmic_bus_access_nb);
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case MBI_PMIC_BUS_ACCESS_BEGIN:
|
|
|
|
/*
|
|
|
|
* forcewake all now to make sure that we don't need to do a
|
|
|
|
* forcewake later which on systems where this notifier gets
|
|
|
|
* called requires the punit to access to the shared pmic i2c
|
|
|
|
* bus, which will be busy after this notification, leading to:
|
|
|
|
* "render: timed out waiting for forcewake ack request."
|
|
|
|
* errors.
|
2017-11-10 23:03:01 +08:00
|
|
|
*
|
|
|
|
* The notifier is unregistered during intel_runtime_suspend(),
|
|
|
|
* so it's ok to access the HW here without holding a RPM
|
|
|
|
* wake reference -> disable wakeref asserts for the time of
|
|
|
|
* the access.
|
2017-02-10 18:28:02 +08:00
|
|
|
*/
|
2017-11-10 23:03:01 +08:00
|
|
|
disable_rpm_wakeref_asserts(dev_priv);
|
2019-03-20 02:35:36 +08:00
|
|
|
intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL);
|
2017-11-10 23:03:01 +08:00
|
|
|
enable_rpm_wakeref_asserts(dev_priv);
|
2017-02-10 18:28:02 +08:00
|
|
|
break;
|
|
|
|
case MBI_PMIC_BUS_ACCESS_END:
|
2019-03-20 02:35:36 +08:00
|
|
|
intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
|
2017-02-10 18:28:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NOTIFY_OK;
|
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:40 +08:00
|
|
|
static int uncore_mmio_setup(struct intel_uncore *uncore)
|
|
|
|
{
|
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
|
|
|
struct pci_dev *pdev = i915->drm.pdev;
|
|
|
|
int mmio_bar;
|
|
|
|
int mmio_size;
|
|
|
|
|
|
|
|
mmio_bar = IS_GEN(i915, 2) ? 1 : 0;
|
|
|
|
/*
|
|
|
|
* Before gen4, the registers and the GTT are behind different BARs.
|
|
|
|
* However, from gen4 onwards, the registers and the GTT are shared
|
|
|
|
* in the same BAR, so we want to restrict this ioremap from
|
|
|
|
* clobbering the GTT which we want ioremap_wc instead. Fortunately,
|
|
|
|
* the register BAR remains the same size for all the earlier
|
|
|
|
* generations up to Ironlake.
|
|
|
|
*/
|
|
|
|
if (INTEL_GEN(i915) < 5)
|
|
|
|
mmio_size = 512 * 1024;
|
|
|
|
else
|
|
|
|
mmio_size = 2 * 1024 * 1024;
|
|
|
|
uncore->regs = pci_iomap(pdev, mmio_bar, mmio_size);
|
|
|
|
if (uncore->regs == NULL) {
|
|
|
|
DRM_ERROR("failed to map registers\n");
|
|
|
|
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void uncore_mmio_cleanup(struct intel_uncore *uncore)
|
|
|
|
{
|
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
|
|
|
struct pci_dev *pdev = i915->drm.pdev;
|
|
|
|
|
|
|
|
pci_iounmap(pdev, uncore->regs);
|
|
|
|
}
|
|
|
|
|
2019-04-03 04:10:31 +08:00
|
|
|
void intel_uncore_init_early(struct intel_uncore *uncore)
|
|
|
|
{
|
|
|
|
spin_lock_init(&uncore->lock);
|
|
|
|
}
|
2019-03-20 02:35:40 +08:00
|
|
|
|
2019-04-03 04:10:32 +08:00
|
|
|
int intel_uncore_init_mmio(struct intel_uncore *uncore)
|
2015-01-28 20:43:24 +08:00
|
|
|
{
|
2019-03-20 02:35:37 +08:00
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
2019-03-20 02:35:40 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = uncore_mmio_setup(uncore);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2019-03-20 02:35:37 +08:00
|
|
|
|
|
|
|
i915_check_vgpu(i915);
|
2015-02-10 19:05:47 +08:00
|
|
|
|
2019-03-26 05:49:33 +08:00
|
|
|
if (INTEL_GEN(i915) > 5 && !intel_vgpu_active(i915))
|
|
|
|
uncore->flags |= UNCORE_HAS_FORCEWAKE;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
intel_uncore_fw_domains_init(uncore);
|
|
|
|
__intel_uncore_early_sanitize(uncore, 0);
|
2013-10-05 12:22:51 +08:00
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
uncore->unclaimed_mmio_check = 1;
|
|
|
|
uncore->pmic_bus_access_nb.notifier_call =
|
2017-02-10 18:28:02 +08:00
|
|
|
i915_pmic_bus_access_notifier;
|
2015-12-16 15:26:48 +08:00
|
|
|
|
2019-03-26 05:49:35 +08:00
|
|
|
uncore->rpm = &i915->runtime_pm;
|
|
|
|
|
2019-03-26 05:49:33 +08:00
|
|
|
if (!intel_uncore_has_forcewake(uncore)) {
|
|
|
|
if (IS_GEN(i915, 5)) {
|
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen5);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, gen5);
|
|
|
|
} else {
|
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen2);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, gen2);
|
|
|
|
}
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_GEN_RANGE(i915, 6, 7)) {
|
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen6);
|
|
|
|
|
|
|
|
if (IS_VALLEYVIEW(i915)) {
|
|
|
|
ASSIGN_FW_DOMAINS_TABLE(uncore, __vlv_fw_ranges);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable);
|
2017-03-10 17:57:47 +08:00
|
|
|
} else {
|
2019-03-20 02:35:37 +08:00
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, gen6);
|
2016-11-16 01:19:20 +08:00
|
|
|
}
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_GEN(i915, 8)) {
|
|
|
|
if (IS_CHERRYVIEW(i915)) {
|
|
|
|
ASSIGN_FW_DOMAINS_TABLE(uncore, __chv_fw_ranges);
|
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable);
|
2014-05-23 23:30:16 +08:00
|
|
|
|
|
|
|
} else {
|
2019-03-20 02:35:37 +08:00
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen8);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, gen6);
|
2014-05-23 23:30:16 +08:00
|
|
|
}
|
2019-03-20 02:35:37 +08:00
|
|
|
} else if (IS_GEN_RANGE(i915, 9, 10)) {
|
|
|
|
ASSIGN_FW_DOMAINS_TABLE(uncore, __gen9_fw_ranges);
|
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable);
|
2018-03-03 00:15:01 +08:00
|
|
|
} else {
|
2019-03-20 02:35:37 +08:00
|
|
|
ASSIGN_FW_DOMAINS_TABLE(uncore, __gen11_fw_ranges);
|
|
|
|
ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen11_fwtable);
|
|
|
|
ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable);
|
2013-10-05 12:22:53 +08:00
|
|
|
}
|
2014-10-24 00:23:21 +08:00
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
if (HAS_FPGA_DBG_UNCLAIMED(i915))
|
|
|
|
uncore->flags |= UNCORE_HAS_FPGA_DBG_UNCLAIMED;
|
|
|
|
|
|
|
|
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
|
|
|
|
uncore->flags |= UNCORE_HAS_DBG_UNCLAIMED;
|
|
|
|
|
|
|
|
if (IS_GEN_RANGE(i915, 6, 7))
|
|
|
|
uncore->flags |= UNCORE_HAS_FIFO;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
iosf_mbi_register_pmic_bus_access_notifier(&uncore->pmic_bus_access_nb);
|
2019-03-20 02:35:40 +08:00
|
|
|
|
|
|
|
return 0;
|
2013-10-05 12:22:51 +08:00
|
|
|
}
|
|
|
|
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
/*
|
|
|
|
* We might have detected that some engines are fused off after we initialized
|
|
|
|
* the forcewake domains. Prune them, to make sure they only reference existing
|
|
|
|
* engines.
|
|
|
|
*/
|
2019-04-03 04:10:32 +08:00
|
|
|
void intel_uncore_prune_mmio_domains(struct intel_uncore *uncore)
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
{
|
2019-03-20 02:35:37 +08:00
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
|
|
|
|
|
|
|
if (INTEL_GEN(i915) >= 11) {
|
|
|
|
enum forcewake_domains fw_domains = uncore->fw_domains;
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
enum forcewake_domain_id domain_id;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < I915_MAX_VCS; i++) {
|
|
|
|
domain_id = FW_DOMAIN_ID_MEDIA_VDBOX0 + i;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
if (HAS_ENGINE(i915, _VCS(i)))
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (fw_domains & BIT(domain_id))
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_fini(uncore, domain_id);
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < I915_MAX_VECS; i++) {
|
|
|
|
domain_id = FW_DOMAIN_ID_MEDIA_VEBOX0 + i;
|
|
|
|
|
2019-03-20 02:35:37 +08:00
|
|
|
if (HAS_ENGINE(i915, _VECS(i)))
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (fw_domains & BIT(domain_id))
|
2019-03-20 02:35:37 +08:00
|
|
|
fw_domain_fini(uncore, domain_id);
|
drm/i915/icl: Check for fused-off VDBOX and VEBOX instances
In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the
Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also,
each VDBOX and VEBOX has its own power well, which only exist if the
related engine exists in the HW.
Unfortunately, we have a Catch-22 situation going on: we need the blitter
forcewake to read the register with the fuse info, but we cannot initialize
the forcewake domains without knowin about the engines present in the HW.
We workaround this problem by allowing the initialization of all forcewake
domains and then pruning the fused off ones, as per the fuse information.
Bspec: 20680
v2: We were shifting incorrectly for vebox disable (Vinay)
v3: Assert mmio is ready and warn if we have attempted to initialize
forcewake for fused-off engines (Paulo)
v4:
- Use INTEL_GEN in new code (Tvrtko)
- Shorter local variable (Tvrtko, Michal)
- Keep "if (!...) continue" style (Tvrtko)
- No unnecessary BUG_ON (Tvrtko)
- WARN_ON and cleanup if wrong mask (Tvrtko, Michal)
- Use I915_READ_FW (Michal)
- Use I915_MAX_VCS/VECS macros (Michal)
v5: Rebased by Rodrigo fixing conflicts on top of:
"drm/i915: Simplify intel_engines_init"
v6: Fix v5. Remove info->num_rings. (by Oscar)
v7: Rebase (Rodrigo).
v8:
- s/intel_device_info_fused_off_engines/
intel_device_info_init_mmio (Chris)
- Make vdbox_disable & vebox_disable local variables (Chris)
v9:
- Move function declaration to intel_device_info.h (Michal)
- Missing indent in bit fields definitions (Michal)
- When RC6 is enabled by BIOS, the fuse register cannot be read until
the blitter powerwell is awake. Shuffle where the fuse is read, prune
the forcewake domains after the fact and change the commit message
accordingly (Vinay, Sagar, Chris).
v10:
- Improved commit message (Sagar)
- New line in header file (Sagar)
- Specify the message in fw_domain_reset applies to ICL+ (Sagar)
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com
[Mika: soothe checkpatch on commit msg]
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
2018-03-16 20:14:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 04:10:32 +08:00
|
|
|
void intel_uncore_fini_mmio(struct intel_uncore *uncore)
|
2013-10-05 12:22:51 +08:00
|
|
|
{
|
|
|
|
/* Paranoia: make sure we have disabled everything before we exit. */
|
2019-03-20 02:35:37 +08:00
|
|
|
intel_uncore_sanitize(uncore_to_i915(uncore));
|
2017-10-19 19:16:20 +08:00
|
|
|
|
|
|
|
iosf_mbi_punit_acquire();
|
|
|
|
iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
|
2019-03-20 02:35:37 +08:00
|
|
|
&uncore->pmic_bus_access_nb);
|
|
|
|
intel_uncore_forcewake_reset(uncore);
|
2017-10-19 19:16:20 +08:00
|
|
|
iosf_mbi_punit_release();
|
2019-03-20 02:35:40 +08:00
|
|
|
uncore_mmio_cleanup(uncore);
|
2013-10-05 12:22:51 +08:00
|
|
|
}
|
|
|
|
|
2017-09-13 19:52:55 +08:00
|
|
|
static const struct reg_whitelist {
|
|
|
|
i915_reg_t offset_ldw;
|
|
|
|
i915_reg_t offset_udw;
|
|
|
|
u16 gen_mask;
|
|
|
|
u8 size;
|
|
|
|
} reg_read_whitelist[] = { {
|
|
|
|
.offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE),
|
|
|
|
.offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE),
|
2018-01-30 21:49:18 +08:00
|
|
|
.gen_mask = INTEL_GEN_MASK(4, 11),
|
2017-09-13 19:52:55 +08:00
|
|
|
.size = 8
|
|
|
|
} };
|
2013-07-20 03:36:52 +08:00
|
|
|
|
|
|
|
int i915_reg_read_ioctl(struct drm_device *dev,
|
|
|
|
void *data, struct drm_file *file)
|
|
|
|
{
|
2016-07-04 18:34:36 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-07-20 03:36:52 +08:00
|
|
|
struct drm_i915_reg_read *reg = data;
|
2017-09-13 19:52:55 +08:00
|
|
|
struct reg_whitelist const *entry;
|
2019-01-14 22:21:18 +08:00
|
|
|
intel_wakeref_t wakeref;
|
2017-09-13 19:52:55 +08:00
|
|
|
unsigned int flags;
|
|
|
|
int remain;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
entry = reg_read_whitelist;
|
|
|
|
remain = ARRAY_SIZE(reg_read_whitelist);
|
|
|
|
while (remain) {
|
|
|
|
u32 entry_offset = i915_mmio_reg_offset(entry->offset_ldw);
|
|
|
|
|
|
|
|
GEM_BUG_ON(!is_power_of_2(entry->size));
|
|
|
|
GEM_BUG_ON(entry->size > 8);
|
|
|
|
GEM_BUG_ON(entry_offset & (entry->size - 1));
|
|
|
|
|
|
|
|
if (INTEL_INFO(dev_priv)->gen_mask & entry->gen_mask &&
|
|
|
|
entry_offset == (reg->offset & -entry->size))
|
2013-07-20 03:36:52 +08:00
|
|
|
break;
|
2017-09-13 19:52:55 +08:00
|
|
|
entry++;
|
|
|
|
remain--;
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2017-09-13 19:52:55 +08:00
|
|
|
if (!remain)
|
2013-07-20 03:36:52 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-09-13 19:52:55 +08:00
|
|
|
flags = reg->offset & (entry->size - 1);
|
2015-07-16 19:37:56 +08:00
|
|
|
|
2019-01-14 22:21:23 +08:00
|
|
|
with_intel_runtime_pm(dev_priv, wakeref) {
|
|
|
|
if (entry->size == 8 && flags == I915_REG_READ_8B_WA)
|
|
|
|
reg->val = I915_READ64_2x32(entry->offset_ldw,
|
|
|
|
entry->offset_udw);
|
|
|
|
else if (entry->size == 8 && flags == 0)
|
|
|
|
reg->val = I915_READ64(entry->offset_ldw);
|
|
|
|
else if (entry->size == 4 && flags == 0)
|
|
|
|
reg->val = I915_READ(entry->offset_ldw);
|
|
|
|
else if (entry->size == 2 && flags == 0)
|
|
|
|
reg->val = I915_READ16(entry->offset_ldw);
|
|
|
|
else if (entry->size == 1 && flags == 0)
|
|
|
|
reg->val = I915_READ8(entry->offset_ldw);
|
|
|
|
else
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
2017-09-13 19:52:55 +08:00
|
|
|
|
2014-04-02 01:55:08 +08:00
|
|
|
return ret;
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2016-06-30 22:32:44 +08:00
|
|
|
/**
|
2017-04-08 00:01:44 +08:00
|
|
|
* __intel_wait_for_register_fw - wait until register matches expected state
|
2019-03-26 05:49:38 +08:00
|
|
|
* @uncore: the struct intel_uncore
|
2016-06-30 22:32:44 +08:00
|
|
|
* @reg: the register to read
|
|
|
|
* @mask: mask to apply to register value
|
|
|
|
* @value: expected value
|
2017-04-08 00:01:44 +08:00
|
|
|
* @fast_timeout_us: fast timeout in microsecond for atomic/tight wait
|
|
|
|
* @slow_timeout_ms: slow timeout in millisecond
|
|
|
|
* @out_value: optional placeholder to hold registry value
|
2016-06-30 22:32:44 +08:00
|
|
|
*
|
|
|
|
* This routine waits until the target register @reg contains the expected
|
2016-07-16 03:48:05 +08:00
|
|
|
* @value after applying the @mask, i.e. it waits until ::
|
|
|
|
*
|
|
|
|
* (I915_READ_FW(reg) & mask) == value
|
|
|
|
*
|
2017-04-08 00:01:44 +08:00
|
|
|
* Otherwise, the wait will timeout after @slow_timeout_ms milliseconds.
|
2017-04-10 20:17:47 +08:00
|
|
|
* For atomic context @slow_timeout_ms must be zero and @fast_timeout_us
|
2017-04-11 19:27:05 +08:00
|
|
|
* must be not larger than 20,0000 microseconds.
|
2016-06-30 22:32:44 +08:00
|
|
|
*
|
|
|
|
* Note that this routine assumes the caller holds forcewake asserted, it is
|
|
|
|
* not suitable for very long waits. See intel_wait_for_register() if you
|
|
|
|
* wish to wait without holding forcewake for the duration (i.e. you expect
|
|
|
|
* the wait to be slow).
|
|
|
|
*
|
|
|
|
* Returns 0 if the register matches the desired condition, or -ETIMEOUT.
|
|
|
|
*/
|
2019-03-26 05:49:38 +08:00
|
|
|
int __intel_wait_for_register_fw(struct intel_uncore *uncore,
|
2017-04-08 00:01:44 +08:00
|
|
|
i915_reg_t reg,
|
2017-04-10 17:38:17 +08:00
|
|
|
u32 mask,
|
|
|
|
u32 value,
|
|
|
|
unsigned int fast_timeout_us,
|
|
|
|
unsigned int slow_timeout_ms,
|
2017-04-08 00:01:44 +08:00
|
|
|
u32 *out_value)
|
2016-06-30 22:32:44 +08:00
|
|
|
{
|
2017-05-10 23:19:32 +08:00
|
|
|
u32 uninitialized_var(reg_value);
|
2019-03-26 05:49:38 +08:00
|
|
|
#define done (((reg_value = intel_uncore_read_fw(uncore, reg)) & mask) == value)
|
2017-04-08 00:01:44 +08:00
|
|
|
int ret;
|
|
|
|
|
2017-04-10 20:17:47 +08:00
|
|
|
/* Catch any overuse of this function */
|
2017-04-11 19:27:05 +08:00
|
|
|
might_sleep_if(slow_timeout_ms);
|
|
|
|
GEM_BUG_ON(fast_timeout_us > 20000);
|
2017-04-10 20:17:47 +08:00
|
|
|
|
2017-04-11 19:27:05 +08:00
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
if (fast_timeout_us && fast_timeout_us <= 20000)
|
2017-04-08 00:01:44 +08:00
|
|
|
ret = _wait_for_atomic(done, fast_timeout_us, 0);
|
2017-05-10 23:19:32 +08:00
|
|
|
if (ret && slow_timeout_ms)
|
2017-04-08 00:01:44 +08:00
|
|
|
ret = wait_for(done, slow_timeout_ms);
|
2017-04-11 19:27:05 +08:00
|
|
|
|
2017-04-08 00:01:44 +08:00
|
|
|
if (out_value)
|
|
|
|
*out_value = reg_value;
|
2017-04-11 19:27:05 +08:00
|
|
|
|
2016-06-30 22:32:44 +08:00
|
|
|
return ret;
|
|
|
|
#undef done
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-01-09 03:55:36 +08:00
|
|
|
* __intel_wait_for_register - wait until register matches expected state
|
2019-03-26 05:49:40 +08:00
|
|
|
* @uncore: the struct intel_uncore
|
2016-06-30 22:32:44 +08:00
|
|
|
* @reg: the register to read
|
|
|
|
* @mask: mask to apply to register value
|
|
|
|
* @value: expected value
|
2018-01-09 03:55:36 +08:00
|
|
|
* @fast_timeout_us: fast timeout in microsecond for atomic/tight wait
|
|
|
|
* @slow_timeout_ms: slow timeout in millisecond
|
|
|
|
* @out_value: optional placeholder to hold registry value
|
2016-06-30 22:32:44 +08:00
|
|
|
*
|
|
|
|
* This routine waits until the target register @reg contains the expected
|
2016-07-16 03:48:05 +08:00
|
|
|
* @value after applying the @mask, i.e. it waits until ::
|
|
|
|
*
|
|
|
|
* (I915_READ(reg) & mask) == value
|
|
|
|
*
|
2016-06-30 22:32:44 +08:00
|
|
|
* Otherwise, the wait will timeout after @timeout_ms milliseconds.
|
|
|
|
*
|
|
|
|
* Returns 0 if the register matches the desired condition, or -ETIMEOUT.
|
|
|
|
*/
|
2019-03-26 05:49:39 +08:00
|
|
|
int __intel_wait_for_register(struct intel_uncore *uncore,
|
|
|
|
i915_reg_t reg,
|
|
|
|
u32 mask,
|
|
|
|
u32 value,
|
|
|
|
unsigned int fast_timeout_us,
|
|
|
|
unsigned int slow_timeout_ms,
|
|
|
|
u32 *out_value)
|
|
|
|
{
|
2016-06-30 22:32:44 +08:00
|
|
|
unsigned fw =
|
2019-03-26 05:49:37 +08:00
|
|
|
intel_uncore_forcewake_for_reg(uncore, reg, FW_REG_READ);
|
2018-01-09 03:55:36 +08:00
|
|
|
u32 reg_value;
|
2016-06-30 22:32:44 +08:00
|
|
|
int ret;
|
|
|
|
|
2018-03-30 06:45:19 +08:00
|
|
|
might_sleep_if(slow_timeout_ms);
|
2017-04-11 18:13:38 +08:00
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_lock_irq(&uncore->lock);
|
|
|
|
intel_uncore_forcewake_get__locked(uncore, fw);
|
2017-04-11 18:13:38 +08:00
|
|
|
|
2019-03-26 05:49:38 +08:00
|
|
|
ret = __intel_wait_for_register_fw(uncore,
|
2017-04-11 18:13:38 +08:00
|
|
|
reg, mask, value,
|
2018-01-09 03:55:36 +08:00
|
|
|
fast_timeout_us, 0, ®_value);
|
2017-04-11 18:13:38 +08:00
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
intel_uncore_forcewake_put__locked(uncore, fw);
|
|
|
|
spin_unlock_irq(&uncore->lock);
|
2017-04-11 18:13:38 +08:00
|
|
|
|
2018-03-30 06:45:19 +08:00
|
|
|
if (ret && slow_timeout_ms)
|
2019-03-26 05:49:38 +08:00
|
|
|
ret = __wait_for(reg_value = intel_uncore_read_notrace(uncore,
|
|
|
|
reg),
|
2018-01-09 03:55:36 +08:00
|
|
|
(reg_value & mask) == value,
|
|
|
|
slow_timeout_ms * 1000, 10, 1000);
|
|
|
|
|
2019-02-05 05:16:44 +08:00
|
|
|
/* just trace the final value */
|
|
|
|
trace_i915_reg_rw(false, reg, reg_value, sizeof(reg_value), true);
|
|
|
|
|
2018-01-09 03:55:36 +08:00
|
|
|
if (out_value)
|
|
|
|
*out_value = reg_value;
|
2016-06-30 22:32:44 +08:00
|
|
|
|
|
|
|
return ret;
|
2016-03-02 22:46:24 +08:00
|
|
|
}
|
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
bool intel_uncore_unclaimed_mmio(struct intel_uncore *uncore)
|
2013-07-20 03:36:52 +08:00
|
|
|
{
|
2019-03-26 05:49:34 +08:00
|
|
|
return check_for_unclaimed_mmio(uncore);
|
2013-07-20 03:36:52 +08:00
|
|
|
}
|
2015-12-16 15:26:48 +08:00
|
|
|
|
2016-01-08 21:51:20 +08:00
|
|
|
bool
|
2019-03-26 05:49:34 +08:00
|
|
|
intel_uncore_arm_unclaimed_mmio_detection(struct intel_uncore *uncore)
|
2015-12-16 15:26:48 +08:00
|
|
|
{
|
2018-09-04 21:12:07 +08:00
|
|
|
bool ret = false;
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_lock_irq(&uncore->lock);
|
2018-09-04 21:12:07 +08:00
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
if (unlikely(uncore->unclaimed_mmio_check <= 0))
|
2018-09-04 21:12:07 +08:00
|
|
|
goto out;
|
2015-12-16 15:26:48 +08:00
|
|
|
|
2019-03-26 05:49:34 +08:00
|
|
|
if (unlikely(intel_uncore_unclaimed_mmio(uncore))) {
|
2018-09-04 19:17:32 +08:00
|
|
|
if (!i915_modparams.mmio_debug) {
|
|
|
|
DRM_DEBUG("Unclaimed register detected, "
|
|
|
|
"enabling oneshot unclaimed register reporting. "
|
|
|
|
"Please use i915.mmio_debug=N for more information.\n");
|
|
|
|
i915_modparams.mmio_debug++;
|
|
|
|
}
|
2019-03-20 02:35:39 +08:00
|
|
|
uncore->unclaimed_mmio_check--;
|
2018-09-04 21:12:07 +08:00
|
|
|
ret = true;
|
2015-12-16 15:26:48 +08:00
|
|
|
}
|
2016-01-08 21:51:20 +08:00
|
|
|
|
2018-09-04 21:12:07 +08:00
|
|
|
out:
|
2019-03-20 02:35:39 +08:00
|
|
|
spin_unlock_irq(&uncore->lock);
|
2018-09-04 21:12:07 +08:00
|
|
|
|
|
|
|
return ret;
|
2015-12-16 15:26:48 +08:00
|
|
|
}
|
2016-04-12 21:37:31 +08:00
|
|
|
|
|
|
|
static enum forcewake_domains
|
2019-03-26 05:49:37 +08:00
|
|
|
intel_uncore_forcewake_for_read(struct intel_uncore *uncore,
|
2016-04-12 21:37:31 +08:00
|
|
|
i915_reg_t reg)
|
|
|
|
{
|
2019-03-26 05:49:37 +08:00
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
2016-10-04 16:29:24 +08:00
|
|
|
u32 offset = i915_mmio_reg_offset(reg);
|
2016-04-12 21:37:31 +08:00
|
|
|
enum forcewake_domains fw_domains;
|
|
|
|
|
2019-03-26 05:49:37 +08:00
|
|
|
if (INTEL_GEN(i915) >= 11) {
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_domains = __gen11_fwtable_reg_read_fw_domains(uncore, offset);
|
2019-03-26 05:49:37 +08:00
|
|
|
} else if (HAS_FWTABLE(i915)) {
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_domains = __fwtable_reg_read_fw_domains(uncore, offset);
|
2019-03-26 05:49:37 +08:00
|
|
|
} else if (INTEL_GEN(i915) >= 6) {
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_domains = __gen6_reg_read_fw_domains(uncore, offset);
|
2016-10-04 16:29:24 +08:00
|
|
|
} else {
|
2019-03-26 05:49:33 +08:00
|
|
|
/* on devices with FW we expect to hit one of the above cases */
|
|
|
|
if (intel_uncore_has_forcewake(uncore))
|
2019-03-26 05:49:37 +08:00
|
|
|
MISSING_CASE(INTEL_GEN(i915));
|
2019-03-26 05:49:33 +08:00
|
|
|
|
2016-10-04 16:29:24 +08:00
|
|
|
fw_domains = 0;
|
2016-04-12 21:37:31 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
WARN_ON(fw_domains & ~uncore->fw_domains);
|
2016-04-12 21:37:31 +08:00
|
|
|
|
|
|
|
return fw_domains;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum forcewake_domains
|
2019-03-26 05:49:37 +08:00
|
|
|
intel_uncore_forcewake_for_write(struct intel_uncore *uncore,
|
2016-04-12 21:37:31 +08:00
|
|
|
i915_reg_t reg)
|
|
|
|
{
|
2019-03-26 05:49:37 +08:00
|
|
|
struct drm_i915_private *i915 = uncore_to_i915(uncore);
|
2016-10-04 16:29:26 +08:00
|
|
|
u32 offset = i915_mmio_reg_offset(reg);
|
2016-04-12 21:37:31 +08:00
|
|
|
enum forcewake_domains fw_domains;
|
|
|
|
|
2019-03-26 05:49:37 +08:00
|
|
|
if (INTEL_GEN(i915) >= 11) {
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_domains = __gen11_fwtable_reg_write_fw_domains(uncore, offset);
|
2019-03-26 05:49:37 +08:00
|
|
|
} else if (HAS_FWTABLE(i915) && !IS_VALLEYVIEW(i915)) {
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_domains = __fwtable_reg_write_fw_domains(uncore, offset);
|
2019-03-26 05:49:37 +08:00
|
|
|
} else if (IS_GEN(i915, 8)) {
|
2019-03-20 02:35:39 +08:00
|
|
|
fw_domains = __gen8_reg_write_fw_domains(uncore, offset);
|
2019-03-26 05:49:37 +08:00
|
|
|
} else if (IS_GEN_RANGE(i915, 6, 7)) {
|
2016-04-12 21:37:31 +08:00
|
|
|
fw_domains = FORCEWAKE_RENDER;
|
2016-10-04 16:29:26 +08:00
|
|
|
} else {
|
2019-03-26 05:49:33 +08:00
|
|
|
/* on devices with FW we expect to hit one of the above cases */
|
|
|
|
if (intel_uncore_has_forcewake(uncore))
|
2019-03-26 05:49:37 +08:00
|
|
|
MISSING_CASE(INTEL_GEN(i915));
|
2019-03-26 05:49:33 +08:00
|
|
|
|
2016-10-04 16:29:26 +08:00
|
|
|
fw_domains = 0;
|
2016-04-12 21:37:31 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 02:35:39 +08:00
|
|
|
WARN_ON(fw_domains & ~uncore->fw_domains);
|
2016-04-12 21:37:31 +08:00
|
|
|
|
|
|
|
return fw_domains;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_uncore_forcewake_for_reg - which forcewake domains are needed to access
|
|
|
|
* a register
|
2019-03-26 05:49:37 +08:00
|
|
|
* @uncore: pointer to struct intel_uncore
|
2016-04-12 21:37:31 +08:00
|
|
|
* @reg: register in question
|
|
|
|
* @op: operation bitmask of FW_REG_READ and/or FW_REG_WRITE
|
|
|
|
*
|
|
|
|
* Returns a set of forcewake domains required to be taken with for example
|
|
|
|
* intel_uncore_forcewake_get for the specified register to be accessible in the
|
|
|
|
* specified mode (read, write or read/write) with raw mmio accessors.
|
|
|
|
*
|
|
|
|
* NOTE: On Gen6 and Gen7 write forcewake domain (FORCEWAKE_RENDER) requires the
|
|
|
|
* callers to do FIFO management on their own or risk losing writes.
|
|
|
|
*/
|
|
|
|
enum forcewake_domains
|
2019-03-26 05:49:37 +08:00
|
|
|
intel_uncore_forcewake_for_reg(struct intel_uncore *uncore,
|
2016-04-12 21:37:31 +08:00
|
|
|
i915_reg_t reg, unsigned int op)
|
|
|
|
{
|
|
|
|
enum forcewake_domains fw_domains = 0;
|
|
|
|
|
|
|
|
WARN_ON(!op);
|
|
|
|
|
2019-03-26 05:49:37 +08:00
|
|
|
if (!intel_uncore_has_forcewake(uncore))
|
2016-10-04 16:29:24 +08:00
|
|
|
return 0;
|
|
|
|
|
2016-04-12 21:37:31 +08:00
|
|
|
if (op & FW_REG_READ)
|
2019-03-26 05:49:37 +08:00
|
|
|
fw_domains = intel_uncore_forcewake_for_read(uncore, reg);
|
2016-04-12 21:37:31 +08:00
|
|
|
|
|
|
|
if (op & FW_REG_WRITE)
|
2019-03-26 05:49:37 +08:00
|
|
|
fw_domains |= intel_uncore_forcewake_for_write(uncore, reg);
|
2016-04-12 21:37:31 +08:00
|
|
|
|
|
|
|
return fw_domains;
|
|
|
|
}
|
2017-02-14 01:15:33 +08:00
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
|
2017-04-12 17:21:43 +08:00
|
|
|
#include "selftests/mock_uncore.c"
|
2017-02-14 01:15:33 +08:00
|
|
|
#include "selftests/intel_uncore.c"
|
|
|
|
#endif
|