drivers/of/device.c

Source file repositories/reference/linux-study-clean/drivers/of/device.c

File Facts

System
Linux kernel
Corpus path
drivers/of/device.c
Extension
.c
Size
8879 bytes
Lines
316
Domain
Driver Families
Bucket
drivers/of
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

of_device_is_available(it.node)) {
			if (of_reserved_mem_device_init_by_idx(dev, of_node, i))
				dev_warn(dev, "failed to initialise \"restricted-dma-pool\" memory node\n");
			of_node_put(it.node);
			break;
		}
		i++;
	}

}

/**
 * of_dma_configure_id - Setup DMA configuration
 * @dev:	Device to apply DMA configuration
 * @np:		Pointer to OF node having DMA configuration
 * @force_dma:  Whether device is to be set up by of_dma_configure() even if
 *		DMA capability is not explicitly described by firmware.
 * @id:		Optional const pointer value input id
 *
 * Try to get devices's DMA configuration from DT and update it
 * accordingly.
 *
 * If platform code needs to use its own special DMA configuration, it
 * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events
 * to fix up DMA configuration.
 */
int of_dma_configure_id(struct device *dev, struct device_node *np,
			bool force_dma, const u32 *id)
{
	const struct bus_dma_region *map = NULL;
	struct device_node *bus_np;
	u64 mask, end = 0;
	bool coherent, set_map = false;
	int ret;

	if (dev->dma_range_map) {
		dev_dbg(dev, "dma_range_map already set\n");
		goto skip_map;
	}

	if (np == dev->of_node)
		bus_np = __of_get_dma_parent(np);
	else
		bus_np = of_node_get(np);

	ret = of_dma_get_range(bus_np, &map);
	of_node_put(bus_np);
	if (ret < 0) {
		/*
		 * For legacy reasons, we have to assume some devices need
		 * DMA configuration regardless of whether "dma-ranges" is
		 * correctly specified or not.
		 */
		if (!force_dma)
			return ret == -ENODEV ? 0 : ret;
	} else {
		/* Determine the overall bounds of all DMA regions */
		end = dma_range_map_max(map);
		set_map = true;
	}
skip_map:
	/*
	 * If @dev is expected to be DMA-capable then the bus code that created
	 * it should have initialised its dma_mask pointer by this point. For
	 * now, we'll continue the legacy behaviour of coercing it to the
	 * coherent mask if not, but we'll no longer do so quietly.
	 */
	if (!dev->dma_mask) {
		dev_warn(dev, "DMA mask not set\n");
		dev->dma_mask = &dev->coherent_dma_mask;
	}

	if (!end && dev->coherent_dma_mask)
		end = dev->coherent_dma_mask;
	else if (!end)
		end = (1ULL << 32) - 1;

	/*
	 * Limit coherent and dma mask based on size and default mask
	 * set by the driver.
	 */
	mask = DMA_BIT_MASK(ilog2(end) + 1);
	dev->coherent_dma_mask &= mask;
	*dev->dma_mask &= mask;
	/* ...but only set bus limit and range map if we found valid dma-ranges earlier */
	if (set_map) {
		dev->bus_dma_limit = end;
		dev->dma_range_map = map;
	}

Annotation

Implementation Notes