Esempio n. 1
0
static void get_cells(struct device_node *dp, int *addrc, int *sizec)
{
	if (addrc)
		*addrc = of_n_addr_cells(dp);
	if (sizec)
		*sizec = of_n_size_cells(dp);
}
Esempio n. 2
0
void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
		unsigned long *busno, unsigned long *phys, unsigned long *size)
{
	const u32 *dma_window;
	u32 cells;
	const unsigned char *prop;

	dma_window = dma_window_prop;

	/* busno is always one cell */
	*busno = *(dma_window++);

	prop = of_get_property(dn, "ibm,#dma-address-cells", NULL);
	if (!prop)
		prop = of_get_property(dn, "#address-cells", NULL);

	cells = prop ? *(u32 *)prop : of_n_addr_cells(dn);
	*phys = of_read_number(dma_window, cells);

	dma_window += cells;

	prop = of_get_property(dn, "ibm,#dma-size-cells", NULL);
	cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
	*size = of_read_number(dma_window, cells);
}
Esempio n. 3
0
static void of_bus_default_count_cells(struct device_node *dev,
				       int *addrc, int *sizec)
{
	if (addrc)
		*addrc = of_n_addr_cells(dev);
	if (sizec)
		*sizec = of_n_size_cells(dev);
}
static void hwadp_dts_register_base_addr(void)
{
	struct device_node *node = NULL, *np = NULL;
	int retval = 0;
	const char * nmi_node = "hisilicon,mdrv_nmi_interrupt_regs";
	unsigned int nmi_regs_val[NMI_INT_CORE_NUM] = {0,};

	node = of_find_compatible_node(NULL, NULL, "hisilicon,hardware_adapt");
	if (!node) {
		hwadp_printf("dts node not found!\n");
		return;
	}

	for_each_available_child_of_node(node, np)
	{
		unsigned int ip_type = ~0U, int_type = ~0U, irq_num = ~0U;
		int na = 0, ns = 0, len = 0;
		unsigned long base_addr = 0;
		const __be32 *prop = NULL;

		if(!np->name || !strlen(np->name))
			continue;

		/* try to obtain ip base address */
		na = of_n_addr_cells(np);
		ns = of_n_size_cells(np);
		prop = of_get_property(np, "reg", &len);
		retval = of_property_read_u32(np, "ip_type", &ip_type);
		if(prop && (len == (na + ns) * (int)sizeof(*prop)))
		{
			base_addr = (unsigned long)of_read_number(prop, na);
			if(base_addr && !(base_addr & ((0x1U << 12) - 1)))
				(void)of_iomap(np, 0);
			else
				hwadp_printf("hwad:reg addr = 0x%X Address of zero or that ones not aligned for page are not map!\n",base_addr);
			if(retval)
				ip_type = ~0U;
			retval = bsp_hwadp_register_base_addr(ip_type, (const char *)np->name, (void *)base_addr);
			if(retval)
				hwadp_printf("hwadp:failed to register base addr!ip_type=%d base_addr=%p name=%s\n",(int)ip_type, (void*)base_addr,np->name);
			continue;
		}

		/* try to obtain irq number */
		retval = of_property_read_u32_index(np, "interrupts", 1, &irq_num);
		if(retval)
			continue;

		retval = of_property_read_u32(np, "int_type", &int_type);
		if(retval)
			int_type = ~0U;

		if(bsp_hwadp_register_irq_num(int_type, (const char *)np->name, irq_num))
			hwadp_printf("hwadp:failed to register irq number!int_type=%d irq_num=%d name=%s\n", (int)int_type, irq_num, np->name);
	}
Esempio n. 5
0
File: numa.c Progetto: Gaffey/linux
static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
{
	struct device_node *memory = NULL;

	memory = of_find_node_by_type(memory, "memory");
	if (!memory)
		panic("numa.c: No memory nodes found!");

	*n_addr_cells = of_n_addr_cells(memory);
	*n_size_cells = of_n_size_cells(memory);
	of_node_put(memory);
}
Esempio n. 6
0
/**
 * of_get_dma_window - Parse *dma-window property and returns 0 if found.
 *
 * @dn: device node
 * @prefix: prefix for property name if any
 * @index: index to start to parse
 * @busno: Returns busno if supported. Otherwise pass NULL
 * @addr: Returns address that DMA starts
 * @size: Returns the range that DMA can handle
 *
 * This supports different formats flexibly. "prefix" can be
 * configured if any. "busno" and "index" are optionally
 * specified. Set 0(or NULL) if not used.
 */
int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
		      unsigned long *busno, dma_addr_t *addr, size_t *size)
{
	const __be32 *dma_window, *end;
	int bytes, cur_index = 0;
	char propname[NAME_MAX], addrname[NAME_MAX], sizename[NAME_MAX];

	if (!dn || !addr || !size)
		return -EINVAL;

	if (!prefix)
		prefix = "";

	snprintf(propname, sizeof(propname), "%sdma-window", prefix);
	snprintf(addrname, sizeof(addrname), "%s#dma-address-cells", prefix);
	snprintf(sizename, sizeof(sizename), "%s#dma-size-cells", prefix);

	dma_window = of_get_property(dn, propname, &bytes);
	if (!dma_window)
		return -ENODEV;
	end = dma_window + bytes / sizeof(*dma_window);

	while (dma_window < end) {
		u32 cells;
		const void *prop;

		/* busno is one cell if supported */
		if (busno)
			*busno = be32_to_cpup(dma_window++);

		prop = of_get_property(dn, addrname, NULL);
		if (!prop)
			prop = of_get_property(dn, "#address-cells", NULL);

		cells = prop ? be32_to_cpup(prop) : of_n_addr_cells(dn);
		if (!cells)
			return -EINVAL;
		*addr = of_read_number(dma_window, cells);
		dma_window += cells;

		prop = of_get_property(dn, sizename, NULL);
		cells = prop ? be32_to_cpup(prop) : of_n_size_cells(dn);
		if (!cells)
			return -EINVAL;
		*size = of_read_number(dma_window, cells);
		dma_window += cells;

		if (cur_index++ == index)
			break;
	}
	return 0;
}
Esempio n. 7
0
static int parse_mc_ranges(struct device *dev,
			   int *paddr_cells,
			   int *mc_addr_cells,
			   int *mc_size_cells,
			   const __be32 **ranges_start,
			   u8 *num_ranges)
{
	const __be32 *prop;
	int range_tuple_cell_count;
	int ranges_len;
	int tuple_len;
	struct device_node *mc_node = dev->of_node;

	*ranges_start = of_get_property(mc_node, "ranges", &ranges_len);
	if (!(*ranges_start) || !ranges_len) {
		dev_warn(dev,
			 "missing or empty ranges property for device tree node '%s'\n",
			 mc_node->name);

		*num_ranges = 0;
		return 0;
	}

	*paddr_cells = of_n_addr_cells(mc_node);

	prop = of_get_property(mc_node, "#address-cells", NULL);
	if (prop)
		*mc_addr_cells = be32_to_cpup(prop);
	else
		*mc_addr_cells = *paddr_cells;

	prop = of_get_property(mc_node, "#size-cells", NULL);
	if (prop)
		*mc_size_cells = be32_to_cpup(prop);
	else
		*mc_size_cells = of_n_size_cells(mc_node);

	range_tuple_cell_count = *paddr_cells + *mc_addr_cells +
				 *mc_size_cells;

	tuple_len = range_tuple_cell_count * sizeof(__be32);
	if (ranges_len % tuple_len != 0) {
		dev_err(dev, "malformed ranges property '%s'\n", mc_node->name);
		return -EINVAL;
	}

	*num_ranges = ranges_len / tuple_len;
	return 0;
}
Esempio n. 8
0
static int read_phys_addr(struct device_node *np, char *prop_name,
			struct cxl_afu *afu)
{
	int i, len, entry_size, naddr, nsize, type;
	u64 addr, size;
	const __be32 *prop;

