mhi: core: Enabled full NER support

Enable NER support for MHI core. MHI core now enables
only event rings required for used channels. This saves
a substantial amount of system memory.

Change-Id: I3b9d63875cf117fba2ac062f831da1899b355e2c
Signed-off-by: Andrei Danaila <adanaila@codeaurora.org>
This commit is contained in:
Andrei Danaila 2014-12-11 11:33:39 -08:00 committed by David Keitel
parent ab4c04bef6
commit 8d7c29c161
7 changed files with 27 additions and 94 deletions

View file

@ -356,7 +356,7 @@ struct mhi_control_seg {
union mhi_cmd_pkt cmd_trb_list[NR_OF_CMD_RINGS][CMD_EL_PER_RING + 1]; union mhi_cmd_pkt cmd_trb_list[NR_OF_CMD_RINGS][CMD_EL_PER_RING + 1];
struct mhi_cmd_ctxt mhi_cmd_ctxt_list[NR_OF_CMD_RINGS]; struct mhi_cmd_ctxt mhi_cmd_ctxt_list[NR_OF_CMD_RINGS];
struct mhi_chan_ctxt mhi_cc_list[MHI_MAX_CHANNELS]; struct mhi_chan_ctxt mhi_cc_list[MHI_MAX_CHANNELS];
struct mhi_event_ctxt mhi_ec_list[MHI_MAX_CHANNELS]; struct mhi_event_ctxt mhi_ec_list[EVENT_RINGS_ALLOCATED];
u32 padding; u32 padding;
}; };

View file

@ -31,18 +31,12 @@ static enum MHI_STATUS mhi_create_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_dev_ctxt->nr_of_cmdc = NR_OF_CMD_RINGS; mhi_dev_ctxt->nr_of_cmdc = NR_OF_CMD_RINGS;
mhi_dev_ctxt->alloced_ev_rings[PRIMARY_EVENT_RING] = 0; mhi_dev_ctxt->alloced_ev_rings[PRIMARY_EVENT_RING] = 0;
mhi_dev_ctxt->alloced_ev_rings[SOFTWARE_EV_RING] = mhi_dev_ctxt->alloced_ev_rings[IPA_OUT_EV_RING] = IPA_OUT_EV_RING;
SOFTWARE_EV_RING; mhi_dev_ctxt->alloced_ev_rings[IPA_IN_EV_RING] = IPA_IN_EV_RING;
mhi_dev_ctxt->alloced_ev_rings[IPA_OUT_EV_RING] =
MHI_CLIENT_IP_HW_0_OUT;
mhi_dev_ctxt->alloced_ev_rings[IPA_IN_EV_RING] =
MHI_CLIENT_IP_HW_0_IN;
MHI_SET_EVENT_RING_INFO(EVENT_RING_POLLING, MHI_SET_EVENT_RING_INFO(EVENT_RING_POLLING,
mhi_dev_ctxt->ev_ring_props[PRIMARY_EVENT_RING], mhi_dev_ctxt->ev_ring_props[PRIMARY_EVENT_RING],
MHI_EVENT_POLLING_ENABLED); MHI_EVENT_POLLING_ENABLED);
MHI_SET_EVENT_RING_INFO(EVENT_RING_POLLING,
mhi_dev_ctxt->ev_ring_props[SOFTWARE_EV_RING],
MHI_EVENT_POLLING_ENABLED);
MHI_SET_EVENT_RING_INFO(EVENT_RING_POLLING, MHI_SET_EVENT_RING_INFO(EVENT_RING_POLLING,
mhi_dev_ctxt->ev_ring_props[IPA_OUT_EV_RING], mhi_dev_ctxt->ev_ring_props[IPA_OUT_EV_RING],
MHI_EVENT_POLLING_ENABLED); MHI_EVENT_POLLING_ENABLED);
@ -50,7 +44,7 @@ static enum MHI_STATUS mhi_create_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_dev_ctxt->ev_ring_props[IPA_IN_EV_RING], mhi_dev_ctxt->ev_ring_props[IPA_IN_EV_RING],
MHI_EVENT_POLLING_DISABLED); MHI_EVENT_POLLING_DISABLED);
for (i = 0; i < MAX_NR_MSI; ++i) { for (i = 0; i < EVENT_RINGS_ALLOCATED; ++i) {
MHI_SET_EVENT_RING_INFO(EVENT_RING_MSI_VEC, MHI_SET_EVENT_RING_INFO(EVENT_RING_MSI_VEC,
mhi_dev_ctxt->ev_ring_props[i], mhi_dev_ctxt->ev_ring_props[i],
i); i);
@ -461,7 +455,7 @@ static enum MHI_STATUS mhi_init_contexts(struct mhi_device_ctxt *mhi_dev_ctxt)
(uintptr_t)trb_list, (uintptr_t)trb_list,
MAX_NR_TRBS_PER_HARD_CHAN, MAX_NR_TRBS_PER_HARD_CHAN,
(i % 2) ? MHI_IN : MHI_OUT, (i % 2) ? MHI_IN : MHI_OUT,
i, EVENT_RINGS_ALLOCATED - (MHI_MAX_CHANNELS - i),
&mhi_dev_ctxt->mhi_local_chan_ctxt[i]); &mhi_dev_ctxt->mhi_local_chan_ctxt[i]);
} }
} }

