/* * mods_pci.c - This file is part of NVIDIA MODS kernel driver. * * Copyright (c) 2008-2018, NVIDIA CORPORATION. All rights reserved. * * NVIDIA MODS kernel driver is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * NVIDIA MODS kernel driver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NVIDIA MODS kernel driver. * If not, see . */ #include "mods_internal.h" #include #include #if defined(MODS_HAS_DMA_OPS) #include #endif /************************ * PCI HELPER FUNCTIONS * ************************/ static int mods_free_pci_res_map(struct file *fp, struct MODS_PCI_RES_MAP_INFO *p_del_map) { #if defined(MODS_HAS_PCI_MAP_RESOURCE) struct MODS_PCI_RES_MAP_INFO *p_res_map; MODS_PRIV private_data = fp->private_data; struct list_head *head; struct list_head *iter; mods_debug_printk(DEBUG_PCI, "free pci resource map %p\n", p_del_map); if (unlikely(mutex_lock_interruptible(&private_data->mtx))) return -EINTR; head = private_data->mods_pci_res_map_list; list_for_each(iter, head) { p_res_map = list_entry(iter, struct MODS_PCI_RES_MAP_INFO, list); if (p_del_map == p_res_map) { list_del(iter); mutex_unlock(&private_data->mtx); pci_unmap_resource(p_res_map->dev, p_res_map->va, p_res_map->page_count * PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); mods_debug_printk(DEBUG_PCI, "unmapped pci resource at 0x%llx from %u:%u:%u.%u\n", p_res_map->va, pci_domain_nr(p_res_map->dev->bus), p_res_map->dev->bus->number, PCI_SLOT(p_res_map->dev->devfn), PCI_FUNC(p_res_map->dev->devfn)); kfree(p_res_map); return OK; } } mutex_unlock(&private_data->mtx); mods_error_printk("failed to unregister pci resource mapping %p\n", p_del_map); return -EINVAL; #else return OK; #endif } int mods_unregister_all_pci_res_mappings(struct file *fp) { MODS_PRIV private_data = fp->private_data; struct list_head *head = private_data->mods_pci_res_map_list; struct list_head *iter; struct list_head *tmp; list_for_each_safe(iter, tmp, head) { struct MODS_PCI_RES_MAP_INFO *p_pci_res_map_info; int ret; p_pci_res_map_info = list_entry(iter, struct MODS_PCI_RES_MAP_INFO, list); ret = mods_free_pci_res_map(fp, p_pci_res_map_info); if (ret) return ret; } return OK; } /************************ * PCI ESCAPE FUNCTIONS * ************************/ static int mods_find_pci_dev(struct file *pfile, struct MODS_FIND_PCI_DEVICE_2 *p, int enum_non_zero_dom) { struct pci_dev *dev = NULL; int index = -1; mods_debug_printk(DEBUG_PCI, "find pci dev %04x:%04x, index %d\n", (int) p->vendor_id, (int) p->device_id, (int) p->index); do { dev = pci_get_device(p->vendor_id, p->device_id, dev); if (!dev) return -EINVAL; if (enum_non_zero_dom || !pci_domain_nr(dev->bus)) ++index; } while (index < (int)(p->index)); p->pci_device.domain = pci_domain_nr(dev->bus); p->pci_device.bus = dev->bus->number; p->pci_device.device = PCI_SLOT(dev->devfn); p->pci_device.function = PCI_FUNC(dev->devfn); #if defined(CONFIG_PPC64) /* Enable device on the PCI bus */ if (mods_enable_device(pfile->private_data, dev)) { mods_error_printk( "unable to enable dev %04x:%02x:%02x.%x\n", (unsigned int)p->pci_device.domain, (unsigned int)p->pci_device.bus, (unsigned int)p->pci_device.device, (unsigned int)p->pci_device.function); return -EINVAL; } #endif return OK; } int esc_mods_find_pci_dev_2(struct file *pfile, struct MODS_FIND_PCI_DEVICE_2 *p) { return mods_find_pci_dev(pfile, p, 1); } int esc_mods_find_pci_dev(struct file *pfile, struct MODS_FIND_PCI_DEVICE *p) { struct MODS_FIND_PCI_DEVICE_2 p2; int ret; p2.device_id = p->device_id; p2.vendor_id = p->vendor_id; p2.index = p->index; ret = mods_find_pci_dev(pfile, &p2, 0); if (!ret) { p->bus_number = p2.pci_device.bus; p->device_number = p2.pci_device.device; p->function_number = p2.pci_device.function; } return ret; } static int mods_find_pci_class_code(struct file *pfile, struct MODS_FIND_PCI_CLASS_CODE_2 *p, int enum_non_zero_dom) { struct pci_dev *dev = NULL; int index = -1; mods_debug_printk(DEBUG_PCI, "find pci class code %04x, index %d\n", (int) p->class_code, (int) p->index); do { dev = pci_get_class(p->class_code, dev); if (!dev) return -EINVAL; if (enum_non_zero_dom || !pci_domain_nr(dev->bus)) ++index; } while (index < (int)(p->index)); p->pci_device.domain = pci_domain_nr(dev->bus); p->pci_device.bus = dev->bus->number; p->pci_device.device = PCI_SLOT(dev->devfn); p->pci_device.function = PCI_FUNC(dev->devfn); #if defined(CONFIG_PPC64) /* Enable device on the PCI bus */ if (mods_enable_device(pfile->private_data, dev)) { mods_error_printk( "unable to enable dev %04x:%02x:%02x.%x\n", (unsigned int)p->pci_device.domain, (unsigned int)p->pci_device.bus, (unsigned int)p->pci_device.device, (unsigned int)p->pci_device.function); return -EINVAL; } #endif return OK; } int esc_mods_find_pci_class_code_2(struct file *pfile, struct MODS_FIND_PCI_CLASS_CODE_2 *p) { return mods_find_pci_class_code(pfile, p, 1); } int esc_mods_find_pci_class_code(struct file *pfile, struct MODS_FIND_PCI_CLASS_CODE *p) { struct MODS_FIND_PCI_CLASS_CODE_2 p2; int ret; p2.class_code = p->class_code; p2.index = p->index; ret = mods_find_pci_class_code(pfile, &p2, 0); if (!ret) { p->bus_number = p2.pci_device.bus; p->device_number = p2.pci_device.device; p->function_number = p2.pci_device.function; } return ret; } int esc_mods_pci_get_bar_info_2(struct file *pfile, struct MODS_PCI_GET_BAR_INFO_2 *p) { struct pci_dev *dev; unsigned int devfn, bar_resource_offset, i; #if !defined(MODS_HAS_IORESOURCE_MEM_64) __u32 temp; #endif devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); if (dev == NULL) return -EINVAL; mods_debug_printk(DEBUG_PCI, "pci get bar info %04x:%x:%02x:%x, bar index %d\n", (int) p->pci_device.domain, (int) p->pci_device.bus, (int) p->pci_device.device, (int) p->pci_device.function, (int) p->bar_index); bar_resource_offset = 0; for (i = 0; i < p->bar_index; i++) { #if defined(MODS_HAS_IORESOURCE_MEM_64) if (pci_resource_flags(dev, bar_resource_offset) & IORESOURCE_MEM_64) { #else pci_read_config_dword(dev, (PCI_BASE_ADDRESS_0 + (bar_resource_offset * 4)), &temp); if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { #endif bar_resource_offset += 2; } else { bar_resource_offset += 1; } } p->base_address = pci_resource_start(dev, bar_resource_offset); p->bar_size = pci_resource_len(dev, bar_resource_offset); return OK; } int esc_mods_pci_get_bar_info(struct file *pfile, struct MODS_PCI_GET_BAR_INFO *p) { int retval; struct MODS_PCI_GET_BAR_INFO_2 get_bar_info = { {0} }; get_bar_info.pci_device.domain = 0; get_bar_info.pci_device.bus = p->pci_device.bus; get_bar_info.pci_device.device = p->pci_device.device; get_bar_info.pci_device.function = p->pci_device.function; get_bar_info.bar_index = p->bar_index; retval = esc_mods_pci_get_bar_info_2(pfile, &get_bar_info); if (retval) return retval; p->base_address = get_bar_info.base_address; p->bar_size = get_bar_info.bar_size; return OK; } int esc_mods_pci_get_irq_2(struct file *pfile, struct MODS_PCI_GET_IRQ_2 *p) { struct pci_dev *dev; unsigned int devfn; devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); if (dev == NULL) return -EINVAL; mods_debug_printk(DEBUG_PCI, "pci get irq %04x:%x:%02x:%x\n", (int) p->pci_device.domain, (int) p->pci_device.bus, (int) p->pci_device.device, (int) p->pci_device.function); p->irq = dev->irq; return OK; } int esc_mods_pci_get_irq(struct file *pfile, struct MODS_PCI_GET_IRQ *p) { int retval; struct MODS_PCI_GET_IRQ_2 get_irq = { {0} }; get_irq.pci_device.domain = 0; get_irq.pci_device.bus = p->pci_device.bus; get_irq.pci_device.device = p->pci_device.device; get_irq.pci_device.function = p->pci_device.function; retval = esc_mods_pci_get_irq_2(pfile, &get_irq); if (retval) return retval; p->irq = get_irq.irq; return OK; } int esc_mods_pci_read_2(struct file *pfile, struct MODS_PCI_READ_2 *p) { struct pci_dev *dev; unsigned int devfn; devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); if (dev == NULL) return -EINVAL; mods_debug_printk(DEBUG_PCI, "pci read %04x:%x:%02x.%x, addr 0x%04x, size %d\n", (int) p->pci_device.domain, (int) p->pci_device.bus, (int) p->pci_device.device, (int) p->pci_device.function, (int) p->address, (int) p->data_size); p->data = 0; switch (p->data_size) { case 1: { u8 value; pci_read_config_byte(dev, p->address, &value); p->data = value; } break; case 2: { u16 value; pci_read_config_word(dev, p->address, &value); p->data = value; } break; case 4: pci_read_config_dword(dev, p->address, (u32 *) &p->data); break; default: return -EINVAL; } return OK; } int esc_mods_pci_read(struct file *pfile, struct MODS_PCI_READ *p) { int retval; struct MODS_PCI_READ_2 pci_read = { {0} }; pci_read.pci_device.domain = 0; pci_read.pci_device.bus = p->bus_number; pci_read.pci_device.device = p->device_number; pci_read.pci_device.function = p->function_number; pci_read.address = p->address; pci_read.data_size = p->data_size; retval = esc_mods_pci_read_2(pfile, &pci_read); if (retval) return retval; p->data = pci_read.data; return OK; } int esc_mods_pci_write_2(struct file *pfile, struct MODS_PCI_WRITE_2 *p) { struct pci_dev *dev; unsigned int devfn; mods_debug_printk(DEBUG_PCI, "pci write %04x:%x:%02x.%x, addr 0x%04x, size %d, data 0x%x\n", (int) p->pci_device.domain, (int) p->pci_device.bus, (int) p->pci_device.device, (int) p->pci_device.function, (int) p->address, (int) p->data_size, (int) p->data); devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); if (dev == NULL) { mods_error_printk( "pci write to %04x:%x:%02x.%x, addr 0x%04x, size %d failed\n", (unsigned int)p->pci_device.domain, (unsigned int)p->pci_device.bus, (unsigned int)p->pci_device.device, (unsigned int)p->pci_device.function, (unsigned int)p->address, (int)p->data_size); return -EINVAL; } switch (p->data_size) { case 1: pci_write_config_byte(dev, p->address, p->data); break; case 2: pci_write_config_word(dev, p->address, p->data); break; case 4: pci_write_config_dword(dev, p->address, p->data); break; default: return -EINVAL; } return OK; } int esc_mods_pci_write(struct file *pfile, struct MODS_PCI_WRITE *p) { struct MODS_PCI_WRITE_2 pci_write = { {0} }; pci_write.pci_device.domain = 0; pci_write.pci_device.bus = p->bus_number; pci_write.pci_device.device = p->device_number; pci_write.pci_device.function = p->function_number; pci_write.address = p->address; pci_write.data = p->data; pci_write.data_size = p->data_size; return esc_mods_pci_write_2(pfile, &pci_write); } int esc_mods_pci_bus_add_dev(struct file *pfile, struct MODS_PCI_BUS_ADD_DEVICES *scan) { #if defined(CONFIG_PCI) mods_info_printk("scanning pci bus %x\n", scan->bus); /* initiate a PCI bus scan to find hotplugged PCI devices in domain 0 */ pci_scan_child_bus(pci_find_bus(0, scan->bus)); /* add newly found devices */ pci_bus_add_devices(pci_find_bus(0, scan->bus)); return OK; #else return -EINVAL; #endif } int esc_mods_pci_hot_reset(struct file *pfile, struct MODS_PCI_HOT_RESET *p) { #if defined(CONFIG_PPC64) struct pci_dev *dev; unsigned int devfn; int retval; mods_debug_printk(DEBUG_PCI, "pci_hot_reset %04x:%x:%02x.%x\n", (int) p->pci_device.domain, (int) p->pci_device.bus, (int) p->pci_device.device, (int) p->pci_device.function); devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); if (dev == NULL) { mods_error_printk( "pci_hot_reset cannot find pci device %04x:%x:%02x.%x\n", (unsigned int)p->pci_device.domain, (unsigned int)p->pci_device.bus, (unsigned int)p->pci_device.device, (unsigned int)p->pci_device.function); return -EINVAL; } retval = pci_set_pcie_reset_state(dev, pcie_hot_reset); if (retval) { mods_error_printk( "pci_hot_reset failed on %04x:%x:%02x.%x\n", (unsigned int)p->pci_device.domain, (unsigned int)p->pci_device.bus, (unsigned int)p->pci_device.device, (unsigned int)p->pci_device.function); return retval; } retval = pci_set_pcie_reset_state(dev, pcie_deassert_reset); if (retval) { mods_error_printk( "pci_hot_reset deassert failed on %04x:%x:%02x.%x\n", (unsigned int)p->pci_device.domain, (unsigned int)p->pci_device.bus, (unsigned int)p->pci_device.device, (unsigned int)p->pci_device.function); return retval; } return OK; #else return -EINVAL; #endif } /************************ * PIO ESCAPE FUNCTIONS * ************************/ int esc_mods_pio_read(struct file *pfile, struct MODS_PIO_READ *p) { LOG_ENT(); switch (p->data_size) { case 1: p->data = inb(p->port); break; case 2: p->data = inw(p->port); break; case 4: p->data = inl(p->port); break; default: return -EINVAL; } LOG_EXT(); return OK; } int esc_mods_pio_write(struct file *pfile, struct MODS_PIO_WRITE *p) { LOG_ENT(); switch (p->data_size) { case 1: outb(p->data, p->port); break; case 2: outw(p->data, p->port); break; case 4: outl(p->data, p->port); break; default: return -EINVAL; } LOG_EXT(); return OK; } int esc_mods_device_numa_info_2(struct file *fp, struct MODS_DEVICE_NUMA_INFO_2 *p) { #ifdef MODS_HAS_DEV_TO_NUMA_NODE unsigned int devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); struct pci_dev *dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); LOG_ENT(); if (dev == NULL) { mods_error_printk("PCI device %04x:%x:%02x.%x not found\n", p->pci_device.domain, p->pci_device.bus, p->pci_device.device, p->pci_device.function); LOG_EXT(); return -EINVAL; } p->node = dev_to_node(&dev->dev); if (-1 != p->node) { const unsigned long *maskp = cpumask_bits(cpumask_of_node(p->node)); unsigned int i, word, bit, maskidx; if (((nr_cpumask_bits + 31) / 32) > MAX_CPU_MASKS) { mods_error_printk("too many CPUs (%d) for mask bits\n", nr_cpumask_bits); LOG_EXT(); return -EINVAL; } for (i = 0, maskidx = 0; i < nr_cpumask_bits; i += 32, maskidx++) { word = i / BITS_PER_LONG; bit = i % BITS_PER_LONG; p->node_cpu_mask[maskidx] = (maskp[word] >> bit) & 0xFFFFFFFFUL; } } p->node_count = num_possible_nodes(); p->cpu_count = num_possible_cpus(); LOG_EXT(); return OK; #else return -EINVAL; #endif } int esc_mods_device_numa_info(struct file *fp, struct MODS_DEVICE_NUMA_INFO *p) { int retval, i; struct MODS_DEVICE_NUMA_INFO_2 numa_info = { {0} }; numa_info.pci_device.domain = 0; numa_info.pci_device.bus = p->pci_device.bus; numa_info.pci_device.device = p->pci_device.device; numa_info.pci_device.function = p->pci_device.function; retval = esc_mods_device_numa_info_2(fp, &numa_info); if (retval) return retval; p->node = numa_info.node; p->node_count = numa_info.node_count; for (i = 0; i < MAX_CPU_MASKS; i++) p->node_cpu_mask[i] = numa_info.node_cpu_mask[i]; p->cpu_count = numa_info.cpu_count; return OK; } int esc_mods_pci_map_resource(struct file *fp, struct MODS_PCI_MAP_RESOURCE *p) { #if defined(MODS_HAS_PCI_MAP_RESOURCE) MODS_PRIV private_data = fp->private_data; unsigned int devfn; struct pci_dev *rem_dev; struct pci_dev *loc_dev; struct MODS_PCI_RES_MAP_INFO *p_res_map; LOG_ENT(); devfn = PCI_DEVFN(p->local_pci_device.device, p->local_pci_device.function); loc_dev = MODS_PCI_GET_SLOT(p->local_pci_device.domain, p->local_pci_device.bus, devfn); if (!loc_dev) { mods_error_printk("Local PCI device %04x:%x:%02x.%x not found\n", p->local_pci_device.domain, p->local_pci_device.bus, p->local_pci_device.device, p->local_pci_device.function); LOG_EXT(); return -EINVAL; } devfn = PCI_DEVFN(p->remote_pci_device.device, p->remote_pci_device.function); rem_dev = MODS_PCI_GET_SLOT(p->remote_pci_device.domain, p->remote_pci_device.bus, devfn); if (!rem_dev) { mods_error_printk("Remote PCI device %04x:%x:%02x.%x not found\n", p->remote_pci_device.domain, p->remote_pci_device.bus, p->remote_pci_device.device, p->remote_pci_device.function); LOG_EXT(); return -EINVAL; } if ((p->resource_index >= DEVICE_COUNT_RESOURCE) || !pci_resource_len(rem_dev, p->resource_index)) { mods_error_printk( "Resource %u on device %04x:%x:%02x.%x not found\n", p->resource_index, p->remote_pci_device.domain, p->remote_pci_device.bus, p->remote_pci_device.device, p->remote_pci_device.function); LOG_EXT(); return -EINVAL; } if ((p->va < pci_resource_start(rem_dev, p->resource_index)) || (p->va > pci_resource_end(rem_dev, p->resource_index)) || (p->va + p->page_count * PAGE_SIZE > pci_resource_end(rem_dev, p->resource_index))) { mods_error_printk( "bad resource address 0x%04x:%x:%02x.%x on device %u:%u:%u.%u\n" (unsigned long long)p->va, p->remote_pci_device.domain, p->remote_pci_device.bus, p->remote_pci_device.device, p->remote_pci_device.function); LOG_EXT(); return -EINVAL; } p_res_map = kmalloc(sizeof(struct MODS_PCI_RES_MAP_INFO), GFP_KERNEL | __GFP_NORETRY); if (unlikely(!p_res_map)) { mods_error_printk("failed to allocate pci res map struct\n"); LOG_EXT(); return -ENOMEM; } p_res_map->dev = loc_dev; p_res_map->page_count = p->page_count; p_res_map->va = pci_map_resource(loc_dev, &rem_dev->resource[resource_index], p->va - pci_resource_start(rem_dev, p->resource_index), p->page_count * PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); p_res_map->va = p->va; if (pci_dma_mapping_error(loc_dev, p_res_map->va)) { kfree(p_res_map); LOG_EXT(); return -ENOMEM; } if (unlikely(mutex_lock_interruptible(&private_data->mtx))) { kfree(p_res_map); LOG_EXT(); return -EINTR; } list_add(&p_res_map->list, private_data->mods_pci_res_map_list); mutex_unlock(&private_data->mtx); p->va = p_res_map->va; mods_debug_printk(DEBUG_PCI, "mapped pci resource %u from %u:%u:%u.%u to %u:%u:%u.%u at 0x%llx\n", p->resource_index, p->remote_pci_device.domain, p->remote_pci_device.bus, p->remote_pci_device.device, p->remote_pci_device.function, p->local_pci_device.domain, p->local_pci_device.bus, p->local_pci_device.device, p->local_pci_device.function, p->va); #else /* * We still return OK, in case the system is running an older kernel * with the IOMMU disabled. The va parameter will still contain the * input physical address, which is what the device should use in this * fallback case. */ #endif return OK; } int esc_mods_pci_unmap_resource(struct file *fp, struct MODS_PCI_UNMAP_RESOURCE *p) { #if defined(MODS_HAS_PCI_MAP_RESOURCE) MODS_PRIV private_data = fp->private_data; unsigned int devfn = PCI_DEVFN(p->pci_device.device, p->pci_device.function); struct pci_dev *dev = MODS_PCI_GET_SLOT(p->pci_device.domain, p->pci_device.bus, devfn); struct list_head *head = private_data->mods_pci_res_map_list; struct list_head *iter; struct list_head *tmp; LOG_ENT(); if (!dev) { mods_error_printk("PCI device %04x:%x:%02x.%x not found\n", p->pci_device.domain, p->pci_device.bus, p->pci_device.device, p->pci_device.function); LOG_EXT(); return -EINVAL; } list_for_each_safe(iter, tmp, head) { struct MODS_PCI_RES_MAP_INFO *p_pci_res_map_info; p_pci_res_map_info = list_entry(iter, struct MODS_PCI_RES_MAP_INFO, list); if ((p_pci_res_map_info->dev == dev) && (p_pci_res_map_info->va == p->va)) { int ret = mods_free_pci_res_map(fp, p_pci_res_map_info); LOG_EXT(); return ret; } } mods_error_printk( "PCI mapping 0x%llx on device %04x:%x:%02x.%x not found\n", p->va, p->pci_device.domain, p->pci_device.bus, p->pci_device.device, p->pci_device.function); return -EINVAL; #else return OK; #endif } int esc_mods_get_iommu_state(struct file *pfile, struct MODS_GET_IOMMU_STATE *state) { #if !defined(CONFIG_SWIOTLB) /* SWIOTLB turned off in the kernel, HW IOMMU active */ state->state = 1; #elif defined(MODS_HAS_DMA_OPS) && \ (defined(MODS_HAS_NONCOH_DMA_OPS) || defined(MODS_HAS_MAP_SG_ATTRS)) unsigned int devfn = PCI_DEVFN(state->pci_device.device, state->pci_device.function); struct pci_dev *dev = MODS_PCI_GET_SLOT(state->pci_device.domain, state->pci_device.bus, devfn); const struct dma_map_ops *ops = get_dma_ops(&dev->dev); #if defined(MODS_HAS_NONCOH_DMA_OPS) state->state = ops != &noncoherent_swiotlb_dma_ops && ops != &coherent_swiotlb_dma_ops; #else state->state = ops->map_sg != swiotlb_map_sg_attrs; #endif #elif defined(CONFIG_PPC64) || defined(CONFIG_ARM64) /* Old/new kernels, no way to detect, default to HW IOMMU active */ state->state = 1; #else /* Old/new kernels, no way to detect, on x86 default to no IOMMU */ state->state = 0; #endif return OK; }