	naddr = of_n_addr_cells(np);
	nsize = of_n_size_cells(np);

	prop = of_get_property(np, prop_name, &len);
	if (prop) {
		entry_size = naddr + nsize;
		for (i = 0; i < (len / 4); i += entry_size, prop += entry_size) {
			type = be32_to_cpu(prop[0]);
			addr = of_read_number(prop, naddr);
			size = of_read_number(&prop[naddr], nsize);
			switch (type) {
			case 0: /* unit address */
				afu->guest->handle = addr;
				break;
			case 1: /* p2 area */
				afu->guest->p2n_phys += addr;
				afu->guest->p2n_size = size;
				break;
			case 2: /* problem state area */
				afu->psn_phys += addr;
				afu->adapter->ps_size = size;
				break;
			default:
				pr_err("Invalid address type %d found in %s property of AFU\n",
					type, prop_name);
				return -EINVAL;
			}
			if (cxl_verbose)
				pr_info("%s: %#x %#llx (size %#llx)\n",
					prop_name, type, addr, size);
		}
	}
	return 0;
}
static int mnemosyne_parse_dt(struct device_node *node)
{
	phys_addr_t phys = 0, size = 0;
	struct device_node *pnode = NULL;
	int ret;

	pr_info("%s: init from device tree.\n", MNEMOSYNE_MODULE_NAME);

	if (node == NULL) {
		pr_err("%s: Can't find device_node", MNEMOSYNE_MODULE_NAME);
		ret = -ENODEV;
		goto PARSE_DT_ERR_OUT;
	}

	pnode = of_parse_phandle(node, "linux,contiguous-region", 0);
	if (!pnode) {
		pr_err("%s: mnemosyne memory is not reserved.\n", MNEMOSYNE_MODULE_NAME);
	} else {
		const __be32 *prop;
		int addr_cells, size_cells;
		prop = of_get_address(pnode, 0, NULL, NULL);
		if (!prop) {
			pr_err("%s: Can't find register property", MNEMOSYNE_MODULE_NAME);
			ret = -ENODEV;
			of_node_put(pnode);
			goto PARSE_DT_ERR_OUT;
		}
		of_node_put(pnode);

		addr_cells = of_n_addr_cells(pnode);
		size_cells = of_n_size_cells(pnode);

		phys = of_read_number(prop, addr_cells);
		size = of_read_number(prop + addr_cells, size_cells);
	}

	ret = mnemosyne_setup(phys, size);

PARSE_DT_ERR_OUT:
	return ret;
}
Esempio n. 10
0
static int __devinit of_flash_probe(struct platform_device *dev,
				    const struct of_device_id *match)
{
#ifdef CONFIG_MTD_PARTITIONS
	const char **part_probe_types;
#endif
	struct device_node *dp = dev->dev.of_node;
	struct resource res;
	struct of_flash *info;
	const char *probe_type = match->data;
	const u32 *width;
	int err;
	int i;
	int count;
	const u32 *p;
	int reg_tuple_size;
	struct mtd_info **mtd_list = NULL;
	resource_size_t res_size;

	reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);

	/*
	 * Get number of "reg" tuples. Scan for MTD devices on area's
	 * described by each "reg" region. This makes it possible (including
	 * the concat support) to support the Intel P30 48F4400 chips which
	 * consists internally of 2 non-identical NOR chips on one die.
	 */
	p = of_get_property(dp, "reg", &count);
	if (count % reg_tuple_size != 0) {
		dev_err(&dev->dev, "Malformed reg property on %s\n",
				dev->dev.of_node->full_name);
		err = -EINVAL;
		goto err_flash_remove;
	}
	count /= reg_tuple_size;

	err = -ENOMEM;
	info = kzalloc(sizeof(struct of_flash) +
		       sizeof(struct of_flash_list) * count, GFP_KERNEL);
	if (!info)
		goto err_flash_remove;

	dev_set_drvdata(&dev->dev, info);

	mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
	if (!mtd_list)
		goto err_flash_remove;

	for (i = 0; i < count; i++) {
		err = -ENXIO;
		if (of_address_to_resource(dp, i, &res)) {
			dev_err(&dev->dev, "Can't get IO address from device"
				" tree\n");
			goto err_out;
		}

		dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
			(unsigned long long)res.start,
			(unsigned long long)res.end);

		err = -EBUSY;
		res_size = resource_size(&res);
		info->list[i].res = request_mem_region(res.start, res_size,
						       dev_name(&dev->dev));
		if (!info->list[i].res)
			goto err_out;

		err = -ENXIO;
		width = of_get_property(dp, "bank-width", NULL);
		if (!width) {
			dev_err(&dev->dev, "Can't get bank width from device"
				" tree\n");
			goto err_out;
		}

		info->list[i].map.name = dev_name(&dev->dev);
		info->list[i].map.phys = res.start;
		info->list[i].map.size = res_size;
		info->list[i].map.bankwidth = *width;

		err = -ENOMEM;
		info->list[i].map.virt = ioremap(info->list[i].map.phys,
						 info->list[i].map.size);
		if (!info->list[i].map.virt) {
			dev_err(&dev->dev, "Failed to ioremap() flash"
				" region\n");
			goto err_out;
		}

		simple_map_init(&info->list[i].map);

		if (probe_type) {
			info->list[i].mtd = do_map_probe(probe_type,
							 &info->list[i].map);
		} else {
			info->list[i].mtd = obsolete_probe(dev,
							   &info->list[i].map);
		}
		mtd_list[i] = info->list[i].mtd;

		err = -ENXIO;
		if (!info->list[i].mtd) {
			dev_err(&dev->dev, "do_map_probe() failed\n");
			goto err_out;
		} else {
			info->list_size++;
		}
		info->list[i].mtd->owner = THIS_MODULE;
		info->list[i].mtd->dev.parent = &dev->dev;
	}

	err = 0;
	if (info->list_size == 1) {
		info->cmtd = info->list[0].mtd;
	} else if (info->list_size > 1) {
		/*
		 * We detected multiple devices. Concatenate them together.
		 */
#ifdef CONFIG_MTD_CONCAT
		info->cmtd = mtd_concat_create(mtd_list, info->list_size,
					       dev_name(&dev->dev));
		if (info->cmtd == NULL)
			err = -ENXIO;
#else
		printk(KERN_ERR "physmap_of: multiple devices "
		       "found but MTD concat support disabled.\n");
		err = -ENXIO;
#endif
	}
	if (err)
		goto err_out;

