cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vlv_sideband.c (6607B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * Copyright © 2013-2021 Intel Corporation
      4 */
      5
      6#include "i915_drv.h"
      7#include "i915_iosf_mbi.h"
      8#include "i915_reg.h"
      9#include "vlv_sideband.h"
     10
     11/*
     12 * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and
     13 * VLV_VLV2_PUNIT_HAS_0.8.docx
     14 */
     15
     16/* Standard MMIO read, non-posted */
     17#define SB_MRD_NP	0x00
     18/* Standard MMIO write, non-posted */
     19#define SB_MWR_NP	0x01
     20/* Private register read, double-word addressing, non-posted */
     21#define SB_CRRDDA_NP	0x06
     22/* Private register write, double-word addressing, non-posted */
     23#define SB_CRWRDA_NP	0x07
     24
     25static void ping(void *info)
     26{
     27}
     28
     29static void __vlv_punit_get(struct drm_i915_private *i915)
     30{
     31	iosf_mbi_punit_acquire();
     32
     33	/*
     34	 * Prevent the cpu from sleeping while we use this sideband, otherwise
     35	 * the punit may cause a machine hang. The issue appears to be isolated
     36	 * with changing the power state of the CPU package while changing
     37	 * the power state via the punit, and we have only observed it
     38	 * reliably on 4-core Baytail systems suggesting the issue is in the
     39	 * power delivery mechanism and likely to be board/function
     40	 * specific. Hence we presume the workaround needs only be applied
     41	 * to the Valleyview P-unit and not all sideband communications.
     42	 */
     43	if (IS_VALLEYVIEW(i915)) {
     44		cpu_latency_qos_update_request(&i915->sb_qos, 0);
     45		on_each_cpu(ping, NULL, 1);
     46	}
     47}
     48
     49static void __vlv_punit_put(struct drm_i915_private *i915)
     50{
     51	if (IS_VALLEYVIEW(i915))
     52		cpu_latency_qos_update_request(&i915->sb_qos,
     53					       PM_QOS_DEFAULT_VALUE);
     54
     55	iosf_mbi_punit_release();
     56}
     57
     58void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports)
     59{
     60	if (ports & BIT(VLV_IOSF_SB_PUNIT))
     61		__vlv_punit_get(i915);
     62
     63	mutex_lock(&i915->sb_lock);
     64}
     65
     66void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports)
     67{
     68	mutex_unlock(&i915->sb_lock);
     69
     70	if (ports & BIT(VLV_IOSF_SB_PUNIT))
     71		__vlv_punit_put(i915);
     72}
     73
     74static int vlv_sideband_rw(struct drm_i915_private *i915,
     75			   u32 devfn, u32 port, u32 opcode,
     76			   u32 addr, u32 *val)
     77{
     78	struct intel_uncore *uncore = &i915->uncore;
     79	const bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP);
     80	int err;
     81
     82	lockdep_assert_held(&i915->sb_lock);
     83	if (port == IOSF_PORT_PUNIT)
     84		iosf_mbi_assert_punit_acquired();
     85
     86	/* Flush the previous comms, just in case it failed last time. */
     87	if (intel_wait_for_register(uncore,
     88				    VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
     89				    5)) {
     90		drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n",
     91			is_read ? "read" : "write");
     92		return -EAGAIN;
     93	}
     94
     95	preempt_disable();
     96
     97	intel_uncore_write_fw(uncore, VLV_IOSF_ADDR, addr);
     98	intel_uncore_write_fw(uncore, VLV_IOSF_DATA, is_read ? 0 : *val);
     99	intel_uncore_write_fw(uncore, VLV_IOSF_DOORBELL_REQ,
    100			      (devfn << IOSF_DEVFN_SHIFT) |
    101			      (opcode << IOSF_OPCODE_SHIFT) |
    102			      (port << IOSF_PORT_SHIFT) |
    103			      (0xf << IOSF_BYTE_ENABLES_SHIFT) |
    104			      (0 << IOSF_BAR_SHIFT) |
    105			      IOSF_SB_BUSY);
    106
    107	if (__intel_wait_for_register_fw(uncore,
    108					 VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
    109					 10000, 0, NULL) == 0) {
    110		if (is_read)
    111			*val = intel_uncore_read_fw(uncore, VLV_IOSF_DATA);
    112		err = 0;
    113	} else {
    114		drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n",
    115			is_read ? "read" : "write");
    116		err = -ETIMEDOUT;
    117	}
    118
    119	preempt_enable();
    120
    121	return err;
    122}
    123
    124u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr)
    125{
    126	u32 val = 0;
    127
    128	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
    129			SB_CRRDDA_NP, addr, &val);
    130
    131	return val;
    132}
    133
    134int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val)
    135{
    136	return vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
    137			       SB_CRWRDA_NP, addr, &val);
    138}
    139
    140u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg)
    141{
    142	u32 val = 0;
    143
    144	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
    145			SB_CRRDDA_NP, reg, &val);
    146
    147	return val;
    148}
    149
    150void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val)
    151{
    152	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
    153			SB_CRWRDA_NP, reg, &val);
    154}
    155
    156u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr)
    157{
    158	u32 val = 0;
    159
    160	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_NC,
    161			SB_CRRDDA_NP, addr, &val);
    162
    163	return val;
    164}
    165
    166u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg)
    167{
    168	u32 val = 0;
    169
    170	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port,
    171			SB_CRRDDA_NP, reg, &val);
    172
    173	return val;
    174}
    175
    176void vlv_iosf_sb_write(struct drm_i915_private *i915,
    177		       u8 port, u32 reg, u32 val)
    178{
    179	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port,
    180			SB_CRWRDA_NP, reg, &val);
    181}
    182
    183u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg)
    184{
    185	u32 val = 0;
    186
    187	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
    188			SB_CRRDDA_NP, reg, &val);
    189
    190	return val;
    191}
    192
    193void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val)
    194{
    195	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
    196			SB_CRWRDA_NP, reg, &val);
    197}
    198
    199u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg)
    200{
    201	u32 val = 0;
    202
    203	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
    204			SB_CRRDDA_NP, reg, &val);
    205
    206	return val;
    207}
    208
    209void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val)
    210{
    211	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
    212			SB_CRWRDA_NP, reg, &val);
    213}
    214
    215static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy)
    216{
    217	/*
    218	 * IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D)
    219	 * IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C)
    220	 */
    221	if (IS_CHERRYVIEW(i915))
    222		return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO;
    223	else
    224		return IOSF_PORT_DPIO;
    225}
    226
    227u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg)
    228{
    229	u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
    230	u32 val = 0;
    231
    232	vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val);
    233
    234	/*
    235	 * FIXME: There might be some registers where all 1's is a valid value,
    236	 * so ideally we should check the register offset instead...
    237	 */
    238	drm_WARN(&i915->drm, val == 0xffffffff,
    239		 "DPIO read pipe %c reg 0x%x == 0x%x\n",
    240		 pipe_name(pipe), reg, val);
    241
    242	return val;
    243}
    244
    245void vlv_dpio_write(struct drm_i915_private *i915,
    246		    enum pipe pipe, int reg, u32 val)
    247{
    248	u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
    249
    250	vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val);
    251}
    252
    253u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg)
    254{
    255	u32 val = 0;
    256
    257	vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP,
    258			reg, &val);
    259	return val;
    260}
    261
    262void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val)
    263{
    264	vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP,
    265			reg, &val);
    266}