Skip to content

Commit

Permalink
Revert "sde: interrupts: optimize interrupt dispatching routines"
Browse files Browse the repository at this point in the history
This reverts commit fe70833.
  • Loading branch information
UtsavBalar1231 committed Aug 18, 2020
1 parent de70e7d commit 8e78e6d
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 20 deletions.
37 changes: 33 additions & 4 deletions drivers/gpu/drm/msm/sde/sde_core_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx)
&sde_kms->irq_obj.enable_counts[irq_idx]);
}

atomic_inc(&irq_obj->irq_counts[irq_idx]);

/*
* Perform registered function callback
*/
Expand All @@ -70,6 +72,15 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx)
SDE_EVT32_IRQ(irq_idx, enable_counts, SDE_EVTLOG_ERROR);
}
}

/*
* Clear pending interrupt status in HW.
* NOTE: sde_core_irq_callback_handler is protected by top-level
* spinlock, so it is safe to clear any interrupt status here.
*/
sde_kms->hw_intr->ops.clear_intr_status_nolock(
sde_kms->hw_intr,
irq_idx);
}

int sde_core_irq_idx_lookup(struct sde_kms *sde_kms,
Expand All @@ -94,7 +105,8 @@ static int _sde_core_irq_enable(struct sde_kms *sde_kms, int irq_idx)
int ret = 0;

if (!sde_kms || !sde_kms->hw_intr ||
!sde_kms->irq_obj.enable_counts) {
!sde_kms->irq_obj.enable_counts ||
!sde_kms->irq_obj.irq_counts) {
SDE_ERROR("invalid params\n");
return -EINVAL;
}
Expand Down Expand Up @@ -400,14 +412,15 @@ static int sde_debugfs_core_irq_show(struct seq_file *s, void *v)
for (i = 0; i < irq_obj->total_irqs; i++) {
spin_lock_irqsave(&irq_obj->cb_lock, irq_flags);
cb_count = 0;
irq_count = atomic_read(&irq_obj->irq_counts[i]);
enable_count = atomic_read(&irq_obj->enable_counts[i]);
list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list)
cb_count++;
spin_unlock_irqrestore(&irq_obj->cb_lock, irq_flags);

if (irq_count || enable_count || cb_count)
seq_printf(s, "idx:%d enable:%d cb:%d\n",
i, enable_count, cb_count);
seq_printf(s, "idx:%d irq:%d enable:%d cb:%d\n",
i, irq_count, enable_count, cb_count);
}

return 0;
Expand Down Expand Up @@ -481,14 +494,19 @@ void sde_core_irq_preinstall(struct sde_kms *sde_kms)
sizeof(struct list_head), GFP_KERNEL);
sde_kms->irq_obj.enable_counts = kcalloc(sde_kms->irq_obj.total_irqs,
sizeof(atomic_t), GFP_KERNEL);
if (!sde_kms->irq_obj.irq_cb_tbl || !sde_kms->irq_obj.enable_counts)
sde_kms->irq_obj.irq_counts = kcalloc(sde_kms->irq_obj.total_irqs,
sizeof(atomic_t), GFP_KERNEL);
if (!sde_kms->irq_obj.irq_cb_tbl || !sde_kms->irq_obj.enable_counts
|| !sde_kms->irq_obj.irq_counts)
return;

for (i = 0; i < sde_kms->irq_obj.total_irqs; i++) {
if (sde_kms->irq_obj.irq_cb_tbl)
INIT_LIST_HEAD(&sde_kms->irq_obj.irq_cb_tbl[i]);
if (sde_kms->irq_obj.enable_counts)
atomic_set(&sde_kms->irq_obj.enable_counts[i], 0);
if (sde_kms->irq_obj.irq_counts)
atomic_set(&sde_kms->irq_obj.irq_counts[i], 0);
}
}

Expand Down Expand Up @@ -536,8 +554,10 @@ void sde_core_irq_uninstall(struct sde_kms *sde_kms)
spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
kfree(sde_kms->irq_obj.irq_cb_tbl);
kfree(sde_kms->irq_obj.enable_counts);
kfree(sde_kms->irq_obj.irq_counts);
sde_kms->irq_obj.irq_cb_tbl = NULL;
sde_kms->irq_obj.enable_counts = NULL;
sde_kms->irq_obj.irq_counts = NULL;
sde_kms->irq_obj.total_irqs = 0;
spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
}
Expand Down Expand Up @@ -641,6 +661,15 @@ int sde_core_irq_domain_fini(struct sde_kms *sde_kms)