#ifdef CONFIG_MTD_PARTITIONS
	part_probe_types = of_get_probes(dp);
	err = parse_mtd_partitions(info->cmtd, part_probe_types,
				   &info->parts, 0);
	if (err < 0) {
		of_free_probes(part_probe_types);
		goto err_out;
	}
	of_free_probes(part_probe_types);

#ifdef CONFIG_MTD_OF_PARTS
	if (err == 0) {
		err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
		if (err < 0)
			goto err_out;
	}
#endif

	if (err == 0) {
		err = parse_obsolete_partitions(dev, info, dp);
		if (err < 0)
			goto err_out;
	}

	if (err > 0)
		add_mtd_partitions(info->cmtd, info->parts, err);
	else
#endif
		add_mtd_device(info->cmtd);

	kfree(mtd_list);

	return 0;

err_out:
	kfree(mtd_list);
err_flash_remove:
	of_flash_remove(dev);

	return err;
}
Esempio n. 11
0
static int parse_ofpart_partitions(struct mtd_info *master,
				   struct mtd_partition **pparts,
				   struct mtd_part_parser_data *data)
{
	struct device_node *node;
	const char *partname;
	struct device_node *pp;
	int nr_parts, i;


	if (!data)
		return 0;

	node = data->of_node;
	if (!node)
		return 0;

	/* First count the subnodes */
	nr_parts = 0;
	for_each_child_of_node(node,  pp) {
		if (node_has_compatible(pp))
			continue;

		nr_parts++;
	}

	if (nr_parts == 0)
		return 0;

	*pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
	if (!*pparts)
		return -ENOMEM;

