spmi: pmic-arb: optimize table lookups

The current driver uses a mix of radix tree and a fwd lookup
table to translate between apid and ppid. It is buggy and confusing.

Instead simply use a radix tree for v1 hardware and use the
forward lookup table for v2.

Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Signed-off-by: Kiran Gunda <kgunda@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Abhijeet Dharmapurikar 2017-05-10 19:55:34 +05:30 committed by Greg Kroah-Hartman
parent 1ef1ce4e9d
commit 7f1d4e58da

View file

@ -164,6 +164,8 @@ struct spmi_pmic_arb {
* on v2 offset of SPMI_PIC_IRQ_CLEARn. * on v2 offset of SPMI_PIC_IRQ_CLEARn.
*/ */
struct pmic_arb_ver_ops { struct pmic_arb_ver_ops {
int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
u8 *apid);
int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
mode_t *mode); mode_t *mode);
/* spmi commands (read_cmd, write_cmd, cmd) functionality */ /* spmi commands (read_cmd, write_cmd, cmd) functionality */
@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
unsigned irq:3; unsigned irq:3;
}; };
static int search_mapping_table(struct spmi_pmic_arb *pa,
struct spmi_pmic_arb_irq_spec *spec,
u8 *apid)
{
u16 ppid = spec->slave << 8 | spec->per;
u32 *mapping_table = pa->mapping_table;
int index = 0, i;
u32 data;
for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
if (!test_and_set_bit(index, pa->mapping_table_valid))
mapping_table[index] = readl_relaxed(pa->cnfg +
SPMI_MAPPING_TABLE_REG(index));
data = mapping_table[index];
if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
} else {
*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
return 0;
}
} else {
if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
} else {
*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
return 0;
}
}
}
return -ENODEV;
}
static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
struct device_node *controller, struct device_node *controller,
const u32 *intspec, const u32 *intspec,
@ -702,7 +668,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
{ {
struct spmi_pmic_arb *pa = d->host_data; struct spmi_pmic_arb *pa = d->host_data;
struct spmi_pmic_arb_irq_spec spec; struct spmi_pmic_arb_irq_spec spec;
int err; int rc;
u8 apid; u8 apid;
dev_dbg(&pa->spmic->dev, dev_dbg(&pa->spmic->dev,
@ -720,11 +686,14 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
spec.per = intspec[1]; spec.per = intspec[1];
spec.irq = intspec[2]; spec.irq = intspec[2];
err = search_mapping_table(pa, &spec, &apid); rc = pa->ver_ops->ppid_to_apid(pa, intspec[0],
if (err) (intspec[1] << 8), &apid);
return err; if (rc < 0) {
dev_err(&pa->spmic->dev,
pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per; "failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
intspec[0], intspec[1], intspec[2], rc);
return rc;
}
/* Keep track of {max,min}_apid for bounding search during interrupt */ /* Keep track of {max,min}_apid for bounding search during interrupt */
if (apid > pa->max_apid) if (apid > pa->max_apid)
@ -757,6 +726,54 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
return 0; return 0;
} }
static int
pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
{
u16 ppid = sid << 8 | ((addr >> 8) & 0xFF);
u32 *mapping_table = pa->mapping_table;
int index = 0, i;
u16 apid_valid;
u32 data;
apid_valid = pa->ppid_to_apid[ppid];
if (apid_valid & PMIC_ARB_CHAN_VALID) {
*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);
return 0;
}
for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
if (!test_and_set_bit(index, pa->mapping_table_valid))
mapping_table[index] = readl_relaxed(pa->cnfg +
SPMI_MAPPING_TABLE_REG(index));
data = mapping_table[index];
if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
} else {
*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
pa->ppid_to_apid[ppid]
= *apid | PMIC_ARB_CHAN_VALID;
pa->apid_to_ppid[*apid] = ppid;
return 0;
}
} else {
if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
} else {
*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
pa->ppid_to_apid[ppid]
= *apid | PMIC_ARB_CHAN_VALID;
pa->apid_to_ppid[*apid] = ppid;
return 0;
}
}
}
return -ENODEV;
}
static int static int
pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
{ {
@ -797,6 +814,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
id = (regval >> 8) & PMIC_ARB_PPID_MASK; id = (regval >> 8) & PMIC_ARB_PPID_MASK;
pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID; pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
pa->apid_to_ppid[apid] = id;
if (id == ppid) { if (id == ppid) {
apid |= PMIC_ARB_CHAN_VALID; apid |= PMIC_ARB_CHAN_VALID;
break; break;
@ -809,20 +827,35 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
static int static int
pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
{ {
u16 ppid = (sid << 8) | (addr >> 8); u16 ppid = (sid << 8) | (addr >> 8);
u16 apid; u16 apid_valid;
u8 owner;
apid = pa->ppid_to_apid[ppid]; apid_valid = pa->ppid_to_apid[ppid];
if (!(apid & PMIC_ARB_CHAN_VALID)) if (!(apid_valid & PMIC_ARB_CHAN_VALID))
apid_valid = pmic_arb_find_apid(pa, ppid);
if (!(apid_valid & PMIC_ARB_CHAN_VALID))
return -ENODEV; return -ENODEV;
*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);
return 0;
}
static int
pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
{
u8 apid;
u8 owner;
int rc;
rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
if (rc < 0)
return rc;
*mode = 0; *mode = 0;
*mode |= S_IRUSR; *mode |= S_IRUSR;
apid &= ~PMIC_ARB_CHAN_VALID;
owner = pa->apid_to_owner[apid]; owner = pa->apid_to_owner[apid];
if (owner == pa->ee) if (owner == pa->ee)
*mode |= S_IWUSR; *mode |= S_IWUSR;
@ -833,15 +866,12 @@ pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
static int static int
pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
{ {
u16 ppid = (sid << 8) | (addr >> 8); u8 apid;
u16 apid; int rc;
apid = pa->ppid_to_apid[ppid]; rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
if (!(apid & PMIC_ARB_CHAN_VALID)) if (rc < 0)
apid = pmic_arb_find_apid(pa, ppid); return rc;
if (!(apid & PMIC_ARB_CHAN_VALID))
return -ENODEV;
apid &= ~PMIC_ARB_CHAN_VALID;
*offset = 0x1000 * pa->ee + 0x8000 * apid; *offset = 0x1000 * pa->ee + 0x8000 * apid;
return 0; return 0;
@ -898,6 +928,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
} }
static const struct pmic_arb_ver_ops pmic_arb_v1 = { static const struct pmic_arb_ver_ops pmic_arb_v1 = {
.ppid_to_apid = pmic_arb_ppid_to_apid_v1,
.mode = pmic_arb_mode_v1, .mode = pmic_arb_mode_v1,
.non_data_cmd = pmic_arb_non_data_cmd_v1, .non_data_cmd = pmic_arb_non_data_cmd_v1,
.offset = pmic_arb_offset_v1, .offset = pmic_arb_offset_v1,
@ -909,6 +940,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
}; };
static const struct pmic_arb_ver_ops pmic_arb_v2 = { static const struct pmic_arb_ver_ops pmic_arb_v2 = {
.ppid_to_apid = pmic_arb_ppid_to_apid_v2,
.mode = pmic_arb_mode_v2, .mode = pmic_arb_mode_v2,
.non_data_cmd = pmic_arb_non_data_cmd_v2, .non_data_cmd = pmic_arb_non_data_cmd_v2,
.offset = pmic_arb_offset_v2, .offset = pmic_arb_offset_v2,