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

Commit 1e266f61 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mhi: core: add support for priority based event processing"

parents 6f55033e 65d8df76
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -88,12 +88,13 @@ Main node properties:
  Usage: required
  Value type: Array of <u32>
  Definition: mhi event ring configuration parameters for platform
	defined as below <A B C D E>:
	defined as below <A B C D E F>:
		A = maximum event descriptors
		B = MSI associated with event
		C = interrupt moderation (see MHI specification)
		D = Associated channel
		E = flags defined by mhi_macros.h GET_EV_PROPS
		E = priority of the event ring. 0 being the highest.
		F = flags defined by mhi_macros.h GET_EV_PROPS

- qcom,mhi-address-window
  Usage: required
@@ -120,6 +121,13 @@ Main node properties:
  Value type: <u32>
  Definition: Segment size in bytes for each segment in bytes.

- qcom,mhi-bb-required
  Usage: optional
  Value type: bool
  Definition: Determine whether MHI device require bounce buffer
	during active transfer.  If true, during channel open host
	will pre-allocate transfer buffers.

========
Example:
========
@@ -140,5 +148,5 @@ mhi: qcom,mhi {
			<100 512 1200000000 1200000000>;
	mhi-event-rings = <1>;
	mhi-chan-cfg-102 = <0x66 0x80 0x5 0x62>;
	mhi-event-cfg-0 = <0x80 0x0 0x0 0x0 0x11>;
	mhi-event-cfg-0 = <0x80 0x0 0x0 0x0 0 1 0x11>;
};
+24 −14
Original line number Diff line number Diff line
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2017, 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
@@ -348,6 +348,11 @@ struct mhi_ring {
	u32 msi_disable_cntr;
	u32 msi_enable_cntr;
	spinlock_t ring_lock;
	struct dma_pool *dma_pool;
	struct tasklet_struct ev_task;
	struct work_struct ev_worker;
	struct mhi_device_ctxt *mhi_dev_ctxt;
	int index;
};

enum MHI_CMD_STATUS {
@@ -446,9 +451,12 @@ struct mhi_state_work_queue {

struct mhi_buf_info {
	dma_addr_t bb_p_addr;
	dma_addr_t pre_alloc_p_addr;
	void *bb_v_addr;
	void *pre_alloc_v_addr;
	void *client_buf;
	size_t buf_len;
	size_t pre_alloc_len;
	size_t filled_size;
	enum dma_data_direction dir;
	int bb_active;
@@ -465,7 +473,6 @@ struct mhi_counters {
	u32 bb_used[MHI_MAX_CHANNELS];
	atomic_t device_wake;
	atomic_t outbound_acks;
	atomic_t events_pending;
	u32 *msi_counter;
	u32 mhi_reset_cntr;
	u32 link_down_cntr;
@@ -475,15 +482,10 @@ struct mhi_counters {
struct mhi_flags {
	u32 mhi_initialized;
	u32 link_up;
	int stop_threads;
	u32 kill_threads;
	u32 ev_thread_stopped;
	u32 st_thread_stopped;
	bool bb_required;
};

struct mhi_wait_queues {
	wait_queue_head_t *mhi_event_wq;
	wait_queue_head_t *state_change_event;
	wait_queue_head_t *m0_event;
	wait_queue_head_t *m3_event;
	wait_queue_head_t *bhi_event;
@@ -542,9 +544,7 @@ struct mhi_device_ctxt {

	struct mhi_client_handle *client_handle_list[MHI_MAX_CHANNELS];
	struct mhi_event_ring_cfg *ev_ring_props;
	struct task_struct *event_thread_handle;
	struct task_struct *st_thread_handle;
	struct tasklet_struct ev_task; /* Process control Events */
	struct work_struct st_thread_worker;
	struct work_struct process_m1_worker;
	struct mhi_wait_queues mhi_ev_wq;
	struct dev_mmio_info mmio_info;
@@ -604,10 +604,18 @@ struct mhi_event_ring_cfg {
	u32 intmod;
	enum MHI_CLIENT_CHANNEL chan;
	u32 flags;
	/*
	 * Priority of event handling:
	 * 0 = highest, handle events in isr (reserved for future)
	 * 1 = handles event using tasklet
	 * 2 = handles events using workerthread
	 */
	u32 priority;
	enum MHI_RING_CLASS class;
	enum MHI_EVENT_RING_STATE state;
	irqreturn_t (*mhi_handler_ptr)(int , void *);
};
#define MHI_EV_PRIORITY_TASKLET (1)

struct mhi_data_buf {
	dma_addr_t bounce_buffer;
@@ -665,14 +673,13 @@ enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt,
				union mhi_cmd_pkt **cmd_pkt, u32 event_index);
int parse_cmd_event(struct mhi_device_ctxt *ctxt,
				union mhi_event_pkt *event, u32 event_index);
int parse_event_thread(void *ctxt);
int mhi_test_for_device_ready(
					struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_test_for_device_reset(
					struct mhi_device_ctxt *mhi_dev_ctxt);
int validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr);
int validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr);
int mhi_state_change_thread(void *ctxt);
void mhi_state_change_worker(struct work_struct *work);
int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
					enum STATE_TRANSITION new_state);
int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt);
@@ -746,6 +753,9 @@ int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt);
void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
		     enum MHI_STATE new_state);
const char *state_transition_str(enum STATE_TRANSITION state);
void mhi_ctrl_ev_task(unsigned long data);
void mhi_ev_task(unsigned long data);
void process_event_ring(struct work_struct *work);
int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt);

#endif
+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2017, 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
@@ -39,7 +39,7 @@ static int bhi_alloc_bhie_xfer(struct mhi_device_ctxt *mhi_dev_ctxt,
{
	struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
	struct device *dev = &mhi_dev_ctxt->plat_dev->dev;
	const u32 align = bhi_ctxt->alignment - 1;
	const phys_addr_t align = bhi_ctxt->alignment - 1;
	size_t seg_size = bhi_ctxt->firmware_info.segment_size;
	/* We need one additional entry for Vector Table */
	int segments = DIV_ROUND_UP(size, seg_size) + 1;
@@ -112,7 +112,7 @@ static int bhi_alloc_pbl_xfer(struct mhi_device_ctxt *mhi_dev_ctxt,
			      size_t size)
{
	struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
	const u32 align_len = bhi_ctxt->alignment;
	const phys_addr_t align_len = bhi_ctxt->alignment;
	size_t alloc_size = size + (align_len - 1);
	struct device *dev = &mhi_dev_ctxt->plat_dev->dev;

+18 −8
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, 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
@@ -43,13 +43,13 @@ int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt)
		return -ENOMEM;

	for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i) {
		u32 dt_configs[5];
		int len;
		u32 dt_configs[6];
		int no_elements;

		scnprintf(dt_prop, MAX_BUF_SIZE, "%s%d", "mhi-event-cfg-", i);
		if (!of_find_property(np, dt_prop, &len))
			goto dt_error;
		if (len != sizeof(dt_configs))
		no_elements = of_property_count_elems_of_size(np, dt_prop,
							sizeof(dt_configs));
		if (no_elements != 1)
			goto dt_error;
		r = of_property_read_u32_array(
					np,
@@ -66,14 +66,16 @@ int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt)
		mhi_dev_ctxt->ev_ring_props[i].msi_vec = dt_configs[1];
		mhi_dev_ctxt->ev_ring_props[i].intmod = dt_configs[2];
		mhi_dev_ctxt->ev_ring_props[i].chan = dt_configs[3];
		mhi_dev_ctxt->ev_ring_props[i].flags = dt_configs[4];
		mhi_dev_ctxt->ev_ring_props[i].priority = dt_configs[4];
		mhi_dev_ctxt->ev_ring_props[i].flags = dt_configs[5];
		mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
			"ev ring %d,desc:0x%x,msi:0x%x,intmod%d chan:%u flags0x%x\n",
			"ev ring %d,desc:0x%x,msi:0x%x,intmod%d chan:%u priority:%u flags0x%x\n",
			i,
			mhi_dev_ctxt->ev_ring_props[i].nr_desc,
			mhi_dev_ctxt->ev_ring_props[i].msi_vec,
			mhi_dev_ctxt->ev_ring_props[i].intmod,
			mhi_dev_ctxt->ev_ring_props[i].chan,
			mhi_dev_ctxt->ev_ring_props[i].priority,
			mhi_dev_ctxt->ev_ring_props[i].flags);
		if (GET_EV_PROPS(EV_MANAGED,
			mhi_dev_ctxt->ev_ring_props[i].flags))
@@ -128,6 +130,9 @@ int create_local_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt)
			mhi_local_event_ctxt[i];