	i = 0;
	for_each_child_of_node(node,  pp) {
		const __be32 *reg;
		int len;
		int a_cells, s_cells;

		if (node_has_compatible(pp))
			continue;

		reg = of_get_property(pp, "reg", &len);
		if (!reg) {
			nr_parts--;
			continue;
		}

		a_cells = of_n_addr_cells(pp);
		s_cells = of_n_size_cells(pp);
		(*pparts)[i].offset = of_read_number(reg, a_cells);
		(*pparts)[i].size = of_read_number(reg + a_cells, s_cells);

		partname = of_get_property(pp, "label", &len);
		if (!partname)
			partname = of_get_property(pp, "name", &len);
		(*pparts)[i].name = (char *)partname;

		if (of_get_property(pp, "read-only", &len))
			(*pparts)[i].mask_flags |= MTD_WRITEABLE;

		if (of_get_property(pp, "lock", &len))
			(*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;

		i++;
	}

	if (!i) {
		of_node_put(pp);
		pr_err("No valid partition found on %s\n", node->full_name);
		kfree(*pparts);
		*pparts = NULL;
		return -EINVAL;
	}

	return nr_parts;
}
Esempio n. 12
0
static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
{
	struct platform_device *pdev_parent = of_find_device_by_node(np);
	struct platform_device_info pdevinfo;
	struct of_phandle_args out_irq;
	struct device_node *child;
	struct resource *res;
	const __be32 *cell;
	int ret = 0, size, i, num;
	u64 addr, addr_size;

	for_each_available_child_of_node(np, child) {
		struct resource *res_iter;
		struct platform_device *new_pdev;

		cell = of_get_property(child, "reg", &size);
		if (!cell) {
			ret = -EINVAL;
			goto out;
		}

		size /= sizeof(*cell);
		num = size /
			(of_n_addr_cells(child) + of_n_size_cells(child)) + 1;

		/* allocate a resource array */
		res = kcalloc(num, sizeof(*res), GFP_KERNEL);
		if (!res) {
			ret = -ENOMEM;
			goto out;
		}

		/* read each reg value */
		i = 0;
		res_iter = res;
		while (i < size) {
			addr = of_read_number(&cell[i],
					      of_n_addr_cells(child));
			i += of_n_addr_cells(child);

			addr_size = of_read_number(&cell[i],
						   of_n_size_cells(child));
			i += of_n_size_cells(child);

			res_iter->start = addr;
			res_iter->end = res_iter->start + addr_size - 1;
			res_iter->flags = IORESOURCE_MEM;
			res_iter++;
		}

		ret = of_irq_parse_one(child, 0, &out_irq);
		if (ret)
			goto out;

		res_iter->start = irq_create_of_mapping(&out_irq);
		res_iter->name = "hidma event irq";
		res_iter->flags = IORESOURCE_IRQ;

		memset(&pdevinfo, 0, sizeof(pdevinfo));
		pdevinfo.fwnode = &child->fwnode;
		pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL;
		pdevinfo.name = child->name;
		pdevinfo.id = object_counter++;
		pdevinfo.res = res;
		pdevinfo.num_res = num;
		pdevinfo.data = NULL;
		pdevinfo.size_data = 0;
		pdevinfo.dma_mask = DMA_BIT_MASK(64);
		new_pdev = platform_device_register_full(&pdevinfo);
		if (IS_ERR(new_pdev)) {
			ret = PTR_ERR(new_pdev);
			goto out;
		}
		of_node_get(child);
		new_pdev->dev.of_node = child;
		of_dma_configure(&new_pdev->dev, child);
		/*
		 * It is assumed that calling of_msi_configure is safe on
		 * platforms with or without MSI support.
		 */
		of_msi_configure(&new_pdev->dev, child);
		of_node_put(child);
		kfree(res);
		res = NULL;
	}
out:
	kfree(res);

	return ret;
}
Esempio n. 13
0
static int parse_ofpart_partitions(struct mtd_info *master,
				   struct mtd_partition **pparts,
				   struct mtd_part_parser_data *data)
{
	struct device_node *mtd_node;
	struct device_node *ofpart_node;
	const char *partname;
	struct device_node *pp;
	int nr_parts, i, ret = 0;
	bool dedicated = true;


	if (!data)
		return 0;

	mtd_node = data->of_node;
	if (!mtd_node)
		return 0;

	ofpart_node = of_get_child_by_name(mtd_node, "partitions");
	if (!ofpart_node) {
		pr_warn("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n",
			master->name, mtd_node->full_name);
		ofpart_node = mtd_node;
		dedicated = false;
	}

	/* First count the subnodes */
	nr_parts = 0;
	for_each_child_of_node(ofpart_node,  pp) {
		if (!dedicated && node_has_compatible(pp))
			continue;

		nr_parts++;
	}

	if (nr_parts == 0)
		return 0;

	*pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
	if (!*pparts)
		return -ENOMEM;

	i = 0;
	for_each_child_of_node(ofpart_node,  pp) {
		const __be32 *reg;
		int len;
		int a_cells, s_cells;

		if (!dedicated && node_has_compatible(pp))
			continue;

		reg = of_get_property(pp, "reg", &len);
		if (!reg) {
			if (dedicated) {
				pr_debug("%s: ofpart partition %s (%s) missing reg property.\n",
					 master->name, pp->full_name,
					 mtd_node->full_name);
				goto ofpart_fail;
			} else {
				nr_parts--;
				continue;
			}
		}

		a_cells = of_n_addr_cells(pp);
		s_cells = of_n_size_cells(pp);
		if (len / 4 != a_cells + s_cells) {
			pr_debug("%s: ofpart partition %s (%s) error parsing reg property.\n",
				 master->name, pp->full_name,
				 mtd_node->full_name);
			goto ofpart_fail;
		}

		(*pparts)[i].offset = of_read_number(reg, a_cells);
		(*pparts)[i].size = of_read_number(reg + a_cells, s_cells);

		partname = of_get_property(pp, "label", &len);
		if (!partname)
			partname = of_get_property(pp, "name", &len);
		(*pparts)[i].name = partname;

		if (of_get_property(pp, "read-only", &len))
			(*pparts)[i].mask_flags |= MTD_WRITEABLE;

		if (of_get_property(pp, "lock", &len))
			(*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;

		i++;
	}

	if (!nr_parts)
		goto ofpart_none;

	return nr_parts;

ofpart_fail:
	pr_err("%s: error parsing ofpart partition %s (%s)\n",
	       master->name, pp->full_name, mtd_node->full_name);
	ret = -EINVAL;
ofpart_none:
	of_node_put(pp);
	kfree(*pparts);
	*pparts = NULL;
	return ret;
}
Esempio n. 14
0
struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
dpa_bp_probe(struct platform_device *_of_dev, size_t *count)
{
	int			 i, lenp, na, ns;
	struct device		*dev;
	struct device_node	*dev_node;
	const phandle		*phandle_prop;
	const uint32_t		*bpid;
	const uint32_t		*bpool_cfg;
	struct dpa_bp		*dpa_bp;

	dev = &_of_dev->dev;

	/* The default is one, if there's no property */
	*count = 1;

	/* Get the buffer pools to be used */
	phandle_prop = of_get_property(dev->of_node,
					"fsl,bman-buffer-pools", &lenp);

	if (phandle_prop)
		*count = lenp / sizeof(phandle);
	else {
		dev_err(dev,
			"missing fsl,bman-buffer-pools device tree entry\n");
		return ERR_PTR(-EINVAL);
	}

	dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL);
	if (unlikely(dpa_bp == NULL)) {
		dev_err(dev, "devm_kzalloc() failed\n");
		return ERR_PTR(-ENOMEM);
	}

	dev_node = of_find_node_by_path("/");
	if (unlikely(dev_node == NULL)) {
		dev_err(dev, "of_find_node_by_path(/) failed\n");
		return ERR_PTR(-EINVAL);
	}

	na = of_n_addr_cells(dev_node);
	ns = of_n_size_cells(dev_node);

	for (i = 0; i < *count && phandle_prop; i++) {
		of_node_put(dev_node);
		dev_node = of_find_node_by_phandle(phandle_prop[i]);
		if (unlikely(dev_node == NULL)) {
			dev_err(dev, "of_find_node_by_phandle() failed\n");
			return ERR_PTR(-EFAULT);
		}

		if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) {
			dev_err(dev,
				"!of_device_is_compatible(%s, fsl,bpool)\n",
				dev_node->full_name);
			dpa_bp = ERR_PTR(-EINVAL);
			goto _return_of_node_put;
		}

		bpid = of_get_property(dev_node, "fsl,bpid", &lenp);
		if ((bpid == NULL) || (lenp != sizeof(*bpid))) {
			dev_err(dev, "fsl,bpid property not found.\n");
			dpa_bp = ERR_PTR(-EINVAL);
			goto _return_of_node_put;
		}
		dpa_bp[i].bpid = *bpid;

		bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg",
					&lenp);
		if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) {
			const uint32_t *seed_pool;

			dpa_bp[i].config_count =
				(int)of_read_number(bpool_cfg, ns);
			dpa_bp[i].size	= of_read_number(bpool_cfg + ns, ns);
			dpa_bp[i].paddr	=
				of_read_number(bpool_cfg + 2 * ns, na);

			seed_pool = of_get_property(dev_node,
					"fsl,bpool-ethernet-seeds", &lenp);
			dpa_bp[i].seed_pool = !!seed_pool;

		} else {
			dev_err(dev,
				"Missing/invalid fsl,bpool-ethernet-cfg device tree entry for node %s\n",
				dev_node->full_name);
			dpa_bp = ERR_PTR(-EINVAL);
			goto _return_of_node_put;
		}
	}

	sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL);

	return dpa_bp;

_return_of_node_put:
	if (dev_node)
		of_node_put(dev_node);

	return dpa_bp;
}
Esempio n. 15
0
static int of_flash_probe(struct platform_device *dev)
{
	const char * const *part_probe_types;
	const struct of_device_id *match;
	struct device_node *dp = dev->dev.of_node;
	struct resource res;
	struct of_flash *info;
	const char *probe_type;
	const __be32 *width;
	int err;
	int i;
	int count;
	const __be32 *p;
	int reg_tuple_size;
	struct mtd_info **mtd_list = NULL;
	resource_size_t res_size;
	struct mtd_part_parser_data ppdata;
	bool map_indirect;
	const char *mtd_name = NULL;

	match = of_match_device(of_flash_match, &dev->dev);
	if (!match)
		return -EINVAL;
	probe_type = match->data;

	reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);

	of_property_read_string(dp, "linux,mtd-name", &mtd_name);

	/*
	 * Get number of "reg" tuples. Scan for MTD devices on area's
	 * described by each "reg" region. This makes it possible (including
	 * the concat support) to support the Intel P30 48F4400 chips which
	 * consists internally of 2 non-identical NOR chips on one die.
	 */
	p = of_get_property(dp, "reg", &count);
	if (count % reg_tuple_size != 0) {
		dev_err(&dev->dev, "Malformed reg property on %s\n",
				dev->dev.of_node->full_name);
		err = -EINVAL;
		goto err_flash_remove;
	}
	count /= reg_tuple_size;

	map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");

	err = -ENOMEM;
	info = devm_kzalloc(&dev->dev,
			    sizeof(struct of_flash) +
			    sizeof(struct of_flash_list) * count, GFP_KERNEL);
	if (!info)
		goto err_flash_remove;

	dev_set_drvdata(&dev->dev, info);

	mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
	if (!mtd_list)
		goto err_flash_remove;

	for (i = 0; i < count; i++) {
		err = -ENXIO;
		if (of_address_to_resource(dp, i, &res)) {
			/*
			 * Continue with next register tuple if this
			 * one is not mappable
			 */
			continue;
		}

		dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);

		err = -EBUSY;
		res_size = resource_size(&res);
		info->list[i].res = request_mem_region(res.start, res_size,
						       dev_name(&dev->dev));
		if (!info->list[i].res)
			goto err_out;

		err = -ENXIO;
		width = of_get_property(dp, "bank-width", NULL);
		if (!width) {
			dev_err(&dev->dev, "Can't get bank width from device"
				" tree\n");
			goto err_out;
		}

		info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
		info->list[i].map.phys = res.start;
		info->list[i].map.size = res_size;
		info->list[i].map.bankwidth = be32_to_cpup(width);
		info->list[i].map.device_node = dp;

		err = -ENOMEM;
		info->list[i].map.virt = ioremap(info->list[i].map.phys,
						 info->list[i].map.size);
		if (!info->list[i].map.virt) {
			dev_err(&dev->dev, "Failed to ioremap() flash"
				" region\n");
			goto err_out;
		}

		simple_map_init(&info->list[i].map);

		/*
		 * On some platforms (e.g. MPC5200) a direct 1:1 mapping
		 * may cause problems with JFFS2 usage, as the local bus (LPB)
		 * doesn't support unaligned accesses as implemented in the
		 * JFFS2 code via memcpy(). By setting NO_XIP, the
		 * flash will not be exposed directly to the MTD users
		 * (e.g. JFFS2) any more.
		 */
		if (map_indirect)
			info->list[i].map.phys = NO_XIP;

		if (probe_type) {
			info->list[i].mtd = do_map_probe(probe_type,
							 &info->list[i].map);
		} else {
			info->list[i].mtd = obsolete_probe(dev,
							   &info->list[i].map);
		}
		mtd_list[i] = info->list[i].mtd;

		err = -ENXIO;
		if (!info->list[i].mtd) {
			dev_err(&dev->dev, "do_map_probe() failed\n");
			goto err_out;
		} else {
			info->list_size++;
		}
		info->list[i].mtd->owner = THIS_MODULE;
		info->list[i].mtd->dev.parent = &dev->dev;
	}

	err = 0;
	info->cmtd = NULL;
	if (info->list_size == 1) {
		info->cmtd = info->list[0].mtd;
	} else if (info->list_size > 1) {
		/*
		 * We detected multiple devices. Concatenate them together.
		 */
		info->cmtd = mtd_concat_create(mtd_list, info->list_size,
					       dev_name(&dev->dev));
	}
	if (info->cmtd == NULL)
		err = -ENXIO;

	if (err)
		goto err_out;

	ppdata.of_node = dp;
	part_probe_types = of_get_probes(dp);
	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
			NULL, 0);
	of_free_probes(part_probe_types);

	kfree(mtd_list);

	return 0;

err_out:
	kfree(mtd_list);
err_flash_remove:
	of_flash_remove(dev);

	return err;
}
Esempio n. 16
0
/**
 * of_dma_get_range - Get DMA range info
 * @np:		device node to get DMA range info
 * @dma_addr:	pointer to store initial DMA address of DMA range
 * @paddr:	pointer to store initial CPU address of DMA range
 * @size:	pointer to store size of DMA range
 *
 * Look in bottom up direction for the first "dma-ranges" property
 * and parse it.
 *  dma-ranges format:
 *	DMA addr (dma_addr)	: naddr cells
 *	CPU addr (phys_addr_t)	: pna cells
 *	size			: nsize cells
 *
 * It returns -ENODEV if "dma-ranges" property was not found
 * for this device in DT.
 */
int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size)
{
	struct device_node *node = of_node_get(np);
	const __be32 *ranges = NULL;
	int len, naddr, nsize, pna;
	int ret = 0;
	u64 dmaaddr;

	if (!node)
		return -EINVAL;

	while (1) {
		naddr = of_n_addr_cells(node);
		nsize = of_n_size_cells(node);
		node = of_get_next_parent(node);
		if (!node)
			break;

		ranges = of_get_property(node, "dma-ranges", &len);

		/* Ignore empty ranges, they imply no translation required */
		if (ranges && len > 0)
			break;

		/*
		 * At least empty ranges has to be defined for parent node if
		 * DMA is supported
		 */
		if (!ranges)
			break;
	}

	if (!ranges) {
		pr_debug("no dma-ranges found for node(%pOF)\n", np);
		ret = -ENODEV;
		goto out;
	}

	len /= sizeof(u32);

	pna = of_n_addr_cells(node);

	/* dma-ranges format:
	 * DMA addr	: naddr cells
	 * CPU addr	: pna cells
	 * size		: nsize cells
	 */
	dmaaddr = of_read_number(ranges, naddr);
	*paddr = of_translate_dma_address(np, ranges);
	if (*paddr == OF_BAD_ADDR) {
		pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
		       dma_addr, np);
		ret = -EINVAL;
		goto out;
	}
	*dma_addr = dmaaddr;

	*size = of_read_number(ranges + naddr + pna, nsize);

	pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
		 *dma_addr, *paddr, *size);

