PCI设备: 

coherent_dma_mask :用来分配连续一致性dma。

dma_mask:在dma_map_single->dma_map_page,dma_capable用。

先看默认设置。后续可以通过pci_set_dma_mask/pci_set_consistent_dma_mask分别设置

设置: 

int pci_setup_device(struct pci_dev *dev)
{
        u32 class;
        u16 cmd;
        u8 hdr_type;
        int pos = 0;
        struct pci_bus_region region;
        struct resource *res;

        hdr_type = pci_hdr_type(dev);

        dev->sysdata = dev->bus->sysdata;
        dev->dev.parent = dev->bus->bridge;
        dev->dev.bus = &pci_bus_type;
        dev->hdr_type = hdr_type & 0x7f;
        dev->multifunction = !!(hdr_type & 0x80);
        dev->error_state = pci_channel_io_normal;
        set_pcie_port_type(dev);

        pci_dev_assign_slot(dev);

        /*
         * Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
         * set this higher, assuming the system even supports it.
         */
        dev->dma_mask = 0xffffffff;  //默认设置4G

....


}
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
        int ret;

        pci_configure_device(dev);

        device_initialize(&dev->dev);
        dev->dev.release = pci_release_dev;

        set_dev_node(&dev->dev, pcibus_to_node(bus));
        dev->dev.dma_mask = &dev->dma_mask;
        dev->dev.dma_parms = &dev->dma_parms;
        dev->dev.coherent_dma_mask = 0xffffffffull;  //默认设置4G

......

}

platform设备:acpi创建platform_device_info 数据,创建platform_device

drivers/acpi/acpi_platform.c:

struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
					struct property_entry *properties)
{
	struct platform_device *pdev = NULL;
	struct platform_device_info pdevinfo;
	struct resource_entry *rentry;
	struct list_head resource_list;
	struct resource *resources = NULL;
	int count;

	/* If the ACPI node already has a physical device attached, skip it. */
	if (adev->physical_node_count)
		return NULL;

	if (!acpi_match_device_ids(adev, forbidden_id_list))
		return ERR_PTR(-EINVAL);

	INIT_LIST_HEAD(&resource_list);
	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
	if (count < 0) {
		return NULL;
	} else if (count > 0) {
		resources = kcalloc(count, sizeof(struct resource),
				    GFP_KERNEL);
		if (!resources) {
			dev_err(&adev->dev, "No memory for resources\n");
			acpi_dev_free_resource_list(&resource_list);
			return ERR_PTR(-ENOMEM);
		}
		count = 0;
		list_for_each_entry(rentry, &resource_list, node)
			acpi_platform_fill_resource(adev, rentry->res,
						    &resources[count++]);

		acpi_dev_free_resource_list(&resource_list);
	}

	memset(&pdevinfo, 0, sizeof(pdevinfo));
	/*
	 * If the ACPI node has a parent and that parent has a physical device
	 * attached to it, that physical device should be the parent of the
	 * platform device we are about to create.
	 */
	pdevinfo.parent = adev->parent ?
		acpi_get_first_physical_node(adev->parent) : NULL;
	pdevinfo.name = dev_name(&adev->dev);
	pdevinfo.id = -1;
	pdevinfo.res = resources;
	pdevinfo.num_res = count;
	pdevinfo.fwnode = acpi_fwnode_handle(adev);
	pdevinfo.properties = properties;

	if (acpi_dma_supported(adev))
		pdevinfo.dma_mask = DMA_BIT_MASK(32);  //dma_mask设置
	else
		pdevinfo.dma_mask = 0;

	pdev = platform_device_register_full(&pdevinfo); 
	if (IS_ERR(pdev))
		dev_err(&adev->dev, "platform device creation failed: %ld\n",
			PTR_ERR(pdev));
	else {
		set_dev_node(&pdev->dev, acpi_get_node(adev->handle));
		dev_dbg(&adev->dev, "created platform device %s\n",
			dev_name(&pdev->dev));
	}

	kfree(resources);

	return pdev;
}
EXPORT_SYMBOL_GPL(acpi_create_platform_device);

acpi_dma_supported:判断acpi设备是否支持dma

drivers/acpi/scan.c:
bool acpi_dma_supported(struct acpi_device *adev)
{
	if (!adev)
		return false;

	if (adev->flagsa_seen)
		return true;

	/*
	* Per ACPI 6.0 sec 6.2.17, assume devices can do cache-coherent
	* DMA on "Intel platforms".  Presumably that includes all x86 and
	* ia64, and other arches will set CONFIG_ACPI_CCA_REQUIRED=y.
	*/
	if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
		return true;

	return false;
}

设置
cca_seen:
static void acpi_init_coherency(struct acpi_device *adev)
{
        unsigned long long cca = 0;
        acpi_status status;
        struct acpi_device *parent = adev->parent;

        if (parent && parent->flagsa_seen) {
                /*
                 * From ACPI spec, OSPM will ignore _CCA if an ancestor
                 * already saw one.
                 */
                adev->flagsa_seen = 1;
                cca = parent->flags.coherent_dma;
        } else {
                status = acpi_evaluate_integer(adev->handle, "_CCA", //ACPI表设备属性_CCA
                                               NULL, &cca);
                if (ACPI_SUCCESS(status))
                        adev->flagsa_seen = 1;
                else if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
                        /*
                         * If architecture does not specify that _CCA is
                         * required for DMA-able devices (e.g. x86),
                         * we default to _CCA=1.
                         */
                        cca = 1;
                else
                        acpi_handle_debug(adev->handle,
                                          "ACPI device is missing _CCA.\n");
        }

        adev->flags.coherent_dma = cca;
}


比如飞腾GMAC网卡:
DSDT表:
        Device (ETH1)
        {
            Name (_HID, "PHYT0004")  // _HID: Hardware ID
            Name (_CID, "FTGM0001")  // _CID: Compatible ID
            Name (_UID, One)  // _UID: Unique ID
            Name (_CCA, One)  // _CCA: Cache Coherency Attribute   //一致性内存
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                Memory32Fixed (ReadWrite,
                    0x28210000,         // Address Base
                    0x00002000,         // Address Length
                    )
                Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, )
                {
                    0x00000052,
                }
            })
            Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
            {
                ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */,
                Package (0x0F)
                {
                    Package (0x02)
                    {
                        "interrupt-names",
                        "macirq"
                    },
.....

 

drivers/base/platform.c: 

struct platform_device *platform_device_register_full(
		const struct platform_device_info *pdevinfo)
{
	int ret = -ENOMEM;
	struct platform_device *pdev;

	pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
	if (!pdev)
		goto err_alloc;

	pdev->dev.parent = pdevinfo->parent;
	pdev->dev.fwnode = pdevinfo->fwnode;
//设置dma_mask

	if (pdevinfo->dma_mask) {
		/*
		 * This memory isn't freed when the device is put,
		 * I don't have a nice idea for that though.  Conceptually
		 * dma_mask in struct device should not be a pointer.
		 * See http://thread.gmane/gmane.linux.kernel.pci/9081
		 */
		pdev->dev.dma_mask =
			kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
		if (!pdev->dev.dma_mask)
			goto err;

		kmemleak_ignore(pdev->dev.dma_mask);

		*pdev->dev.dma_mask = pdevinfo->dma_mask;
		pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
	}

	ret = platform_device_add_resources(pdev,
			pdevinfo->res, pdevinfo->num_res);
	if (ret)
		goto err;

	ret = platform_device_add_data(pdev,
			pdevinfo->data, pdevinfo->size_data);
	if (ret)
		goto err;

	if (pdevinfo->properties) {
		ret = platform_device_add_properties(pdev,
						     pdevinfo->properties);
		if (ret)
			goto err;
	}

	ret = platform_device_add(pdev);
	if (ret) {
err:
		ACPI_COMPANION_SET(&pdev->dev, NULL);
		kfree(pdev->dev.dma_mask);

err_alloc:
		platform_device_put(pdev);
		return ERR_PTR(ret);
	}

	return pdev;
}

 

使用:

  dma_alloc_attrs->swiotlb_alloc->dma_direct_alloc:

void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp, unsigned long attrs)
{
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        int page_order = get_order(size);
        struct page *page = NULL;
        void *ret;

        /* we always manually zero the memory once we are done: */
        gfp &= ~__GFP_ZERO;

        /* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */
        if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
                gfp |= GFP_DMA;
        if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
                gfp |= GFP_DMA32;

.....

}

 

 

更多推荐

dma_mask和coherent_dma_mask 的默认值