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

mmio.c (7109B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2022 Linaro Ltd.
      4 * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
      5 */
      6
      7#include <linux/bitfield.h>
      8#include <linux/io.h>
      9#include <linux/mhi_ep.h>
     10
     11#include "internal.h"
     12
     13u32 mhi_ep_mmio_read(struct mhi_ep_cntrl *mhi_cntrl, u32 offset)
     14{
     15	return readl(mhi_cntrl->mmio + offset);
     16}
     17
     18void mhi_ep_mmio_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 val)
     19{
     20	writel(val, mhi_cntrl->mmio + offset);
     21}
     22
     23void mhi_ep_mmio_masked_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 mask, u32 val)
     24{
     25	u32 regval;
     26
     27	regval = mhi_ep_mmio_read(mhi_cntrl, offset);
     28	regval &= ~mask;
     29	regval |= (val << __ffs(mask)) & mask;
     30	mhi_ep_mmio_write(mhi_cntrl, offset, regval);
     31}
     32
     33u32 mhi_ep_mmio_masked_read(struct mhi_ep_cntrl *dev, u32 offset, u32 mask)
     34{
     35	u32 regval;
     36
     37	regval = mhi_ep_mmio_read(dev, offset);
     38	regval &= mask;
     39	regval >>= __ffs(mask);
     40
     41	return regval;
     42}
     43
     44void mhi_ep_mmio_get_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state *state,
     45				bool *mhi_reset)
     46{
     47	u32 regval;
     48
     49	regval = mhi_ep_mmio_read(mhi_cntrl, EP_MHICTRL);
     50	*state = FIELD_GET(MHICTRL_MHISTATE_MASK, regval);
     51	*mhi_reset = !!FIELD_GET(MHICTRL_RESET_MASK, regval);
     52}
     53
     54static void mhi_ep_mmio_set_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id, bool enable)
     55{
     56	u32 chid_mask, chid_shift, chdb_idx, val;
     57
     58	chid_shift = ch_id % 32;
     59	chid_mask = BIT(chid_shift);
     60	chdb_idx = ch_id / 32;
     61
     62	val = enable ? 1 : 0;
     63
     64	mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CHDB_INT_MASK_n(chdb_idx), chid_mask, val);
     65
     66	/* Update the local copy of the channel mask */
     67	mhi_cntrl->chdb[chdb_idx].mask &= ~chid_mask;
     68	mhi_cntrl->chdb[chdb_idx].mask |= val << chid_shift;
     69}
     70
     71void mhi_ep_mmio_enable_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
     72{
     73	mhi_ep_mmio_set_chdb(mhi_cntrl, ch_id, true);
     74}
     75
     76void mhi_ep_mmio_disable_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
     77{
     78	mhi_ep_mmio_set_chdb(mhi_cntrl, ch_id, false);
     79}
     80
     81static void mhi_ep_mmio_set_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl, bool enable)
     82{
     83	u32 val, i;
     84
     85	val = enable ? MHI_CHDB_INT_MASK_n_EN_ALL : 0;
     86
     87	for (i = 0; i < MHI_MASK_ROWS_CH_DB; i++) {
     88		mhi_ep_mmio_write(mhi_cntrl, MHI_CHDB_INT_MASK_n(i), val);
     89		mhi_cntrl->chdb[i].mask = val;
     90	}
     91}
     92
     93void mhi_ep_mmio_enable_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
     94{
     95	mhi_ep_mmio_set_chdb_interrupts(mhi_cntrl, true);
     96}
     97
     98static void mhi_ep_mmio_mask_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
     99{
    100	mhi_ep_mmio_set_chdb_interrupts(mhi_cntrl, false);
    101}
    102
    103bool mhi_ep_mmio_read_chdb_status_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
    104{
    105	bool chdb = false;
    106	u32 i;
    107
    108	for (i = 0; i < MHI_MASK_ROWS_CH_DB; i++) {
    109		mhi_cntrl->chdb[i].status = mhi_ep_mmio_read(mhi_cntrl, MHI_CHDB_INT_STATUS_n(i));
    110		if (mhi_cntrl->chdb[i].status)
    111			chdb = true;
    112	}
    113
    114	/* Return whether a channel doorbell interrupt occurred or not */
    115	return chdb;
    116}
    117
    118static void mhi_ep_mmio_set_erdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl, bool enable)
    119{
    120	u32 val, i;
    121
    122	val = enable ? MHI_ERDB_INT_MASK_n_EN_ALL : 0;
    123
    124	for (i = 0; i < MHI_MASK_ROWS_EV_DB; i++)
    125		mhi_ep_mmio_write(mhi_cntrl, MHI_ERDB_INT_MASK_n(i), val);
    126}
    127
    128static void mhi_ep_mmio_mask_erdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
    129{
    130	mhi_ep_mmio_set_erdb_interrupts(mhi_cntrl, false);
    131}
    132
    133void mhi_ep_mmio_enable_ctrl_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
    134{
    135	mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
    136				  MHI_CTRL_MHICTRL_MASK, 1);
    137}
    138
    139void mhi_ep_mmio_disable_ctrl_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
    140{
    141	mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
    142				  MHI_CTRL_MHICTRL_MASK, 0);
    143}
    144
    145void mhi_ep_mmio_enable_cmdb_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
    146{
    147	mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
    148				  MHI_CTRL_CRDB_MASK, 1);
    149}
    150
    151void mhi_ep_mmio_disable_cmdb_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
    152{
    153	mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
    154				  MHI_CTRL_CRDB_MASK, 0);
    155}
    156
    157void mhi_ep_mmio_mask_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
    158{
    159	mhi_ep_mmio_disable_ctrl_interrupt(mhi_cntrl);
    160	mhi_ep_mmio_disable_cmdb_interrupt(mhi_cntrl);
    161	mhi_ep_mmio_mask_chdb_interrupts(mhi_cntrl);
    162	mhi_ep_mmio_mask_erdb_interrupts(mhi_cntrl);
    163}
    164
    165static void mhi_ep_mmio_clear_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
    166{
    167	u32 i;
    168
    169	for (i = 0; i < MHI_MASK_ROWS_CH_DB; i++)
    170		mhi_ep_mmio_write(mhi_cntrl, MHI_CHDB_INT_CLEAR_n(i),
    171				   MHI_CHDB_INT_CLEAR_n_CLEAR_ALL);
    172
    173	for (i = 0; i < MHI_MASK_ROWS_EV_DB; i++)
    174		mhi_ep_mmio_write(mhi_cntrl, MHI_ERDB_INT_CLEAR_n(i),
    175				   MHI_ERDB_INT_CLEAR_n_CLEAR_ALL);
    176
    177	mhi_ep_mmio_write(mhi_cntrl, MHI_CTRL_INT_CLEAR,
    178			   MHI_CTRL_INT_MMIO_WR_CLEAR |
    179			   MHI_CTRL_INT_CRDB_CLEAR |
    180			   MHI_CTRL_INT_CRDB_MHICTRL_CLEAR);
    181}
    182
    183void mhi_ep_mmio_get_chc_base(struct mhi_ep_cntrl *mhi_cntrl)
    184{
    185	u32 regval;
    186
    187	regval = mhi_ep_mmio_read(mhi_cntrl, EP_CCABAP_HIGHER);
    188	mhi_cntrl->ch_ctx_host_pa = regval;
    189	mhi_cntrl->ch_ctx_host_pa <<= 32;
    190
    191	regval = mhi_ep_mmio_read(mhi_cntrl, EP_CCABAP_LOWER);
    192	mhi_cntrl->ch_ctx_host_pa |= regval;
    193}
    194
    195void mhi_ep_mmio_get_erc_base(struct mhi_ep_cntrl *mhi_cntrl)
    196{
    197	u32 regval;
    198
    199	regval = mhi_ep_mmio_read(mhi_cntrl, EP_ECABAP_HIGHER);
    200	mhi_cntrl->ev_ctx_host_pa = regval;
    201	mhi_cntrl->ev_ctx_host_pa <<= 32;
    202
    203	regval = mhi_ep_mmio_read(mhi_cntrl, EP_ECABAP_LOWER);
    204	mhi_cntrl->ev_ctx_host_pa |= regval;
    205}
    206
    207void mhi_ep_mmio_get_crc_base(struct mhi_ep_cntrl *mhi_cntrl)
    208{
    209	u32 regval;
    210
    211	regval = mhi_ep_mmio_read(mhi_cntrl, EP_CRCBAP_HIGHER);
    212	mhi_cntrl->cmd_ctx_host_pa = regval;
    213	mhi_cntrl->cmd_ctx_host_pa <<= 32;
    214
    215	regval = mhi_ep_mmio_read(mhi_cntrl, EP_CRCBAP_LOWER);
    216	mhi_cntrl->cmd_ctx_host_pa |= regval;
    217}
    218
    219u64 mhi_ep_mmio_get_db(struct mhi_ep_ring *ring)
    220{
    221	struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
    222	u64 db_offset;
    223	u32 regval;
    224
    225	regval = mhi_ep_mmio_read(mhi_cntrl, ring->db_offset_h);
    226	db_offset = regval;
    227	db_offset <<= 32;
    228
    229	regval = mhi_ep_mmio_read(mhi_cntrl, ring->db_offset_l);
    230	db_offset |= regval;
    231
    232	return db_offset;
    233}
    234
    235void mhi_ep_mmio_set_env(struct mhi_ep_cntrl *mhi_cntrl, u32 value)
    236{
    237	mhi_ep_mmio_write(mhi_cntrl, EP_BHI_EXECENV, value);
    238}
    239
    240void mhi_ep_mmio_clear_reset(struct mhi_ep_cntrl *mhi_cntrl)
    241{
    242	mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHICTRL, MHICTRL_RESET_MASK, 0);
    243}
    244
    245void mhi_ep_mmio_reset(struct mhi_ep_cntrl *mhi_cntrl)
    246{
    247	mhi_ep_mmio_write(mhi_cntrl, EP_MHICTRL, 0);
    248	mhi_ep_mmio_write(mhi_cntrl, EP_MHISTATUS, 0);
    249	mhi_ep_mmio_clear_interrupts(mhi_cntrl);
    250}
    251
    252void mhi_ep_mmio_init(struct mhi_ep_cntrl *mhi_cntrl)
    253{
    254	u32 regval;
    255
    256	mhi_cntrl->chdb_offset = mhi_ep_mmio_read(mhi_cntrl, EP_CHDBOFF);
    257	mhi_cntrl->erdb_offset = mhi_ep_mmio_read(mhi_cntrl, EP_ERDBOFF);
    258
    259	regval = mhi_ep_mmio_read(mhi_cntrl, EP_MHICFG);
    260	mhi_cntrl->event_rings = FIELD_GET(MHICFG_NER_MASK, regval);
    261	mhi_cntrl->hw_event_rings = FIELD_GET(MHICFG_NHWER_MASK, regval);
    262
    263	mhi_ep_mmio_reset(mhi_cntrl);
    264}
    265
    266void mhi_ep_mmio_update_ner(struct mhi_ep_cntrl *mhi_cntrl)
    267{
    268	u32 regval;
    269
    270	regval = mhi_ep_mmio_read(mhi_cntrl, EP_MHICFG);
    271	mhi_cntrl->event_rings = FIELD_GET(MHICFG_NER_MASK, regval);
    272	mhi_cntrl->hw_event_rings = FIELD_GET(MHICFG_NHWER_MASK, regval);
    273}