out:
	of_node_put(node);

	return ret;
}
Esempio n. 17
0
static int
oh_port_probe(struct platform_device *_of_dev)
{
	struct device		*dpa_oh_dev;
	struct device_node	*dpa_oh_node;
	int			 lenp, _errno = 0, fq_idx, n_size, i, ret;
	const phandle		*oh_port_handle, *bpool_handle;
	struct platform_device	*oh_of_dev;
	struct device_node	*oh_node, *bpool_node = NULL, *root_node;
	struct device		*oh_dev;
	struct dpa_oh_config_s	*oh_config = NULL;
	uint32_t		*oh_all_queues;
	uint32_t		*oh_tx_queues;
	uint32_t		 queues_count;
	uint32_t		 crt_fqid_base;
	uint32_t		 crt_fq_count;
	bool			frag_enabled = false;
	struct fm_port_params	oh_port_tx_params;
	struct fm_port_pcd_param	oh_port_pcd_params;
	struct dpa_buffer_layout_s buf_layout;
	/* True if the current partition owns the OH port. */
	bool init_oh_port;
	const struct of_device_id *match;
	uint32_t crt_ext_pools_count, ext_pool_size;
	const unsigned int *port_id;
	const unsigned int *channel_id;
	const uint32_t		*bpool_cfg;
	const uint32_t		*bpid;

	memset(&oh_port_tx_params, 0, sizeof(oh_port_tx_params));
	dpa_oh_dev = &_of_dev->dev;
	dpa_oh_node = dpa_oh_dev->of_node;
	BUG_ON(dpa_oh_node == NULL);

	match = of_match_device(oh_port_match_table, dpa_oh_dev);
	if (!match)
		return -EINVAL;

	dev_dbg(dpa_oh_dev, "Probing OH port...\n");

	/*
	 * Find the referenced OH node
	 */

	oh_port_handle = of_get_property(dpa_oh_node,
		"fsl,fman-oh-port", &lenp);
	if (oh_port_handle == NULL) {
		dev_err(dpa_oh_dev, "No OH port handle found in node %s\n",
			dpa_oh_node->full_name);
		return -EINVAL;
	}

	BUG_ON(lenp % sizeof(*oh_port_handle));
	if (lenp != sizeof(*oh_port_handle)) {
		dev_err(dpa_oh_dev, "Found %lu OH port bindings in node %s,"
			" only 1 phandle is allowed.\n",
			(unsigned long int)(lenp / sizeof(*oh_port_handle)),
			dpa_oh_node->full_name);
		return -EINVAL;
	}

	/* Read configuration for the OH port */
	oh_node = of_find_node_by_phandle(*oh_port_handle);
	if (oh_node == NULL) {
		dev_err(dpa_oh_dev, "Can't find OH node referenced from "
			"node %s\n", dpa_oh_node->full_name);
		return -EINVAL;
	}
	dev_info(dpa_oh_dev, "Found OH node handle compatible with %s.\n",
		match->compatible);

	port_id = of_get_property(oh_node, "cell-index", &lenp);

	if (port_id == NULL) {
		dev_err(dpa_oh_dev, "No port id found in node %s\n",
			dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	BUG_ON(lenp % sizeof(*port_id));

	oh_of_dev = of_find_device_by_node(oh_node);
	BUG_ON(oh_of_dev == NULL);
	oh_dev = &oh_of_dev->dev;

	/*
	 * The OH port must be initialized exactly once.
	 * The following scenarios are of interest:
	 *	- the node is Linux-private (will always initialize it);
	 *	- the node is shared between two Linux partitions
	 *	  (only one of them will initialize it);
	 *	- the node is shared between a Linux and a LWE partition
	 *	  (Linux will initialize it) - "fsl,dpa-oh-shared"
	 */

	/* Check if the current partition owns the OH port
	 * and ought to initialize it. It may be the case that we leave this
	 * to another (also Linux) partition. */
	init_oh_port = strcmp(match->compatible, "fsl,dpa-oh-shared");

	/* If we aren't the "owner" of the OH node, we're done here. */
	if (!init_oh_port) {
		dev_dbg(dpa_oh_dev, "Not owning the shared OH port %s, "
			"will not initialize it.\n", oh_node->full_name);
		of_node_put(oh_node);
		return 0;
	}

	/* Allocate OH dev private data */
	oh_config = devm_kzalloc(dpa_oh_dev, sizeof(*oh_config), GFP_KERNEL);
	if (oh_config == NULL) {
		dev_err(dpa_oh_dev, "Can't allocate private data for "
			"OH node %s referenced from node %s!\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -ENOMEM;
		goto return_kfree;
	}

	/*
	 * Read FQ ids/nums for the DPA OH node
	 */
	oh_all_queues = (uint32_t *)of_get_property(dpa_oh_node,
		"fsl,qman-frame-queues-oh", &lenp);
	if (oh_all_queues == NULL) {
		dev_err(dpa_oh_dev, "No frame queues have been "
			"defined for OH node %s referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	/* Check that the OH error and default FQs are there */
	BUG_ON(lenp % (2 * sizeof(*oh_all_queues)));
	queues_count = lenp / (2 * sizeof(*oh_all_queues));
	if (queues_count != 2) {
		dev_err(dpa_oh_dev, "Error and Default queues must be "
			"defined for OH node %s referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	/* Read the FQIDs defined for this OH port */
	dev_dbg(dpa_oh_dev, "Reading %d queues...\n", queues_count);
	fq_idx = 0;

	/* Error FQID - must be present */
	crt_fqid_base = oh_all_queues[fq_idx++];
	crt_fq_count = oh_all_queues[fq_idx++];
	if (crt_fq_count != 1) {
		dev_err(dpa_oh_dev, "Only 1 Error FQ allowed in OH node %s "
			"referenced from node %s (read: %d FQIDs).\n",
			oh_node->full_name, dpa_oh_node->full_name,
			crt_fq_count);
		_errno = -EINVAL;
		goto return_kfree;
	}
	oh_config->error_fqid = crt_fqid_base;
	dev_dbg(dpa_oh_dev, "Read Error FQID 0x%x for OH port %s.\n",
		oh_config->error_fqid, oh_node->full_name);

	/* Default FQID - must be present */
	crt_fqid_base = oh_all_queues[fq_idx++];
	crt_fq_count = oh_all_queues[fq_idx++];
	if (crt_fq_count != 1) {
		dev_err(dpa_oh_dev, "Only 1 Default FQ allowed "
			"in OH node %s referenced from %s (read: %d FQIDs).\n",
			oh_node->full_name, dpa_oh_node->full_name,
			crt_fq_count);
		_errno = -EINVAL;
		goto return_kfree;
	}
	oh_config->default_fqid = crt_fqid_base;
	dev_dbg(dpa_oh_dev, "Read Default FQID 0x%x for OH port %s.\n",
		oh_config->default_fqid, oh_node->full_name);

	/* TX FQID - presence is optional */
	oh_tx_queues = (uint32_t *)of_get_property(dpa_oh_node,
		"fsl,qman-frame-queues-tx", &lenp);
	if (oh_tx_queues == NULL) {
		dev_dbg(dpa_oh_dev, "No tx queues have been "
		"defined for OH node %s referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		goto config_port;
	}

	/* Check that queues-tx has only a base and a count defined */
	BUG_ON(lenp % (2 * sizeof(*oh_tx_queues)));
	queues_count = lenp / (2 * sizeof(*oh_tx_queues));
	if (queues_count != 1) {
		dev_err(dpa_oh_dev, "TX queues must be defined in"
			"only one <base count> tuple for OH node %s "
			"referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	/* Read channel id for the queues */
	channel_id = of_get_property(oh_node, "fsl,qman-channel-id", &lenp);
	if (channel_id == NULL) {
		dev_err(dpa_oh_dev, "No channel id found in node %s\n",
			dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}
	BUG_ON(lenp % sizeof(*channel_id));

	fq_idx = 0;
	crt_fqid_base = oh_tx_queues[fq_idx++];
	crt_fq_count = oh_tx_queues[fq_idx++];
	oh_config->egress_cnt = crt_fq_count;

	/* Allocate TX queues */
	dev_dbg(dpa_oh_dev, "Allocating %d queues for TX...\n", crt_fq_count);
	oh_config->egress_fqs = devm_kzalloc(dpa_oh_dev,
		crt_fq_count * sizeof(struct qman_fq), GFP_KERNEL);
	if (oh_config->egress_fqs == NULL) {
		dev_err(dpa_oh_dev, "Can't allocate private data for "
			"TX queues for OH node %s referenced from node %s!\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -ENOMEM;
		goto return_kfree;
	}

	/* Create TX queues */
	for (i = 0; i < crt_fq_count; i++) {
		ret = oh_fq_create(oh_config->egress_fqs + i,
			crt_fqid_base + i, *channel_id, 3);
		if (ret != 0) {
			dev_err(dpa_oh_dev, "Unable to create TX frame "
				"queue %d for OH node %s referenced "
				"from node %s!\n",
				crt_fqid_base + i, oh_node->full_name,
				dpa_oh_node->full_name);
			_errno = -EINVAL;
			goto return_kfree;
		}
	}

config_port:
	/* Get a handle to the fm_port so we can set
	 * its configuration params */
	oh_config->oh_port = fm_port_bind(oh_dev);
	if (oh_config->oh_port == NULL) {
		dev_err(dpa_oh_dev, "NULL drvdata from fm port dev %s!\n",
			oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	oh_set_buffer_layout(oh_config->oh_port, &buf_layout);
	bpool_handle = of_get_property(dpa_oh_node,
			"fsl,bman-buffer-pools", &lenp);

	if (bpool_handle == NULL) {
		dev_info(dpa_oh_dev, "OH port %s has no buffer pool. Fragmentation will not be enabled\n",
			oh_node->full_name);
		goto init_port;
	}

	/* used for reading ext_pool_size*/
	root_node = of_find_node_by_path("/");
	if (root_node == NULL) {
		dev_err(dpa_oh_dev, "of_find_node_by_path(/) failed\n");
		_errno = -EINVAL;
		goto return_kfree;
	}

	n_size = of_n_size_cells(root_node);
	of_node_put(root_node);

	crt_ext_pools_count = lenp / sizeof(phandle);
	dev_dbg(dpa_oh_dev, "OH port number of pools = %u\n",
					crt_ext_pools_count);

	oh_port_tx_params.num_pools = crt_ext_pools_count;

	for (i = 0; i < crt_ext_pools_count; i++) {
		bpool_node = of_find_node_by_phandle(bpool_handle[i]);
		if (bpool_node == NULL) {
			dev_err(dpa_oh_dev, "Invalid Buffer pool node\n");
			_errno = -EINVAL;
			goto return_kfree;
		}

		bpid = of_get_property(bpool_node, "fsl,bpid", &lenp);
		if ((bpid == NULL) || (lenp != sizeof(*bpid))) {
			dev_err(dpa_oh_dev, "Invalid Buffer pool Id\n");
			_errno = -EINVAL;
			goto return_kfree;
		}

		oh_port_tx_params.pool_param[i].id = *bpid;
		dev_dbg(dpa_oh_dev, "OH port bpool id = %u\n", *bpid);

		bpool_cfg = of_get_property(bpool_node,
				"fsl,bpool-ethernet-cfg", &lenp);
		if (bpool_cfg == NULL) {
			dev_err(dpa_oh_dev, "Invalid Buffer pool config params\n");
			_errno = -EINVAL;
			goto return_kfree;
		}

		of_read_number(bpool_cfg, n_size);
		ext_pool_size = of_read_number(bpool_cfg + n_size, n_size);
		oh_port_tx_params.pool_param[i].size = ext_pool_size;
		dev_dbg(dpa_oh_dev, "OH port bpool size = %u\n",
			ext_pool_size);
		of_node_put(bpool_node);

	}

	if (buf_layout.data_align != FRAG_DATA_ALIGN ||
	    buf_layout.manip_extra_space != FRAG_MANIP_SPACE)
		goto init_port;

	frag_enabled = true;
	dev_info(dpa_oh_dev, "IP Fragmentation enabled for OH port %d",
		     *port_id);

init_port:
	of_node_put(oh_node);
	/* Set Tx params */
	dpaa_eth_init_port(tx, oh_config->oh_port, oh_port_tx_params,
		oh_config->error_fqid, oh_config->default_fqid, (&buf_layout),
		frag_enabled);
	/* Set PCD params */
	oh_port_pcd_params.cba = oh_alloc_pcd_fqids;
	oh_port_pcd_params.cbf = oh_free_pcd_fqids;
	oh_port_pcd_params.dev = dpa_oh_dev;
	fm_port_pcd_bind(oh_config->oh_port, &oh_port_pcd_params);

	dev_set_drvdata(dpa_oh_dev, oh_config);

	/* Enable the OH port */
	_errno = fm_port_enable(oh_config->oh_port);
	if (_errno)
		goto return_kfree;

	dev_info(dpa_oh_dev, "OH port %s enabled.\n", oh_node->full_name);

	return 0;

return_kfree:
	if (bpool_node)
		of_node_put(bpool_node);
	if (oh_node)
		of_node_put(oh_node);
	if (oh_config && oh_config->egress_fqs)
		devm_kfree(dpa_oh_dev, oh_config->egress_fqs);
	devm_kfree(dpa_oh_dev, oh_config);
	return _errno;
}