mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									1ef1ce4e9d
								
							
						
					
					
						commit
						7f1d4e58da
					
				
					 1 changed files with 88 additions and 56 deletions
				
			
		| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue