diff options
Diffstat (limited to 'drivers/remoteproc/pru_rproc.c')
| -rw-r--r-- | drivers/remoteproc/pru_rproc.c | 67 | 
1 files changed, 54 insertions, 13 deletions
| diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 2667919d76b3..e5778e476245 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -244,8 +244,8 @@ static int pru_rproc_debug_ss_get(void *data, u64 *val)  	return 0;  } -DEFINE_SIMPLE_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get, -			pru_rproc_debug_ss_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get, +			 pru_rproc_debug_ss_set, "%llu\n");  /*   * Create PRU-specific debugfs entries @@ -266,12 +266,17 @@ static void pru_rproc_create_debug_entries(struct rproc *rproc)  static void pru_dispose_irq_mapping(struct pru_rproc *pru)  { -	while (pru->evt_count--) { +	if (!pru->mapped_irq) +		return; + +	while (pru->evt_count) { +		pru->evt_count--;  		if (pru->mapped_irq[pru->evt_count] > 0)  			irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);  	}  	kfree(pru->mapped_irq); +	pru->mapped_irq = NULL;  }  /* @@ -284,7 +289,7 @@ static int pru_handle_intrmap(struct rproc *rproc)  	struct pru_rproc *pru = rproc->priv;  	struct pru_irq_rsc *rsc = pru->pru_interrupt_map;  	struct irq_fwspec fwspec; -	struct device_node *irq_parent; +	struct device_node *parent, *irq_parent;  	int i, ret = 0;  	/* not having pru_interrupt_map is not an error */ @@ -307,16 +312,31 @@ static int pru_handle_intrmap(struct rproc *rproc)  	pru->evt_count = rsc->num_evts;  	pru->mapped_irq = kcalloc(pru->evt_count, sizeof(unsigned int),  				  GFP_KERNEL); -	if (!pru->mapped_irq) +	if (!pru->mapped_irq) { +		pru->evt_count = 0;  		return -ENOMEM; +	}  	/*  	 * parse and fill in system event to interrupt channel and -	 * channel-to-host mapping +	 * channel-to-host mapping. The interrupt controller to be used +	 * for these mappings for a given PRU remoteproc is always its +	 * corresponding sibling PRUSS INTC node.  	 */ -	irq_parent = of_irq_find_parent(pru->dev->of_node); +	parent = of_get_parent(dev_of_node(pru->dev)); +	if (!parent) { +		kfree(pru->mapped_irq); +		pru->mapped_irq = NULL; +		pru->evt_count = 0; +		return -ENODEV; +	} + +	irq_parent = of_get_child_by_name(parent, "interrupt-controller"); +	of_node_put(parent);  	if (!irq_parent) {  		kfree(pru->mapped_irq); +		pru->mapped_irq = NULL; +		pru->evt_count = 0;  		return -ENODEV;  	} @@ -332,16 +352,20 @@ static int pru_handle_intrmap(struct rproc *rproc)  		pru->mapped_irq[i] = irq_create_fwspec_mapping(&fwspec);  		if (!pru->mapped_irq[i]) { -			dev_err(dev, "failed to get virq\n"); -			ret = pru->mapped_irq[i]; +			dev_err(dev, "failed to get virq for fw mapping %d: event %d chnl %d host %d\n", +				i, fwspec.param[0], fwspec.param[1], +				fwspec.param[2]); +			ret = -EINVAL;  			goto map_fail;  		}  	} +	of_node_put(irq_parent);  	return ret;  map_fail:  	pru_dispose_irq_mapping(pru); +	of_node_put(irq_parent);  	return ret;  } @@ -387,8 +411,7 @@ static int pru_rproc_stop(struct rproc *rproc)  	pru_control_write_reg(pru, PRU_CTRL_CTRL, val);  	/* dispose irq mapping - new firmware can provide new mapping */ -	if (pru->mapped_irq) -		pru_dispose_irq_mapping(pru); +	pru_dispose_irq_mapping(pru);  	return 0;  } @@ -450,6 +473,24 @@ static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len)  	if (len == 0)  		return NULL; +	/* +	 * GNU binutils do not support multiple address spaces. The GNU +	 * linker's default linker script places IRAM at an arbitrary high +	 * offset, in order to differentiate it from DRAM. Hence we need to +	 * strip the artificial offset in the IRAM addresses coming from the +	 * ELF file. +	 * +	 * The TI proprietary linker would never set those higher IRAM address +	 * bits anyway. PRU architecture limits the program counter to 16-bit +	 * word-address range. This in turn corresponds to 18-bit IRAM +	 * byte-address range for ELF. +	 * +	 * Two more bits are added just in case to make the final 20-bit mask. +	 * Idea is to have a safeguard in case TI decides to add banking +	 * in future SoCs. +	 */ +	da &= 0xfffff; +  	if (da >= PRU_IRAM_DA &&  	    da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) {  		offset = da - PRU_IRAM_DA; @@ -465,7 +506,7 @@ static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len)   * core for any PRU client drivers. The PRU Instruction RAM access is restricted   * only to the PRU loader code.   */ -static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)  {  	struct pru_rproc *pru = rproc->priv; @@ -585,7 +626,7 @@ pru_rproc_load_elf_segments(struct rproc *rproc, const struct firmware *fw)  			break;  		} -		if (pru->data->is_k3 && is_iram) { +		if (pru->data->is_k3) {  			ret = pru_rproc_memcpy(ptr, elf_data + phdr->p_offset,  					       filesz);  			if (ret) { | 