		spin_lock_init(&mhi_ring->ring_lock);
		tasklet_init(&mhi_ring->ev_task, mhi_ev_task,
			     (unsigned long)mhi_ring);
		INIT_WORK(&mhi_ring->ev_worker, process_event_ring);
	}

	return r;
@@ -157,6 +162,8 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index)

static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
			       struct mhi_ring *ring,
			       struct mhi_device_ctxt *mhi_dev_ctxt,
			       int index,
			       u32 el_per_ring,
			       u32 intmodt_val,
			       u32 msi_vec,
@@ -166,6 +173,8 @@ static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
	ev_list->mhi_msi_vector     = msi_vec;
	ev_list->mhi_event_ring_len = el_per_ring*sizeof(union mhi_event_pkt);
	MHI_SET_EV_CTXT(EVENT_CTXT_INTMODT, ev_list, intmodt_val);
	ring->mhi_dev_ctxt = mhi_dev_ctxt;
	ring->index = index;
	ring->len = ((size_t)(el_per_ring)*sizeof(union mhi_event_pkt));
	ring->el_size = sizeof(union mhi_event_pkt);
	ring->overwrite_en = 0;
@@ -198,6 +207,7 @@ void init_event_ctxt_array(struct mhi_device_ctxt *mhi_dev_ctxt)
		event_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[i];
		mhi_local_event_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[i];
		mhi_event_ring_init(event_ctxt, mhi_local_event_ctxt,
				    mhi_dev_ctxt, i,
				    mhi_dev_ctxt->ev_ring_props[i].nr_desc,
				    mhi_dev_ctxt->ev_ring_props[i].intmod,
				    mhi_dev_ctxt->ev_ring_props[i].msi_vec,
+6 −6
Original line number Diff line number Diff line
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2017, 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
@@ -110,8 +110,6 @@ int mhi_ctxt_init(struct mhi_device_ctxt *mhi_dev_ctxt)

irq_error:
	kfree(mhi_dev_ctxt->state_change_work_item_list.q_lock);
	kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
	kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
	kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event);
	kfree(mhi_dev_ctxt->mhi_ev_wq.m3_event);
	kfree(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
@@ -190,12 +188,10 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
	pcie_device->dev.of_node = plat_dev->dev.of_node;
	mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE;
	INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition);
	INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker);
	mutex_init(&mhi_dev_ctxt->pm_lock);
	rwlock_init(&mhi_dev_ctxt->pm_xfer_lock);
	spin_lock_init(&mhi_dev_ctxt->dev_wake_lock);
	tasklet_init(&mhi_dev_ctxt->ev_task,
		     mhi_ctrl_ev_task,
		     (unsigned long)mhi_dev_ctxt);
	init_completion(&mhi_dev_ctxt->cmd_complete);
	mhi_dev_ctxt->flags.link_up = 1;

@@ -456,6 +452,10 @@ static int mhi_plat_probe(struct platform_device *pdev)
		INIT_WORK(&bhi_ctxt->fw_load_work, bhi_firmware_download);
	}

	mhi_dev_ctxt->flags.bb_required =
		of_property_read_bool(pdev->dev.of_node,
				      "qcom,mhi-bb-required");

	mhi_dev_ctxt->plat_dev = pdev;
	platform_set_drvdata(pdev, mhi_dev_ctxt);

Loading