Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0954330 authored by Siddartha Mohanadoss's avatar Siddartha Mohanadoss
Browse files

msm: mhi_dev: Add MHI driver snapshot



Modem host interface (MHI) driver is used by clients
to transfer data between host and device over PCIe
end point driver. Software clients include QTI and
software IP to setup data call and initiate data
transfer. Driver interfaces with IPA, end point PCIe
for data transfer. Add a callback for kernel clients
to receive notification once the software channel
for which the client has registered has opened/closed.

This diff is taken as of msm-3.18
'commit <18d7487> ("Merge "msm: ipa: Fix to check only
reset IPA stats can have data as NULL"")'.

Change-Id: I3dd54121d7dde6ddc6138da8d2ab9802452d4681
Signed-off-by: default avatarSiddartha Mohanadoss <smohanad@codeaurora.org>
parent 85a10b57
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -19,6 +19,18 @@ Required properties:
  - qcom,mhi-ep-msi: End point MSI number.
  - qcom,mhi-version: MHI specification version supported by the device.

Optional property:
  - qcom,use-ipa-software-channel: If property is present use IPA hardware
		accelerated path for MHI software channel data transfers
		between host and device.
  - qcom,mhi-config-iatu: If property is present map the control and data region
		between host and device using iatu.
  - qcom,mhi-interrupt: If property is present register for mhi interrupt.
  - qcom,mhi-local-pa-base: The physical base address on the device used by the
		MHI device driver to map the control and data region with the
		MHI driver on the host. This property is required if iatu
		property qcom,mhi-config-iatu is present.

