spmi: pmic-arb: optimize table lookups
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>
Wed, 10 May 2017 14:25:34 +0000 (19:55 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 3 Jun 2017 10:05:47 +0000 (19:05 +0900)
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>
drivers/spmi/spmi-pmic-arb.c

index 7201611..6320f1f 100644 (file)
@@ -164,6 +164,8 @@ struct spmi_pmic_arb {
  *                     on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 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,
                        mode_t *mode);
        /* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
        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,
                                           struct device_node *controller,
                                           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_irq_spec spec;
-       int err;
+       int rc;
        u8 apid;
 
        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.irq   = intspec[2];
 
-       err = search_mapping_table(pa, &spec, &apid);
-       if (err)
-               return err;
-
-       pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+       rc = pa->ver_ops->ppid_to_apid(pa, intspec[0],
+                       (intspec[1] << 8), &apid);
+       if (rc < 0) {
+               dev_err(&pa->spmic->dev,
+               "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 */
        if (apid > pa->max_apid)
@@ -758,6 +727,54 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 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
 pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
        *mode = S_IRUSR | S_IWUSR;
@@ -797,6 +814,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
                id = (regval >> 8) & PMIC_ARB_PPID_MASK;
                pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
+               pa->apid_to_ppid[apid] = id;
                if (id == ppid) {
                        apid |= PMIC_ARB_CHAN_VALID;
                        break;
@@ -809,20 +827,35 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 
 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 apid;
-       u8 owner;
+       u16 apid_valid;
 
-       apid = pa->ppid_to_apid[ppid];
-       if (!(apid & PMIC_ARB_CHAN_VALID))
+       apid_valid = pa->ppid_to_apid[ppid];
+       if (!(apid_valid & PMIC_ARB_CHAN_VALID))
+               apid_valid = pmic_arb_find_apid(pa, ppid);
+       if (!(apid_valid & PMIC_ARB_CHAN_VALID))
                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 |= S_IRUSR;
 
-       apid &= ~PMIC_ARB_CHAN_VALID;
        owner = pa->apid_to_owner[apid];
        if (owner == pa->ee)
                *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
 pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
 {
-       u16 ppid = (sid << 8) | (addr >> 8);
-       u16 apid;
+       u8 apid;
+       int rc;
 
-       apid = pa->ppid_to_apid[ppid];
-       if (!(apid & PMIC_ARB_CHAN_VALID))
-               apid = pmic_arb_find_apid(pa, ppid);
-       if (!(apid & PMIC_ARB_CHAN_VALID))
-               return -ENODEV;
-       apid &= ~PMIC_ARB_CHAN_VALID;
+       rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
+       if (rc < 0)
+               return rc;
 
        *offset = 0x1000 * pa->ee + 0x8000 * apid;
        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 = {
+       .ppid_to_apid           = pmic_arb_ppid_to_apid_v1,
        .mode                   = pmic_arb_mode_v1,
        .non_data_cmd           = pmic_arb_non_data_cmd_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 = {
+       .ppid_to_apid           = pmic_arb_ppid_to_apid_v2,
        .mode                   = pmic_arb_mode_v2,
        .non_data_cmd           = pmic_arb_non_data_cmd_v2,
        .offset                 = pmic_arb_offset_v2,