lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 24 Jan 2020 15:51:12 -0700
From:   Jeffrey Hugo <jhugo@...eaurora.org>
To:     Manivannan Sadhasivam <manivannan.sadhasivam@...aro.org>,
        gregkh@...uxfoundation.org, arnd@...db.de
Cc:     smohanad@...eaurora.org, kvalo@...eaurora.org,
        bjorn.andersson@...aro.org, hemantk@...eaurora.org,
        linux-arm-msm@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 05/16] bus: mhi: core: Add support for ringing
 channel/event ring doorbells

On 1/23/2020 4:18 AM, Manivannan Sadhasivam wrote:
> This commit adds support for ringing channel and event ring doorbells
> by MHI host. The MHI host can use the channel and event ring doorbells
> for notifying the client device about processing transfer and event
> rings which it has queued using MMIO registers.
> 
> This is based on the patch submitted by Sujeev Dias:
> https://lkml.org/lkml/2018/7/9/989
> 
> Signed-off-by: Sujeev Dias <sdias@...eaurora.org>
> Signed-off-by: Siddartha Mohanadoss <smohanad@...eaurora.org>
> [mani: splitted from pm patch and cleaned up for upstream]
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@...aro.org>
> ---
>   drivers/bus/mhi/core/init.c     | 140 ++++++++++++++++
>   drivers/bus/mhi/core/internal.h | 275 ++++++++++++++++++++++++++++++++
>   drivers/bus/mhi/core/main.c     | 118 ++++++++++++++
>   include/linux/mhi.h             |   5 +
>   4 files changed, 538 insertions(+)
> 
> diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c
> index 60dcf2ad3a5f..588166b588b4 100644
> --- a/drivers/bus/mhi/core/init.c
> +++ b/drivers/bus/mhi/core/init.c
> @@ -19,6 +19,136 @@
>   #include <linux/wait.h>
>   #include "internal.h"
>   
> +int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
> +{
> +	u32 val;
> +	int i, ret;
> +	struct mhi_chan *mhi_chan;
> +	struct mhi_event *mhi_event;
> +	void __iomem *base = mhi_cntrl->regs;
> +	struct {
> +		u32 offset;
> +		u32 mask;
> +		u32 shift;
> +		u32 val;
> +	} reg_info[] = {
> +		{
> +			CCABAP_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->mhi_ctxt->chan_ctxt_addr),
> +		},
> +		{
> +			CCABAP_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->mhi_ctxt->chan_ctxt_addr),
> +		},
> +		{
> +			ECABAP_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->mhi_ctxt->er_ctxt_addr),
> +		},
> +		{
> +			ECABAP_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->mhi_ctxt->er_ctxt_addr),
> +		},
> +		{
> +			CRCBAP_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->mhi_ctxt->cmd_ctxt_addr),
> +		},
> +		{
> +			CRCBAP_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->mhi_ctxt->cmd_ctxt_addr),
> +		},
> +		{
> +			MHICFG, MHICFG_NER_MASK, MHICFG_NER_SHIFT,
> +			mhi_cntrl->total_ev_rings,
> +		},
> +		{
> +			MHICFG, MHICFG_NHWER_MASK, MHICFG_NHWER_SHIFT,
> +			mhi_cntrl->hw_ev_rings,
> +		},
> +		{
> +			MHICTRLBASE_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->iova_start),
> +		},
> +		{
> +			MHICTRLBASE_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->iova_start),
> +		},
> +		{
> +			MHIDATABASE_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->iova_start),
> +		},
> +		{
> +			MHIDATABASE_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->iova_start),
> +		},
> +		{
> +			MHICTRLLIMIT_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->iova_stop),
> +		},
> +		{
> +			MHICTRLLIMIT_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->iova_stop),
> +		},
> +		{
> +			MHIDATALIMIT_HIGHER, U32_MAX, 0,
> +			upper_32_bits(mhi_cntrl->iova_stop),
> +		},
> +		{
> +			MHIDATALIMIT_LOWER, U32_MAX, 0,
> +			lower_32_bits(mhi_cntrl->iova_stop),
> +		},
> +		{ 0, 0, 0 }
> +	};
> +
> +	dev_dbg(mhi_cntrl->dev, "Initializing MHI registers\n");
> +
> +	/* Read channel db offset */
> +	ret = mhi_read_reg_field(mhi_cntrl, base, CHDBOFF, CHDBOFF_CHDBOFF_MASK,
> +				 CHDBOFF_CHDBOFF_SHIFT, &val);
> +	if (ret) {
> +		dev_err(mhi_cntrl->dev, "Unable to read CHDBOFF register\n");
> +		return -EIO;
> +	}
> +
> +	/* Setup wake db */
> +	mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB);
> +	mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 4, 0);
> +	mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0);
> +	mhi_cntrl->wake_set = false;
> +
> +	/* Setup channel db address for each channel in tre_ring */
> +	mhi_chan = mhi_cntrl->mhi_chan;
> +	for (i = 0; i < mhi_cntrl->max_chan; i++, val += 8, mhi_chan++)
> +		mhi_chan->tre_ring.db_addr = base + val;
> +
> +	/* Read event ring db offset */
> +	ret = mhi_read_reg_field(mhi_cntrl, base, ERDBOFF, ERDBOFF_ERDBOFF_MASK,
> +				 ERDBOFF_ERDBOFF_SHIFT, &val);
> +	if (ret) {
> +		dev_err(mhi_cntrl->dev, "Unable to read ERDBOFF register\n");
> +		return -EIO;
> +	}
> +
> +	/* Setup event db address for each ev_ring */
> +	mhi_event = mhi_cntrl->mhi_event;
> +	for (i = 0; i < mhi_cntrl->total_ev_rings; i++, val += 8, mhi_event++) {
> +		if (mhi_event->offload_ev)
> +			continue;
> +
> +		mhi_event->ring.db_addr = base + val;
> +	}
> +
> +	/* Setup DB register for primary CMD rings */
> +	mhi_cntrl->mhi_cmd[PRIMARY_CMD_RING].ring.db_addr = base + CRDB_LOWER;
> +
> +	/* Write to MMIO registers */
> +	for (i = 0; reg_info[i].offset; i++)
> +		mhi_write_reg_field(mhi_cntrl, base, reg_info[i].offset,
> +				    reg_info[i].mask, reg_info[i].shift,
> +				    reg_info[i].val);
> +
> +	return 0;
> +}
> +
>   static int parse_ev_cfg(struct mhi_controller *mhi_cntrl,
>   			struct mhi_controller_config *config)
>   {
> @@ -63,6 +193,11 @@ static int parse_ev_cfg(struct mhi_controller *mhi_cntrl,
>   		if (MHI_INVALID_BRSTMODE(mhi_event->db_cfg.brstmode))
>   			goto error_ev_cfg;
>   
> +		if (mhi_event->db_cfg.brstmode == MHI_DB_BRST_ENABLE)
> +			mhi_event->db_cfg.process_db = mhi_db_brstmode;
> +		else
> +			mhi_event->db_cfg.process_db = mhi_db_brstmode_disable;
> +
>   		mhi_event->data_type = event_cfg->data_type;
>   
>   		mhi_event->hw_ring = event_cfg->hardware_event;
> @@ -194,6 +329,11 @@ static int parse_ch_cfg(struct mhi_controller *mhi_cntrl,
>   			}
>   		}
>   
> +		if (mhi_chan->db_cfg.brstmode == MHI_DB_BRST_ENABLE)
> +			mhi_chan->db_cfg.process_db = mhi_db_brstmode;
> +		else
> +			mhi_chan->db_cfg.process_db = mhi_db_brstmode_disable;
> +
>   		mhi_chan->configured = true;
>   
>   		if (mhi_chan->lpm_notify)
> diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h
> index ea7f1d7b0129..a4d10916984a 100644
> --- a/drivers/bus/mhi/core/internal.h
> +++ b/drivers/bus/mhi/core/internal.h
> @@ -9,6 +9,255 @@
>   
>   extern struct bus_type mhi_bus_type;
>   
> +/* MHI MMIO register mapping */
> +#define PCI_INVALID_READ(val) (val == U32_MAX)
> +
> +#define MHIREGLEN (0x0)
> +#define MHIREGLEN_MHIREGLEN_MASK (0xFFFFFFFF)
> +#define MHIREGLEN_MHIREGLEN_SHIFT (0)
> +
> +#define MHIVER (0x8)
> +#define MHIVER_MHIVER_MASK (0xFFFFFFFF)
> +#define MHIVER_MHIVER_SHIFT (0)
> +
> +#define MHICFG (0x10)
> +#define MHICFG_NHWER_MASK (0xFF000000)
> +#define MHICFG_NHWER_SHIFT (24)
> +#define MHICFG_NER_MASK (0xFF0000)
> +#define MHICFG_NER_SHIFT (16)
> +#define MHICFG_NHWCH_MASK (0xFF00)
> +#define MHICFG_NHWCH_SHIFT (8)
> +#define MHICFG_NCH_MASK (0xFF)
> +#define MHICFG_NCH_SHIFT (0)
> +
> +#define CHDBOFF (0x18)
> +#define CHDBOFF_CHDBOFF_MASK (0xFFFFFFFF)
> +#define CHDBOFF_CHDBOFF_SHIFT (0)
> +
> +#define ERDBOFF (0x20)
> +#define ERDBOFF_ERDBOFF_MASK (0xFFFFFFFF)
> +#define ERDBOFF_ERDBOFF_SHIFT (0)
> +
> +#define BHIOFF (0x28)
> +#define BHIOFF_BHIOFF_MASK (0xFFFFFFFF)
> +#define BHIOFF_BHIOFF_SHIFT (0)
> +
> +#define BHIEOFF (0x2C)
> +#define BHIEOFF_BHIEOFF_MASK (0xFFFFFFFF)
> +#define BHIEOFF_BHIEOFF_SHIFT (0)
> +
> +#define DEBUGOFF (0x30)
> +#define DEBUGOFF_DEBUGOFF_MASK (0xFFFFFFFF)
> +#define DEBUGOFF_DEBUGOFF_SHIFT (0)
> +
> +#define MHICTRL (0x38)
> +#define MHICTRL_MHISTATE_MASK (0x0000FF00)
> +#define MHICTRL_MHISTATE_SHIFT (8)
> +#define MHICTRL_RESET_MASK (0x2)
> +#define MHICTRL_RESET_SHIFT (1)
> +
> +#define MHISTATUS (0x48)
> +#define MHISTATUS_MHISTATE_MASK (0x0000FF00)
> +#define MHISTATUS_MHISTATE_SHIFT (8)
> +#define MHISTATUS_SYSERR_MASK (0x4)
> +#define MHISTATUS_SYSERR_SHIFT (2)
> +#define MHISTATUS_READY_MASK (0x1)
> +#define MHISTATUS_READY_SHIFT (0)
> +
> +#define CCABAP_LOWER (0x58)
> +#define CCABAP_LOWER_CCABAP_LOWER_MASK (0xFFFFFFFF)
> +#define CCABAP_LOWER_CCABAP_LOWER_SHIFT (0)
> +
> +#define CCABAP_HIGHER (0x5C)
> +#define CCABAP_HIGHER_CCABAP_HIGHER_MASK (0xFFFFFFFF)
> +#define CCABAP_HIGHER_CCABAP_HIGHER_SHIFT (0)
> +
> +#define ECABAP_LOWER (0x60)
> +#define ECABAP_LOWER_ECABAP_LOWER_MASK (0xFFFFFFFF)
> +#define ECABAP_LOWER_ECABAP_LOWER_SHIFT (0)
> +
> +#define ECABAP_HIGHER (0x64)
> +#define ECABAP_HIGHER_ECABAP_HIGHER_MASK (0xFFFFFFFF)
> +#define ECABAP_HIGHER_ECABAP_HIGHER_SHIFT (0)
> +
> +#define CRCBAP_LOWER (0x68)
> +#define CRCBAP_LOWER_CRCBAP_LOWER_MASK (0xFFFFFFFF)
> +#define CRCBAP_LOWER_CRCBAP_LOWER_SHIFT (0)
> +
> +#define CRCBAP_HIGHER (0x6C)
> +#define CRCBAP_HIGHER_CRCBAP_HIGHER_MASK (0xFFFFFFFF)
> +#define CRCBAP_HIGHER_CRCBAP_HIGHER_SHIFT (0)
> +
> +#define CRDB_LOWER (0x70)
> +#define CRDB_LOWER_CRDB_LOWER_MASK (0xFFFFFFFF)
> +#define CRDB_LOWER_CRDB_LOWER_SHIFT (0)
> +
> +#define CRDB_HIGHER (0x74)
> +#define CRDB_HIGHER_CRDB_HIGHER_MASK (0xFFFFFFFF)
> +#define CRDB_HIGHER_CRDB_HIGHER_SHIFT (0)
> +
> +#define MHICTRLBASE_LOWER (0x80)
> +#define MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_MASK (0xFFFFFFFF)
> +#define MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_SHIFT (0)
> +
> +#define MHICTRLBASE_HIGHER (0x84)
> +#define MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_MASK (0xFFFFFFFF)
> +#define MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_SHIFT (0)
> +
> +#define MHICTRLLIMIT_LOWER (0x88)
> +#define MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_MASK (0xFFFFFFFF)
> +#define MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_SHIFT (0)
> +
> +#define MHICTRLLIMIT_HIGHER (0x8C)
> +#define MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_MASK (0xFFFFFFFF)
> +#define MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_SHIFT (0)
> +
> +#define MHIDATABASE_LOWER (0x98)
> +#define MHIDATABASE_LOWER_MHIDATABASE_LOWER_MASK (0xFFFFFFFF)
> +#define MHIDATABASE_LOWER_MHIDATABASE_LOWER_SHIFT (0)
> +
> +#define MHIDATABASE_HIGHER (0x9C)
> +#define MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_MASK (0xFFFFFFFF)
> +#define MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_SHIFT (0)
> +
> +#define MHIDATALIMIT_LOWER (0xA0)
> +#define MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_MASK (0xFFFFFFFF)
> +#define MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_SHIFT (0)
> +
> +#define MHIDATALIMIT_HIGHER (0xA4)
> +#define MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_MASK (0xFFFFFFFF)
> +#define MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_SHIFT (0)
> +
> +/* Host request register */
> +#define MHI_SOC_RESET_REQ_OFFSET (0xB0)
> +#define MHI_SOC_RESET_REQ BIT(0)
> +
> +/* MHI BHI offfsets */
> +#define BHI_BHIVERSION_MINOR (0x00)
> +#define BHI_BHIVERSION_MAJOR (0x04)
> +#define BHI_IMGADDR_LOW (0x08)
> +#define BHI_IMGADDR_HIGH (0x0C)
> +#define BHI_IMGSIZE (0x10)
> +#define BHI_RSVD1 (0x14)
> +#define BHI_IMGTXDB (0x18)
> +#define BHI_TXDB_SEQNUM_BMSK (0x3FFFFFFF)
> +#define BHI_TXDB_SEQNUM_SHFT (0)
> +#define BHI_RSVD2 (0x1C)
> +#define BHI_INTVEC (0x20)
> +#define BHI_RSVD3 (0x24)
> +#define BHI_EXECENV (0x28)
> +#define BHI_STATUS (0x2C)
> +#define BHI_ERRCODE (0x30)
> +#define BHI_ERRDBG1 (0x34)
> +#define BHI_ERRDBG2 (0x38)
> +#define BHI_ERRDBG3 (0x3C)
> +#define BHI_SERIALNU (0x40)
> +#define BHI_SBLANTIROLLVER (0x44)
> +#define BHI_NUMSEG (0x48)
> +#define BHI_MSMHWID(n) (0x4C + (0x4 * n))
> +#define BHI_OEMPKHASH(n) (0x64 + (0x4 * n))
> +#define BHI_RSVD5 (0xC4)
> +#define BHI_STATUS_MASK (0xC0000000)
> +#define BHI_STATUS_SHIFT (30)
> +#define BHI_STATUS_ERROR (3)
> +#define BHI_STATUS_SUCCESS (2)
> +#define BHI_STATUS_RESET (0)
> +
> +/* MHI BHIE offsets */
> +#define BHIE_MSMSOCID_OFFS (0x0000)
> +#define BHIE_TXVECADDR_LOW_OFFS (0x002C)
> +#define BHIE_TXVECADDR_HIGH_OFFS (0x0030)
> +#define BHIE_TXVECSIZE_OFFS (0x0034)
> +#define BHIE_TXVECDB_OFFS (0x003C)
> +#define BHIE_TXVECDB_SEQNUM_BMSK (0x3FFFFFFF)
> +#define BHIE_TXVECDB_SEQNUM_SHFT (0)
> +#define BHIE_TXVECSTATUS_OFFS (0x0044)
> +#define BHIE_TXVECSTATUS_SEQNUM_BMSK (0x3FFFFFFF)
> +#define BHIE_TXVECSTATUS_SEQNUM_SHFT (0)
> +#define BHIE_TXVECSTATUS_STATUS_BMSK (0xC0000000)
> +#define BHIE_TXVECSTATUS_STATUS_SHFT (30)
> +#define BHIE_TXVECSTATUS_STATUS_RESET (0x00)
> +#define BHIE_TXVECSTATUS_STATUS_XFER_COMPL (0x02)
> +#define BHIE_TXVECSTATUS_STATUS_ERROR (0x03)
> +#define BHIE_RXVECADDR_LOW_OFFS (0x0060)
> +#define BHIE_RXVECADDR_HIGH_OFFS (0x0064)
> +#define BHIE_RXVECSIZE_OFFS (0x0068)
> +#define BHIE_RXVECDB_OFFS (0x0070)
> +#define BHIE_RXVECDB_SEQNUM_BMSK (0x3FFFFFFF)
> +#define BHIE_RXVECDB_SEQNUM_SHFT (0)
> +#define BHIE_RXVECSTATUS_OFFS (0x0078)
> +#define BHIE_RXVECSTATUS_SEQNUM_BMSK (0x3FFFFFFF)
> +#define BHIE_RXVECSTATUS_SEQNUM_SHFT (0)
> +#define BHIE_RXVECSTATUS_STATUS_BMSK (0xC0000000)
> +#define BHIE_RXVECSTATUS_STATUS_SHFT (30)
> +#define BHIE_RXVECSTATUS_STATUS_RESET (0x00)
> +#define BHIE_RXVECSTATUS_STATUS_XFER_COMPL (0x02)
> +#define BHIE_RXVECSTATUS_STATUS_ERROR (0x03)
> +
> +struct mhi_event_ctxt {
> +	u32 reserved : 8;
> +	u32 intmodc : 8;
> +	u32 intmodt : 16;
> +	u32 ertype;
> +	u32 msivec;
> +
> +	u64 rbase __packed __aligned(4);
> +	u64 rlen __packed __aligned(4);
> +	u64 rp __packed __aligned(4);
> +	u64 wp __packed __aligned(4);
> +};

This is the struct that is shared with the device, correct?  Surely it 
needs to be packed then?  Seems like you'd expect some padding between 
msivec and rbase on a 64-bit system otherwise, which is probably not 
intended.

Also I strongly dislike bitfields in structures which are shared with 
another system since the C specification doesn't define how they are 
implemented, therefore you can run into issues where different compilers 
decide to implement the actual backing memory differently.  I know its 
less convinent, but I would prefer the use of bitmasks for these fields.

Same comments for the next two structs following this.

> +
> +struct mhi_chan_ctxt {
> +	u32 chstate : 8;
> +	u32 brstmode : 2;
> +	u32 pollcfg : 6;
> +	u32 reserved : 16;
> +	u32 chtype;
> +	u32 erindex;
> +
> +	u64 rbase __packed __aligned(4);
> +	u64 rlen __packed __aligned(4);
> +	u64 rp __packed __aligned(4);
> +	u64 wp __packed __aligned(4);
> +};
> +
> +struct mhi_cmd_ctxt {
> +	u32 reserved0;
> +	u32 reserved1;
> +	u32 reserved2;
> +
> +	u64 rbase __packed __aligned(4);
> +	u64 rlen __packed __aligned(4);
> +	u64 rp __packed __aligned(4);
> +	u64 wp __packed __aligned(4);
> +};
> +
> +struct mhi_ctxt {
> +	struct mhi_event_ctxt *er_ctxt;
> +	struct mhi_chan_ctxt *chan_ctxt;
> +	struct mhi_cmd_ctxt *cmd_ctxt;
> +	dma_addr_t er_ctxt_addr;
> +	dma_addr_t chan_ctxt_addr;
> +	dma_addr_t cmd_ctxt_addr;
> +};
> +
> +struct mhi_tre {
> +	u64 ptr;
> +	u32 dword[2];
> +};
> +
> +struct bhi_vec_entry {
> +	u64 dma_addr;
> +	u64 size;
> +};
> +
> +enum mhi_cmd_type {
> +	MHI_CMD_NOP = 1,
> +	MHI_CMD_RESET_CHAN = 16,
> +	MHI_CMD_STOP_CHAN = 17,
> +	MHI_CMD_START_CHAN = 18,
> +};
> +
>   /* MHI transfer completion events */
>   enum mhi_ev_ccs {
>   	MHI_EV_CC_INVALID = 0x0,
> @@ -37,6 +286,7 @@ enum mhi_ch_state {
>   #define NR_OF_CMD_RINGS			1
>   #define CMD_EL_PER_RING			128
>   #define PRIMARY_CMD_RING		0
> +#define MHI_DEV_WAKE_DB			127
>   #define MHI_MAX_MTU			0xffff
>   
>   enum mhi_er_type {
> @@ -167,4 +417,29 @@ static inline void mhi_dealloc_device(struct mhi_controller *mhi_cntrl,
>   int mhi_destroy_device(struct device *dev, void *data);
>   void mhi_create_devices(struct mhi_controller *mhi_cntrl);
>   
> +/* Register access methods */
> +void mhi_db_brstmode(struct mhi_controller *mhi_cntrl, struct db_cfg *db_cfg,
> +		     void __iomem *db_addr, dma_addr_t db_val);
> +void mhi_db_brstmode_disable(struct mhi_controller *mhi_cntrl,
> +			     struct db_cfg *db_mode, void __iomem *db_addr,
> +			     dma_addr_t db_val);
> +int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
> +			      void __iomem *base, u32 offset, u32 *out);
> +int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
> +				    void __iomem *base, u32 offset, u32 mask,
> +				    u32 shift, u32 *out);
> +void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
> +		   u32 offset, u32 val);
> +void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,
> +			 u32 offset, u32 mask, u32 shift, u32 val);
> +void mhi_ring_er_db(struct mhi_event *mhi_event);
> +void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr,
> +		  dma_addr_t db_val);
> +void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd);
> +void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
> +		      struct mhi_chan *mhi_chan);
> +
> +/* Initialization methods */
> +int mhi_init_mmio(struct mhi_controller *mhi_cntrl);
> +
>   #endif /* _MHI_INT_H */
> diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c
> index 216fd8691140..134ef9b2cc78 100644
> --- a/drivers/bus/mhi/core/main.c
> +++ b/drivers/bus/mhi/core/main.c
> @@ -17,6 +17,124 @@
>   #include <linux/slab.h>
>   #include "internal.h"
>   
> +int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
> +			      void __iomem *base, u32 offset, u32 *out)
> +{
> +	u32 tmp = readl_relaxed(base + offset);
> +
> +	/* If there is any unexpected value, query the link status */
> +	if (PCI_INVALID_READ(tmp) &&
> +	    mhi_cntrl->link_status(mhi_cntrl, mhi_cntrl->priv_data))
> +		return -EIO;
> +
> +	*out = tmp;
> +
> +	return 0;
> +}
> +
> +int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
> +				    void __iomem *base, u32 offset,
> +				    u32 mask, u32 shift, u32 *out)
> +{
> +	u32 tmp;
> +	int ret;
> +
> +	ret = mhi_read_reg(mhi_cntrl, base, offset, &tmp);
> +	if (ret)
> +		return ret;
> +
> +	*out = (tmp & mask) >> shift;
> +
> +	return 0;
> +}
> +
> +void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
> +		   u32 offset, u32 val)
> +{
> +	writel_relaxed(val, base + offset);
> +}
> +
> +void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,
> +			 u32 offset, u32 mask, u32 shift, u32 val)
> +{
> +	int ret;
> +	u32 tmp;
> +
> +	ret = mhi_read_reg(mhi_cntrl, base, offset, &tmp);
> +	if (ret)
> +		return;
> +
> +	tmp &= ~mask;
> +	tmp |= (val << shift);
> +	mhi_write_reg(mhi_cntrl, base, offset, tmp);
> +}
> +
> +void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr,
> +		  dma_addr_t db_val)
> +{
> +	mhi_write_reg(mhi_cntrl, db_addr, 4, upper_32_bits(db_val));
> +	mhi_write_reg(mhi_cntrl, db_addr, 0, lower_32_bits(db_val));
> +}
> +
> +void mhi_db_brstmode(struct mhi_controller *mhi_cntrl,
> +		     struct db_cfg *db_cfg,
> +		     void __iomem *db_addr,
> +		     dma_addr_t db_val)
> +{
> +	if (db_cfg->db_mode) {
> +		db_cfg->db_val = db_val;
> +		mhi_write_db(mhi_cntrl, db_addr, db_val);
> +		db_cfg->db_mode = 0;
> +	}
> +}
> +
> +void mhi_db_brstmode_disable(struct mhi_controller *mhi_cntrl,
> +			     struct db_cfg *db_cfg,
> +			     void __iomem *db_addr,
> +			     dma_addr_t db_val)
> +{
> +	db_cfg->db_val = db_val;
> +	mhi_write_db(mhi_cntrl, db_addr, db_val);
> +}
> +
> +void mhi_ring_er_db(struct mhi_event *mhi_event)
> +{
> +	struct mhi_ring *ring = &mhi_event->ring;
> +
> +	mhi_event->db_cfg.process_db(mhi_event->mhi_cntrl, &mhi_event->db_cfg,
> +				     ring->db_addr, *ring->ctxt_wp);
> +}
> +
> +void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd)
> +{
> +	dma_addr_t db;
> +	struct mhi_ring *ring = &mhi_cmd->ring;
> +
> +	db = ring->iommu_base + (ring->wp - ring->base);
> +	*ring->ctxt_wp = db;
> +	mhi_write_db(mhi_cntrl, ring->db_addr, db);
> +}
> +
> +void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
> +		      struct mhi_chan *mhi_chan)
> +{
> +	struct mhi_ring *ring = &mhi_chan->tre_ring;
> +	dma_addr_t db;
> +
> +	db = ring->iommu_base + (ring->wp - ring->base);
> +	*ring->ctxt_wp = db;
> +	mhi_chan->db_cfg.process_db(mhi_cntrl, &mhi_chan->db_cfg,
> +				    ring->db_addr, db);
> +}
> +
> +enum mhi_ee_type mhi_get_exec_env(struct mhi_controller *mhi_cntrl)
> +{
> +	u32 exec;
> +	int ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_EXECENV, &exec);
> +
> +	return (ret) ? MHI_EE_MAX : exec;
> +}
> +
>   int mhi_destroy_device(struct device *dev, void *data)
>   {
>   	struct mhi_device *mhi_dev;
> diff --git a/include/linux/mhi.h b/include/linux/mhi.h
> index cb6ddd23463c..d08f212cdfd0 100644
> --- a/include/linux/mhi.h
> +++ b/include/linux/mhi.h
> @@ -246,6 +246,8 @@ struct mhi_controller_config {
>    * @dev_id: Device ID of the controller
>    * @bus_id: Physical bus instance used by the controller
>    * @regs: Base address of MHI MMIO register space
> + * @bhi: Points to base of MHI BHI register space
> + * @wake_db: MHI WAKE doorbell register address
>    * @iova_start: IOMMU starting address for data
>    * @iova_stop: IOMMU stop address for data
>    * @fw_image: Firmware image name for normal booting
> @@ -306,6 +308,9 @@ struct mhi_controller {
>   	u32 dev_id;
>   	u32 bus_id;
>   	void __iomem *regs;
> +	void __iomem *bhi;
> +	void __iomem *wake_db;
> +
>   	dma_addr_t iova_start;
>   	dma_addr_t iova_stop;
>   	const char *fw_image;
> 


-- 
Jeffrey Hugo
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