Example:

	mhi: qcom,msm-mhi-dev {
+1 −1
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ config GPIO_USB_DETECT

config MSM_MHI_DEV
        tristate "Modem Device Interface Driver"
	depends on EP_PCIE && IPA
	depends on EP_PCIE && IPA3
        help
          This kernel module is used to interact with PCIe Root complex
          supporting MHI protocol. MHI is a data transmission protocol
+1 −0
Original line number Diff line number Diff line
@@ -4,3 +4,4 @@ obj-y += mhi.o
obj-y += mhi_ring.o
obj-y += mhi_uci.o
obj-y += mhi_sm.o
obj-y += mhi_dev_net.o
+1366 −312

File changed.

Preview size limit exceeded, changes collapsed.

+180 −30
Original line number Diff line number Diff line
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -274,7 +274,15 @@ struct mhi_config {
#define HW_CHANNEL_END			107
#define MHI_ENV_VALUE			2
#define MHI_MASK_ROWS_CH_EV_DB		4
#define TRB_MAX_DATA_SIZE		4096
#define TRB_MAX_DATA_SIZE		8192
#define MHI_CTRL_STATE			25
#define IPA_DMA_SYNC                    1
#define IPA_DMA_ASYNC                   0

/*maximum trasnfer completion events buffer*/
#define MAX_TR_EVENTS			50
/*maximum event requests */
#define MHI_MAX_EVT_REQ			50

/* Possible ring element types */
union mhi_dev_ring_element_type {
@@ -324,7 +332,10 @@ struct mhi_addr {
	uint64_t	host_pa;
	uintptr_t	device_pa;
	uintptr_t	device_va;
	uint32_t	size;
	size_t		size;
	dma_addr_t	phy_addr;
	void		*virt_addr;
	bool		use_ipa_dma;
};

struct mhi_interrupt_state {
@@ -349,6 +360,23 @@ enum mhi_dev_ch_operation {
	MHI_DEV_POLL,
};

enum mhi_ctrl_info {
	MHI_STATE_CONFIGURED = 0,
	MHI_STATE_CONNECTED = 1,
	MHI_STATE_DISCONNECTED = 2,
	MHI_STATE_INVAL,
};

enum mhi_dev_tr_compl_evt_type {
	SEND_EVENT_BUFFER,
	SEND_EVENT_RD_OFFSET,
};

enum mhi_dev_transfer_type {
	MHI_DEV_DMA_SYNC,
	MHI_DEV_DMA_ASYNC,
};

struct mhi_dev_channel;

struct mhi_dev_ring {
@@ -394,6 +422,7 @@ static inline void mhi_dev_ring_inc_index(struct mhi_dev_ring *ring,

enum cb_reason {
	MHI_DEV_TRE_AVAILABLE = 0,
	MHI_DEV_CTRL_UPDATE,
};

struct mhi_dev_client_cb_reason {
@@ -423,14 +452,30 @@ struct mhi_dev_client {
	uint32_t			nr_iov;
};

struct ring_cache_req {
	struct completion	*done;
	void			*context;
};

struct event_req {
	union mhi_dev_ring_element_type *tr_events;
	u32			num_events;
	dma_addr_t		dma;
	u32			dma_len;
	dma_addr_t		event_rd_dma;
	void			*context;
	enum mhi_dev_tr_compl_evt_type event_type;
	u32			event_ring;
	void			(*client_cb)(void *req);
	struct list_head	list;
};

struct mhi_dev_channel {
	struct list_head		list;
	struct list_head		clients;
	/* synchronization for changing channel state,
	 * adding/removing clients, mhi_dev callbacks, etc
	 */
	spinlock_t			lock;

	struct mhi_dev_ring		*ring;

	enum mhi_dev_channel_state	state;
@@ -440,6 +485,9 @@ struct mhi_dev_channel {
	/* client which the current inbound/outbound message is for */
	struct mhi_dev_client		*active_client;

	struct list_head		event_req_buffers;
	struct event_req		*curr_ereq;

	/* current TRE being processed */
	uint64_t			tre_loc;
	/* current TRE size */
@@ -466,6 +514,7 @@ struct mhi_dev {
	struct mhi_config		cfg;
	bool				mmio_initialized;

	spinlock_t			lock;
	/* Host control base information */
	struct mhi_host_addr		host_addr;
	struct mhi_addr			ctrl_base;
@@ -481,6 +530,7 @@ struct mhi_dev {
	struct mhi_dev_ch_ctx		*cmd_ctx_cache;
	dma_addr_t			cmd_ctx_cache_dma_handle;
	struct mhi_dev_ring		*ring;
	int				mhi_irq;
	struct mhi_dev_channel		*ch;

	int				ctrl_int;
@@ -491,6 +541,7 @@ struct mhi_dev {

	/* Scheduler work */
	struct work_struct		chdb_ctrl_work;

	struct mutex			mhi_lock;
	struct mutex			mhi_event_lock;

@@ -509,15 +560,22 @@ struct mhi_dev {
	u32				ipa_clnt_hndl[4];
	struct workqueue_struct		*ring_init_wq;
	struct work_struct		ring_init_cb_work;
	struct work_struct		re_init;

	/* EP PCIe registration */
	struct workqueue_struct		*pcie_event_wq;
	struct ep_pcie_register_event	event_reg;
	u32                             ifc_id;
	struct ep_pcie_hw               *phandle;
	struct work_struct		pcie_event;
	struct ep_pcie_msi_config	msi_cfg;

	atomic_t			write_active;
	atomic_t			is_suspended;
	atomic_t			mhi_dev_wake;
	atomic_t			re_init_done;
	struct mutex			mhi_write_test;
	u32				device_local_pa_base;
	u32				mhi_ep_msi_num;
	u32				mhi_version;
	void				*dma_cache;
@@ -535,6 +593,37 @@ struct mhi_dev {
	 * region from device used in mhi_write()
	 */
	dma_addr_t			write_dma_handle;

	/* Use IPA DMA for Software channel data transfer */
	bool				use_ipa;

	/* iATU is required to map control and data region */
	bool				config_iatu;

	/* MHI state info */
	enum mhi_ctrl_info		ctrl_info;

	/*Register for interrupt */
	bool				mhi_int;
	/* Registered client callback list */
	struct list_head		client_cb_list;
};

struct mhi_req {
	u32                             chan;
	u32                             mode;
	u32				chain;
	void                            *buf;
	dma_addr_t                      dma;
	u32                             snd_cmpl;
	void                            *context;
	size_t                          len;
	size_t                          actual_len;
	uint32_t                        rd_offset;
	struct mhi_dev_client           *client;
	struct list_head                list;
	union mhi_dev_ring_element_type *el;
	void (*client_cb)(void *req);
};

enum mhi_msg_level {
@@ -609,7 +698,9 @@ enum mhi_client_channel {
	MHI_CLIENT_CSVT_IN = 43,
	MHI_CLIENT_SMCT_OUT = 44,
	MHI_CLIENT_SMCT_IN = 45,
	MHI_MAX_SOFTWARE_CHANNELS = 46,
	MHI_CLIENT_IP_SW_4_OUT  = 46,
	MHI_CLIENT_IP_SW_4_IN  = 47,
	MHI_MAX_SOFTWARE_CHANNELS = 48,
	MHI_CLIENT_TEST_OUT = 60,
	MHI_CLIENT_TEST_IN = 61,
	MHI_CLIENT_RESERVED_1_LOWER = 62,
@@ -626,6 +717,20 @@ struct mhi_dev_iov {
	uint32_t	buf_size;
};

struct mhi_dev_client_cb_data {
	void			*user_data;
	enum mhi_client_channel	channel;
	enum mhi_ctrl_info	ctrl_info;
};

typedef void (*mhi_state_cb)(struct mhi_dev_client_cb_data *cb_dat);

struct mhi_dev_ready_cb_info {
	struct list_head		list;
	mhi_state_cb			cb;
	struct mhi_dev_client_cb_data	cb_data;
};

/**
 * mhi_dev_open_channel() - Channel open for a given client done prior
 *		to read/write.
@@ -643,24 +748,21 @@ int mhi_dev_close_channel(struct mhi_dev_client *handle_client);

/**
 * mhi_dev_read_channel() - Channel read for a given client
 * @handle_client:	Client Handle issued during mhi_dev_open_channel
 * @buf: Pointer to the buffer used by the MHI core to copy the data received
 *	 from the Host.
 * @buf_size: Size of the buffer pointer.
 * @chain : Indicate if the received data is part of chained packet.
 * @mreq:       mreq is the client argument which includes meta info
 *              like write data location, buffer len, read offset, mode,
 *              chain and client call back function which will be invoked
 *              when data read is completed.
 */
int mhi_dev_read_channel(struct mhi_dev_client *handle_client,
				void *buf, uint32_t buf_size, uint32_t *chain);
int mhi_dev_read_channel(struct mhi_req *mreq);

/**
 * mhi_dev_write_channel() - Channel write for a given software client.
 * @handle_client:	Client Handle issued during mhi_dev_open_channel
 * @buf: Pointer to the buffer used by the MHI core to copy the data from the
 *	 device to the host.
 * @buf_size: Size of the buffer pointer.
 * @wreq	wreq is the client argument which includes meta info like
 *              client handle, read data location, buffer length, mode,
 *              and client call back function which will free the packet.
 *              when data write is completed.
 */
int mhi_dev_write_channel(struct mhi_dev_client *handle_client, void *buf,
							uint32_t buf_size);
int mhi_dev_write_channel(struct mhi_req *wreq);

/**
 * mhi_dev_channel_isempty() - Checks if there is any pending TRE's to process.
@@ -733,8 +835,8 @@ int mhi_dev_process_ring_element(struct mhi_dev_ring *ring, uint32_t offset);
 * @element:	Transfer ring element to be copied to the host memory.
 */
int mhi_dev_add_element(struct mhi_dev_ring *ring,
				union mhi_dev_ring_element_type *element);

				union mhi_dev_ring_element_type *element,
				struct event_req *ereq, int evt_offset);
/**
 * mhi_transfer_device_to_host() - memcpy equivalent API to transfer data
 *		from device to the host.
@@ -742,9 +844,10 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
 * @src:	Source virtual address.
 * @len:	Numer of bytes to be transferred.
 * @mhi:	MHI dev structure.
 * @req:        mhi_req structure
 */
int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len,
				struct mhi_dev *mhi);
				struct mhi_dev *mhi, struct mhi_req *req);

/**
 * mhi_transfer_host_to_dev() - memcpy equivalent API to transfer data
@@ -753,20 +856,20 @@ int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len,
 * @src_pa:	Source physical address.
 * @len:	Numer of bytes to be transferred.
 * @mhi:	MHI dev structure.
 * @req:        mhi_req structure
 */
int mhi_transfer_host_to_device(void *device, uint64_t src_pa, uint32_t len,
				struct mhi_dev *mhi);
				struct mhi_dev *mhi, struct mhi_req *mreq);

/**
 * mhi_dev_write_to_host() - memcpy equivalent API to transfer data
 *		from device to host.
 * mhi_dev_write_to_host() - Transfer data from device to host.
 *		Based on support available, either IPA DMA or memcpy is used.
 * @host:	Host and device address details.
 * @buf:	Data buffer that needs to be written to the host.
 * @size:	Data buffer size.
 */
void mhi_dev_write_to_host(struct mhi_addr *host, void *buf, size_t size,
				struct mhi_dev *mhi);

void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *mhi_transfer,
		struct event_req *ereq, enum mhi_dev_transfer_type type);
/**
 * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
 *		from host to device.
@@ -774,7 +877,8 @@ void mhi_dev_write_to_host(struct mhi_addr *host, void *buf, size_t size,
 * @buf:	Data buffer that needs to be read from the host.
 * @size:	Data buffer size.
 */
void mhi_dev_read_from_host(struct mhi_addr *dst, dma_addr_t buf, size_t size);
void mhi_dev_read_from_host(struct mhi_dev *mhi,
				struct mhi_addr *mhi_transfer);

/**
 * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
@@ -783,6 +887,7 @@ void mhi_dev_read_from_host(struct mhi_addr *dst, dma_addr_t buf, size_t size);
 * @buf:	Data buffer that needs to be read from the host.
 * @size:	Data buffer size.
 */

void mhi_ring_set_cb(struct mhi_dev_ring *ring,
			void (*ring_cb)(struct mhi_dev *dev,
			union mhi_dev_ring_element_type *el, void *ctx));
@@ -848,6 +953,7 @@ int mhi_dev_mmio_masked_read(struct mhi_dev *dev, uint32_t offset,
 * mhi_dev_mmio_enable_ctrl_interrupt() - Enable Control interrupt.
 * @dev:	MHI device structure.
 */

int mhi_dev_mmio_enable_ctrl_interrupt(struct mhi_dev *dev);

/**
@@ -1021,8 +1127,10 @@ int mhi_dev_get_mhi_addr(struct mhi_dev *dev);
 * mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3.
 * @dev:	MHI device structure.
 * @state:	Pointer of type mhi_dev_state
 * @mhi_reset:	MHI device reset from host.
 */
int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state);
int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state,
						bool *mhi_reset);

/**
 * mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event
@@ -1121,6 +1229,48 @@ int mhi_pcie_config_db_routing(struct mhi_dev *mhi);
 */
int mhi_uci_init(void);

/**
 * mhi_dev_net_interface_init() - Initializes the mhi device network interface
 *		which exposes the virtual network interface (mhi_dev_net0).
 *		data packets will transfer between MHI host interface (mhi_swip)
 *		and mhi_dev_net interface using software path
 */
int mhi_dev_net_interface_init(void);

/**
 * mhi_dev_net_exit() - Clean up and close MHI Network interface module.
 */
void mhi_dev_net_exit(void);

/**
 * mhi_dev_notify_a7_event() - Used by PCIe driver to notify A7 MHI device
 *	interrupt after doorbell is received. Used by PCIe driver when MHI
 *	A7 interrupts are routed to PCIe instead of MHI device.
 */
void mhi_dev_notify_a7_event(struct mhi_dev *mhi);

/**
 * mhi_ctrl_state_info() - Provide MHI state info
 *		MHI_STATE=CONFIGURED - MHI device is present but not ready
 *					for data traffic.
 *		MHI_STATE=CONNECTED - MHI device is ready for data transfer.
 *		MHI_STATE=DISCONNECTED - MHI device has its pipes suspended.
 *		exposes device nodes for the supported MHI software
 *		channels.
 */
int mhi_ctrl_state_info(uint32_t *info);

/**
 * uci_ctrl_update() - Update UCI once TRE's are available for clients to
 *			consume.
 */
void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason);

/**
 * mhi_register_state_cb() - Clients can register and receive callback after
 *		MHI channel is connected or disconnected.
 */
int mhi_register_state_cb(void (*mhi_state_cb)
			(struct mhi_dev_client_cb_data *cb_data), void *data,
			enum mhi_client_channel channel);
#endif /* _MHI_H_ */
Loading