irqreturn_t sde_core_irq(struct sde_kms *sde_kms)
{
/*
* Read interrupt status from all sources. Interrupt status are
* stored within hw_intr.
* Function will also clear the interrupt status after reading.
* Individual interrupt status bit will only get stored if it
* is enabled.
*/
sde_kms->hw_intr->ops.get_interrupt_statuses(sde_kms->hw_intr);

/*
* Dispatch to HW driver to handle interrupt lookup that is being
* fired. When matching interrupt is located, HW driver will call to
Expand Down
71 changes: 55 additions & 16 deletions drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,17 +880,13 @@ static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
return;

/*
* The dispatcher will save the IRQ status before calling here.
* Now need to go through each IRQ status and find matching
* irq lookup index.
*/
spin_lock_irqsave(&intr->irq_lock, irq_flags);
for (reg_idx = 0; reg_idx < intr->sde_irq_size; reg_idx++) {
/* Read interrupt status */
irq_status = SDE_REG_READ(&intr->hw,
intr->sde_irq_tbl[reg_idx].status_off);

if (!irq_status)
continue;
irq_status = intr->save_irq_status[reg_idx];

/* get the global offset in 'sde_irq_map' */
sde_irq_idx = intr->sde_irq_tbl[reg_idx].sde_irq_idx;
Expand All @@ -916,13 +912,20 @@ static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
for (irq_idx = start_idx;
(irq_idx < end_idx) && irq_status;
irq_idx++)
if (irq_status & sde_irq_map[irq_idx].irq_mask) {
if ((irq_status & sde_irq_map[irq_idx].irq_mask) &&
(sde_irq_map[irq_idx].reg_idx == reg_idx)) {
/*
* Once a match on irq mask, perform a callback
* to the given cbfunc.
* to the given cbfunc. cbfunc will take care
* the interrupt status clearing. If cbfunc is
* not provided, then the interrupt clearing
* is here.
*/
if (cbfunc)
cbfunc(arg, irq_idx);
else
intr->ops.clear_intr_status_nolock(
intr, irq_idx);

/*
* When callback finish, clear the irq_status
Expand All @@ -931,15 +934,7 @@ static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
*/
irq_status &= ~sde_irq_map[irq_idx].irq_mask;
}

/* Clear the interrupt */
SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[reg_idx].clr_off,
0xffffffff);
}

/* ensure register writes go through */
wmb();

spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
}

Expand Down Expand Up @@ -1120,6 +1115,40 @@ static int sde_hw_intr_get_interrupt_sources(struct sde_hw_intr *intr,
return 0;
}

static void sde_hw_intr_get_interrupt_statuses(struct sde_hw_intr *intr)
{
int i;
u32 enable_mask;
unsigned long irq_flags;

if (!intr)
return;

spin_lock_irqsave(&intr->irq_lock, irq_flags);
for (i = 0; i < intr->sde_irq_size; i++) {
/* Read interrupt status */
intr->save_irq_status[i] = SDE_REG_READ(&intr->hw,
intr->sde_irq_tbl[i].status_off);

/* Read enable mask */
enable_mask = SDE_REG_READ(&intr->hw,
intr->sde_irq_tbl[i].en_off);

/* and clear the interrupt */
if (intr->save_irq_status[i])
SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[i].clr_off,
intr->save_irq_status[i]);

/* Finally update IRQ status based on enable mask */
intr->save_irq_status[i] &= enable_mask;
}

/* ensure register writes go through */
wmb();

spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
}

static void sde_hw_intr_clear_intr_status_force_mask(struct sde_hw_intr *intr,
int irq_idx, u32 irq_mask)
{
Expand Down Expand Up @@ -1292,6 +1321,7 @@ static void __setup_intr_ops(struct sde_hw_intr_ops *ops)
ops->disable_all_irqs = sde_hw_intr_disable_irqs;
ops->get_valid_interrupts = sde_hw_intr_get_valid_interrupts;
ops->get_interrupt_sources = sde_hw_intr_get_interrupt_sources;
ops->get_interrupt_statuses = sde_hw_intr_get_interrupt_statuses;
ops->clear_interrupt_status = sde_hw_intr_clear_interrupt_status;
ops->clear_intr_status_nolock = sde_hw_intr_clear_intr_status_nolock;
ops->clear_intr_status_force_mask =
Expand Down Expand Up @@ -1439,6 +1469,7 @@ void sde_hw_intr_destroy(struct sde_hw_intr *intr)
if (intr) {
kfree(intr->sde_irq_tbl);
kfree(intr->cache_irq_mask);
kfree(intr->save_irq_status);
kfree(intr);
}
}
Expand Down Expand Up @@ -1547,13 +1578,21 @@ struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr,
goto exit;
}

intr->save_irq_status = kcalloc(intr->sde_irq_size, sizeof(u32),
GFP_KERNEL);
if (intr->save_irq_status == NULL) {
ret = -ENOMEM;
goto exit;
}

spin_lock_init(&intr->irq_lock);

return intr;

exit:
kfree(intr->sde_irq_tbl);
kfree(intr->cache_irq_mask);
kfree(intr->save_irq_status);
kfree(intr);
return ERR_PTR(ret);
}
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ struct sde_hw_intr_ops {
void (*cbfunc)(void *arg, int irq_idx),
void *arg);

/**
* get_interrupt_statuses - Gets and store value from all interrupt
* status registers that are currently fired.
* @intr: HW interrupt handle
*/
void (*get_interrupt_statuses)(
struct sde_hw_intr *intr);

/**
* clear_interrupt_status - Clears HW interrupt status based on given
* lookup IRQ index.
Expand Down Expand Up @@ -284,6 +292,7 @@ struct sde_hw_intr_ops {
* @hw: virtual address mapping
* @ops: function pointer mapping for IRQ handling
* @cache_irq_mask: array of IRQ enable masks reg storage created during init
* @save_irq_status: array of IRQ status reg storage created during init
* @irq_idx_tbl_size: total number of irq_idx mapped in the hw_interrupts
* @irq_lock: spinlock for accessing IRQ resources
* @sde_irq_size: total number of elements of the sde_irq_tbl
Expand All @@ -294,6 +303,7 @@ struct sde_hw_intr {
struct sde_hw_blk_reg_map hw;
struct sde_hw_intr_ops ops;
u32 *cache_irq_mask;
u32 *save_irq_status;
u32 irq_idx_tbl_size;
u32 sde_irq_size;
struct sde_intr_reg *sde_irq_tbl;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/msm/sde/sde_kms.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ struct sde_irq {
u32 total_irqs;
struct list_head *irq_cb_tbl;
atomic_t *enable_counts;
atomic_t *irq_counts;
spinlock_t cb_lock;
struct dentry *debugfs_file;
};
Expand Down

0 comments on commit 8e78e6d

Please sign in to comment.