View file

@ -35,13 +35,11 @@ irqreturn_t mhi_msi_handlr(int irq_number, void *dev_id)
switch (IRQ_TO_MSI(mhi_dev_ctxt, irq_number)) { switch (IRQ_TO_MSI(mhi_dev_ctxt, irq_number)) {
case 0: case 0:
case 1: case 1:
case 2:
atomic_inc(&mhi_dev_ctxt->flags.events_pending); atomic_inc(&mhi_dev_ctxt->flags.events_pending);
wake_up_interruptible(mhi_dev_ctxt->event_handle); wake_up_interruptible(mhi_dev_ctxt->event_handle);
break; break;
case 3: case 2:
client_index = client_index = MHI_CLIENT_IP_HW_0_IN;
mhi_dev_ctxt->alloced_ev_rings[IPA_IN_EV_RING];
client_handle = mhi_dev_ctxt->client_handle_list[client_index]; client_handle = mhi_dev_ctxt->client_handle_list[client_index];
client_info = &client_handle->client_info; client_info = &client_handle->client_info;

View file

@ -32,11 +32,10 @@
#define MAX_NR_MSI 4 #define MAX_NR_MSI 4
#define EVENT_RINGS_ALLOCATED 4 #define EVENT_RINGS_ALLOCATED 3
#define PRIMARY_EVENT_RING 0 #define PRIMARY_EVENT_RING 0
#define SOFTWARE_EV_RING 1 #define IPA_OUT_EV_RING 1
#define IPA_OUT_EV_RING 2 #define IPA_IN_EV_RING 2
#define IPA_IN_EV_RING 3
#define PRIMARY_CMD_RING 0 #define PRIMARY_CMD_RING 0
#define MHI_WORK_Q_MAX_SIZE 128 #define MHI_WORK_Q_MAX_SIZE 128

View file

@ -50,8 +50,12 @@ static void mhi_update_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan]. mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan].
mhi_trb_write_ptr = val; mhi_trb_write_ptr = val;
} else if (mhi_dev_ctxt->event_db_addr == io_addr) { } else if (mhi_dev_ctxt->event_db_addr == io_addr) {
if (chan < EVENT_RINGS_ALLOCATED)
mhi_dev_ctxt->mhi_ctrl_seg->mhi_ec_list[chan]. mhi_dev_ctxt->mhi_ctrl_seg->mhi_ec_list[chan].
mhi_event_write_ptr = val; mhi_event_write_ptr = val;
else
mhi_log(MHI_MSG_ERROR,
"Bad EV ring index: %lx\n", chan);
} }
} }
@ -334,10 +338,9 @@ enum MHI_STATUS mhi_register_channel(struct mhi_client_handle **client_handle,
mhi_log(MHI_MSG_VERBOSE, mhi_log(MHI_MSG_VERBOSE,
"Successfuly registered chan 0x%x\n", chan); "Successfuly registered chan 0x%x\n", chan);
return ret_val;
error_handle: error_handle:
return ret_val; return ret_val;
} }
EXPORT_SYMBOL(mhi_register_channel); EXPORT_SYMBOL(mhi_register_channel);
@ -410,8 +413,7 @@ enum MHI_STATUS mhi_add_elements_to_event_rings(
event_ring_state); event_ring_state);
ret_val = mhi_init_event_ring(mhi_dev_ctxt, ret_val = mhi_init_event_ring(mhi_dev_ctxt,
EV_EL_PER_RING, EV_EL_PER_RING,
mhi_dev_ctxt-> PRIMARY_EVENT_RING);
alloced_ev_rings[PRIMARY_EVENT_RING]);
if (MHI_STATUS_SUCCESS != ret_val) { if (MHI_STATUS_SUCCESS != ret_val) {
mhi_log(MHI_MSG_ERROR, mhi_log(MHI_MSG_ERROR,
@ -425,7 +427,7 @@ enum MHI_STATUS mhi_add_elements_to_event_rings(
mhi_log(MHI_MSG_ERROR, mhi_log(MHI_MSG_ERROR,
"Event ring initialized ringing, EV DB to resume\n"); "Event ring initialized ringing, EV DB to resume\n");
ring_ev_db(mhi_dev_ctxt, ring_ev_db(mhi_dev_ctxt,
mhi_dev_ctxt->alloced_ev_rings[PRIMARY_EVENT_RING]); PRIMARY_EVENT_RING);
break; break;
case STATE_TRANSITION_AMSS: case STATE_TRANSITION_AMSS:
MHI_GET_EVENT_RING_INFO(EVENT_RING_STATE_FIELD, MHI_GET_EVENT_RING_INFO(EVENT_RING_STATE_FIELD,
@ -434,8 +436,7 @@ enum MHI_STATUS mhi_add_elements_to_event_rings(
if (MHI_EVENT_RING_UINIT == event_ring_state) { if (MHI_EVENT_RING_UINIT == event_ring_state) {
ret_val = mhi_init_event_ring(mhi_dev_ctxt, ret_val = mhi_init_event_ring(mhi_dev_ctxt,
EV_EL_PER_RING, EV_EL_PER_RING,
mhi_dev_ctxt-> IPA_OUT_EV_RING);
alloced_ev_rings[IPA_OUT_EV_RING]);
if (MHI_STATUS_SUCCESS != ret_val) { if (MHI_STATUS_SUCCESS != ret_val) {
mhi_log(MHI_MSG_ERROR, mhi_log(MHI_MSG_ERROR,
"Failed to add ev el on event ring\n"); "Failed to add ev el on event ring\n");
@ -443,7 +444,7 @@ enum MHI_STATUS mhi_add_elements_to_event_rings(
} }
ret_val = mhi_init_event_ring(mhi_dev_ctxt, ret_val = mhi_init_event_ring(mhi_dev_ctxt,
EV_EL_PER_RING, EV_EL_PER_RING,
mhi_dev_ctxt->alloced_ev_rings[IPA_IN_EV_RING]); IPA_IN_EV_RING);
if (MHI_STATUS_SUCCESS != ret_val) { if (MHI_STATUS_SUCCESS != ret_val) {
mhi_log(MHI_MSG_ERROR, mhi_log(MHI_MSG_ERROR,
"Failed to add ev el on event ring\n"); "Failed to add ev el on event ring\n");
@ -456,12 +457,8 @@ enum MHI_STATUS mhi_add_elements_to_event_rings(
mhi_dev_ctxt->ev_ring_props[IPA_IN_EV_RING], mhi_dev_ctxt->ev_ring_props[IPA_IN_EV_RING],
MHI_EVENT_RING_INIT); MHI_EVENT_RING_INIT);
} }
ring_ev_db(mhi_dev_ctxt, ring_ev_db(mhi_dev_ctxt, IPA_OUT_EV_RING);
mhi_dev_ctxt->alloced_ev_rings[SOFTWARE_EV_RING]); ring_ev_db(mhi_dev_ctxt, IPA_IN_EV_RING);
ring_ev_db(mhi_dev_ctxt,
mhi_dev_ctxt->alloced_ev_rings[IPA_OUT_EV_RING]);
ring_ev_db(mhi_dev_ctxt,
mhi_dev_ctxt->alloced_ev_rings[IPA_IN_EV_RING]);
break; break;
default: default:
mhi_log(MHI_MSG_ERROR, mhi_log(MHI_MSG_ERROR,
@ -784,6 +781,9 @@ static enum MHI_STATUS parse_inbound(struct mhi_device_ctxt *mhi_dev_ctxt,
cb_info.result = &client_handle->result; cb_info.result = &client_handle->result;
cb_info.chan = chan; cb_info.chan = chan;
client_handle->client_info.mhi_client_cb(&cb_info); client_handle->client_info.mhi_client_cb(&cb_info);
} else {
mhi_log(MHI_MSG_VERBOSE,
"No client registered chan %d\n", chan);
} }
} else { } else {
/* IN Hardware channel with no client /* IN Hardware channel with no client

View file

@ -108,7 +108,7 @@ enum MHI_STATUS mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICFG, mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICFG,
MHICFG_NER_MASK, MHICFG_NER_SHIFT, MHICFG_NER_MASK, MHICFG_NER_SHIFT,
MHI_MAX_CHANNELS); EVENT_RINGS_ALLOCATED);
pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info, pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info,
(uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list); (uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list);

View file

@ -751,64 +751,6 @@ int mhi_state_change_thread(void *ctxt)
return 0; return 0;
} }
/**
* mhi_reset_channel - Reset for a single MHI channel
*
* @client_handle device context
*
*/
enum MHI_STATUS mhi_reset_channel(struct mhi_client_handle *client_handle)
{
enum MHI_STATUS ret_val;
struct mhi_chan_ctxt *cur_ctxt = NULL;
struct mhi_device_ctxt *mhi_dev_ctxt = NULL;
u32 chan_id = 0;
struct mhi_ring *cur_ring = NULL;
chan_id = client_handle->chan;
mhi_dev_ctxt = client_handle->mhi_dev_ctxt;
if (chan_id > (MHI_MAX_CHANNELS - 1) || NULL == mhi_dev_ctxt) {
mhi_log(MHI_MSG_ERROR, "Bad input parameters\n");
return MHI_STATUS_ERROR;
}
mutex_lock(&mhi_dev_ctxt->mhi_chan_mutex[chan_id]);
/* We need to reset the channel completley, we will assume that our
* base is correct*/
cur_ctxt = &mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan_id];
cur_ring = &mhi_dev_ctxt->mhi_local_event_ctxt[chan_id];
memset(cur_ring->base, 0, sizeof(char)*cur_ring->len);
if (IS_HARDWARE_CHANNEL(chan_id)) {
ret_val = mhi_init_chan_ctxt(cur_ctxt,
mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info,
(uintptr_t)cur_ring->base),
(uintptr_t)cur_ring->base,
MAX_NR_TRBS_PER_HARD_CHAN,
(chan_id % 2) ? MHI_IN : MHI_OUT,
(chan_id % 2) ? IPA_IN_EV_RING : IPA_OUT_EV_RING,
cur_ring);
} else {
ret_val = mhi_init_chan_ctxt(cur_ctxt,
mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info,
(uintptr_t)cur_ring->base),
(uintptr_t)cur_ring->base,
MAX_NR_TRBS_PER_SOFT_CHAN,
(chan_id % 2) ? MHI_IN : MHI_OUT,
SOFTWARE_EV_RING,
cur_ring);
}
if (MHI_STATUS_SUCCESS != ret_val)
mhi_log(MHI_MSG_ERROR, "Failed to reset chan ctxt\n");
mutex_unlock(&mhi_dev_ctxt->mhi_chan_mutex[chan_id]);
return ret_val;
}
/** /**
* mhi_init_state_transition - Add a new state transition work item to * mhi_init_state_transition - Add a new state transition work item to
* the state transition thread work item list. * the state transition thread work item list.