dma_mask和coherent_dma_mask 的默认值

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->flags.cca_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->flags.cca_seen) {
                /*
                 * From ACPI spec, OSPM will ignore _CCA if an ancestor
                 * already saw one.
                 */
                adev->flags.cca_seen = 1;
                cca = parent->flags.coherent_dma;
        } else {
                status = acpi_evaluate_integer(adev->handle, "_CCA", //ACPI表设备属性_CCA
                                               NULL, &cca);
                if (ACPI_SUCCESS(status))
                        adev->flags.cca_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"
                    },
.....

platform_dma_configure会通过acpi_get_dma_attr获取dev_dma_attr类型并调用初始化函数acpi_dma_configure

int platform_dma_configure(struct device *dev)
{
	enum dev_dma_attr attr;
	int ret = 0;

	if (dev->of_node) {
		ret = of_dma_configure(dev, dev->of_node, true);
	} else if (has_acpi_companion(dev)) {
		attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
		ret = acpi_dma_configure(dev, attr);
	}

	return ret;
}



enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
{
	if (!acpi_dma_supported(adev))
		return DEV_DMA_NOT_SUPPORTED;

	if (adev->flags.coherent_dma)
		return DEV_DMA_COHERENT;
	else
		return DEV_DMA_NON_COHERENT;
}

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.org/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;

.....

}

pci设置驱动会设置实际的dma_mask:

[    8.785389] ===dma_set_mask 0000:05:00.0 mask ffffffffffffffff 
[    8.791302] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #46
[    8.799725] Hardware name: PHYTIUM LTD D2000/D2000, BIOS  
[    8.805197] Call trace:
[    8.807637]  dump_backtrace+0x0/0x1b4
[    8.811288]  show_stack+0x24/0x70
[    8.814592]  dump_stack+0xd0/0x12c
[    8.817982]  dma_set_mask+0x44/0x80
[    8.821459]  ahci_init_one+0x780/0xd10
[    8.825197]  local_pci_probe+0x4c/0xc0
[    8.828934]  pci_device_probe+0x120/0x1c0
[    8.832932]  really_probe+0xec/0x494
[    8.836495]  driver_probe_device+0x64/0xcc
[    8.840578]  device_driver_attach+0xcc/0xd4
[    8.844748]  __driver_attach+0x90/0x130
[    8.848571]  bus_for_each_dev+0x7c/0xe0
[    8.852395]  driver_attach+0x30/0x40
[    8.855957]  bus_add_driver+0x114/0x200
[    8.859780]  driver_register+0x84/0x140
[    8.863603]  __pci_register_driver+0x50/0x5c
[    8.867861]  ahci_pci_driver_init+0x30/0x3c
[    8.872032]  do_one_initcall+0x50/0x260
[    8.875855]  kernel_init_freeable+0x22c/0x2c0
[    8.880201]  kernel_init+0x20/0x124
[    8.883676]  ret_from_fork+0x10/0x30
[    8.887243] ===dma_set_coherent_mask 0000:05:00.0 mask ffffffffffffffff 
[    8.893933] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #46
[    8.902355] Hardware name: PHYTIUM LTD D2000/D2000, BIOS  
[    8.907826] Call trace:
[    8.910260]  dump_backtrace+0x0/0x1b4
[    8.913910]  show_stack+0x24/0x70
[    8.917212]  dump_stack+0xd0/0x12c
[    8.920602]  dma_set_coherent_mask+0x44/0x74
[    8.924859]  ahci_init_one+0x968/0xd10
[    8.928595]  local_pci_probe+0x4c/0xc0
[    8.932331]  pci_device_probe+0x120/0x1c0
[    8.936327]  really_probe+0xec/0x494
[    8.939890]  driver_probe_device+0x64/0xcc

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古井无波 2024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值