From: Jeff Garzik <jeff@garzik.org>
To: anil.s.keshavamurthy@intel.com
Cc: linux-kernel@vger.kernel.org, akpm@osdl.org, ak@suse.de,
gregkh@suse.de, muli@il.ibm.com, asit.k.mallick@intel.com,
suresh.b.siddha@intel.com, arjan@linux.intel.com,
ashok.raj@intel.com, shaohua.li@intel.com, davem@davemloft.net
Subject: Re: [Intel-IOMMU 01/10] DMAR detection and parsing logic
Date: Mon, 4 Jun 2007 18:54:21 -0400 [thread overview]
Message-ID: <20070604225421.GL20299@havoc.gtf.org> (raw)
In-Reply-To: <20070604210644.076940000@askeshav-devel.jf.intel.com>
On Mon, Jun 04, 2007 at 02:02:43PM -0700, anil.s.keshavamurthy@intel.com wrote:
> --- linux-2.6.22-rc3.orig/drivers/pci/Makefile 2007-06-04 12:28:13.000000000 -0700
> +++ linux-2.6.22-rc3/drivers/pci/Makefile 2007-06-04 12:33:15.000000000 -0700
> @@ -20,6 +20,9 @@
> # Build the Hypertransport interrupt support
> obj-$(CONFIG_HT_IRQ) += htirq.o
>
> +# Build Intel IOMMU support
> +obj-$(CONFIG_DMAR) += dmar.o
It's not Intel IOMMU support though, is it?
It's x86 PCI IOMMU support (as opposed to x86 GART IOMMU).
I just want to avoid Intel branding on something that will not be
specific to Intel-manufacured products in the long term.
> Index: linux-2.6.22-rc3/drivers/pci/dmar.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.22-rc3/drivers/pci/dmar.c 2007-06-04 12:33:15.000000000 -0700
> @@ -0,0 +1,318 @@
> +/*
> + * Copyright (c) 2006, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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
> + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
> + * Place - Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * Copyright (C) Ashok Raj <ashok.raj@intel.com>
> + * Copyright (C) Shaohua Li <shaohua.li@intel.com>
> + *
> + * This file implements early detection/parsing of DMA Remapping Devices
> + * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
> + * tables.
> + */
> +
> +#include <linux/pci.h>
> +#include <linux/dmar.h>
> +
> +#undef PREFIX
> +#define PREFIX "DMAR:"
> +
> +/* No locks are needed as DMA remapping hardware unit
> + * list is constructed at boot time and hotplug of
> + * these units are not supported by the architecture.
> + */
> +LIST_HEAD(dmar_drhd_units);
> +LIST_HEAD(dmar_rmrr_units);
> +
> +static struct acpi_table_header * __initdata dmar_tbl;
> +
> +static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
> +{
> + /*
> + * add INCLUDE_ALL at the tail, so scan the list will find it at
> + * the very end.
> + */
> + if (drhd->include_all)
> + list_add_tail(&drhd->list, &dmar_drhd_units);
> + else
> + list_add(&drhd->list, &dmar_drhd_units);
> +}
> +
> +static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
> +{
> + list_add(&rmrr->list, &dmar_rmrr_units);
> +}
> +
> +static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
> + struct pci_dev **dev, u16 segment)
> +{
> + struct pci_bus *bus;
> + struct pci_dev *pdev = NULL;
> + struct acpi_dmar_pci_path *path;
> + int count;
> +
> + bus = pci_find_bus(segment, scope->bus);
> + path = (struct acpi_dmar_pci_path *)(scope + 1);
> + count = (scope->length - sizeof(struct acpi_dmar_device_scope))
> + /sizeof(struct acpi_dmar_pci_path);
add a space.
But overall this casting and typed-struct pointer addition is a bit
fragile. No comment (I haven't read enough yet) whether it is needed or
not.
> +
> + while (count) {
> + if (pdev)
> + pci_dev_put(pdev);
> + /*
> + * Some BIOSes list non-exist devices in DMAR table, just
> + * ignore it
> + */
> + if (!bus) {
> + printk(KERN_WARNING
> + PREFIX "Device scope bus [%d] not found\n",
> + scope->bus);
> + break;
> + }
> + pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn));
> + if (!pdev) {
> + printk(KERN_WARNING PREFIX
> + "Device scope device [%04x:%02x:%02x.%02x] not found\n",
> + segment, bus->number, path->dev, path->fn);
> + break;
> + }
> + path ++;
> + count --;
> + bus = pdev->subordinate;
> + }
> + if (!pdev) {
> + printk(KERN_WARNING PREFIX
> + "Device scope device [%04x:%02x:%02x.%02x] not found\n",
> + segment, scope->bus, path->dev, path->fn);
> + *dev = NULL;
> + return 0;
> + }
> + if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && pdev->subordinate)
> + || (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
> + pci_dev_put(pdev);
> + printk(KERN_WARNING PREFIX "Device scope type does not match for %s\n", pci_name(pdev));
> + return -EINVAL;
> + }
> + *dev = pdev;
> + return 0;
> +}
> +
> +static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
> + struct pci_dev ***devices, u16 segment)
> +{
> + struct acpi_dmar_device_scope *scope;
> + void * tmp = start;
> + int index;
> + int ret;
> +
> + *cnt = 0;
> + while (start < end) {
> + scope = start;
> + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
> + scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
> + (*cnt)++;
> + else
> + printk(KERN_WARNING PREFIX "Unsupported device scope\n");
> + start += scope->length;
> + }
> + if (*cnt == 0)
> + return 0;
> +
> + *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL);
> + if (!*devices)
> + return -ENOMEM;
> +
> + start = tmp;
> + index = 0;
> + while (start < end) {
> + scope = start;
> + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
> + scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) {
> + ret = dmar_parse_one_dev_scope(scope,
> + &(*devices)[index], segment);
> + if (ret) {
> + kfree(*devices);
> + return ret;
> + }
> + index ++;
> + }
> + start += scope->length;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
> + * structure which uniquely represent one DMA remapping hardware unit
> + * present in the platform
> + */
> +static int __init
> +dmar_parse_one_drhd(struct acpi_dmar_header *header)
> +{
> + struct acpi_dmar_hardware_unit * drhd = (struct acpi_dmar_hardware_unit *)header;
> + struct dmar_drhd_unit *dmaru;
> + int ret = 0;
> + static int include_all;
> +
> + dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
> + if (!dmaru)
> + return -ENOMEM;
> +
> + dmaru->reg_base_addr = drhd->address;
> + dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
> +
> + if (!dmaru->include_all)
> + ret = dmar_parse_dev_scope((void *)(drhd + 1),
> + ((void *)drhd) + header->length,
> + &dmaru->devices_cnt, &dmaru->devices,
> + drhd->segment);
> + else {
> + /* Only allow one INCLUDE_ALL */
> + if (include_all) {
> + printk(KERN_WARNING PREFIX "Only one INCLUDE_ALL "
> + "device scope is allowed\n");
> + ret = -EINVAL;
> + }
> + include_all = 1;
> + }
> +
> + if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
> + kfree(dmaru);
> + else
> + dmar_register_drhd_unit(dmaru);
> + return ret;
> +}
> +
> +static int __init
> +dmar_parse_one_rmrr(struct acpi_dmar_header *header)
> +{
> + struct acpi_dmar_reserved_memory *rmrr = (struct acpi_dmar_reserved_memory *)header;
> + struct dmar_rmrr_unit *rmrru;
> + int ret = 0;
> +
> + rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
> + if (!rmrru)
> + return -ENOMEM;
> +
> + rmrru->base_address = rmrr->base_address;
> + rmrru->end_address = rmrr->end_address;
> + ret = dmar_parse_dev_scope((void *)(rmrr + 1),
> + ((void*)rmrr) + header->length,
> + &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
> +
> + if (ret || (rmrru->devices_cnt == 0))
> + kfree(rmrru);
> + else
> + dmar_register_rmrr_unit(rmrru);
> + return ret;
> +}
> +
> +static void __init
> +dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
> +{
> + struct acpi_dmar_hardware_unit *drhd;
> + struct acpi_dmar_reserved_memory *rmrr;
> +
> + switch (header->type) {
> + case ACPI_DMAR_TYPE_HARDWARE_UNIT:
> + drhd = (struct acpi_dmar_hardware_unit *)header;
> + printk (KERN_INFO PREFIX
> + "DRHD (flags: 0x%08x)base: 0x%016Lx\n",
> + drhd->flags, drhd->address);
> + break;
> + case ACPI_DMAR_TYPE_RESERVED_MEMORY:
> + rmrr = (struct acpi_dmar_reserved_memory *)header;
> +
> + printk (KERN_INFO PREFIX
> + "RMRR base: 0x%016Lx end: 0x%016Lx\n",
> + rmrr->base_address, rmrr->end_address);
> + break;
> + }
> +}
> +
> +/**
> + * parse_dmar_table - parses the DMA reporting table
> + */
> +static int __init
> +parse_dmar_table(void)
> +{
> + struct acpi_table_dmar *dmar;
> + struct acpi_dmar_header *entry_header;
> + int ret = 0;
> +
> + dmar = (struct acpi_table_dmar *)dmar_tbl;
> +
> + if (!dmar->width) {
> + printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
> + return -EINVAL;
> + }
> +
> + printk (KERN_INFO PREFIX "Host address width %d\n",
> + dmar->width + 1);
> +
> + entry_header = (struct acpi_dmar_header *)(dmar + 1);
> + while (((unsigned long)entry_header) < (((unsigned long)dmar) + dmar_tbl->length)) {
> + dmar_table_print_dmar_entry(entry_header);
> +
> + switch (entry_header->type) {
> + case ACPI_DMAR_TYPE_HARDWARE_UNIT:
> + ret = dmar_parse_one_drhd(entry_header);
> + break;
> + case ACPI_DMAR_TYPE_RESERVED_MEMORY:
> + ret = dmar_parse_one_rmrr(entry_header);
> + break;
> + default:
> + printk(KERN_WARNING PREFIX "Unknown DMAR structure type\n");
> + ret = 0; /* for forward compatibility */
> + break;
> + }
> + if (ret)
> + break;
> +
> + entry_header = ((void *)entry_header + entry_header->length);
> + }
> + return ret;
> +}
> +
> +
> +int __init dmar_table_init(void)
> +{
> +
> + parse_dmar_table();
> + if (list_empty(&dmar_drhd_units)) {
> + printk(KERN_ERR PREFIX "No DMAR devices found\n");
> + return -ENODEV;
> + }
> + return 0;
> +}
> +
> +/**
> + * early_dmar_detect - checks to see if the platform supports DMAR devices
> + */
> +int __init early_dmar_detect(void)
> +{
> + acpi_status status = AE_OK;
> +
> + /* if we could find DMAR table, then there are DMAR devices */
> + status = acpi_get_table(ACPI_SIG_DMAR, 0,
> + (struct acpi_table_header **)&dmar_tbl);
> +
> + if (ACPI_SUCCESS(status) && !dmar_tbl) {
> + printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
> + status = AE_NOT_FOUND;
> + }
> +
> + return (ACPI_SUCCESS(status) ? 1 : 0);
> +}
> Index: linux-2.6.22-rc3/include/acpi/actbl1.h
> ===================================================================
> --- linux-2.6.22-rc3.orig/include/acpi/actbl1.h 2007-06-04 12:28:13.000000000 -0700
> +++ linux-2.6.22-rc3/include/acpi/actbl1.h 2007-06-04 12:33:15.000000000 -0700
> @@ -257,7 +257,8 @@
> struct acpi_table_dmar {
> struct acpi_table_header header; /* Common ACPI table header */
> u8 width; /* Host Address Width */
> - u8 reserved[11];
> + u8 flags;
> + u8 reserved[10];
> };
>
> /* DMAR subtable header */
> @@ -265,8 +266,6 @@
> struct acpi_dmar_header {
> u16 type;
> u16 length;
> - u8 flags;
> - u8 reserved[3];
> };
>
> /* Values for subtable type in struct acpi_dmar_header */
> @@ -274,13 +273,15 @@
> enum acpi_dmar_type {
> ACPI_DMAR_TYPE_HARDWARE_UNIT = 0,
> ACPI_DMAR_TYPE_RESERVED_MEMORY = 1,
> - ACPI_DMAR_TYPE_RESERVED = 2 /* 2 and greater are reserved */
> + ACPI_DMAR_TYPE_ATSR = 2,
> + ACPI_DMAR_TYPE_RESERVED = 3 /* 3 and greater are reserved */
> };
>
> struct acpi_dmar_device_scope {
> u8 entry_type;
> u8 length;
> - u8 segment;
> + u16 reserved;
> + u8 enumeration_id;
> u8 bus;
> };
>
> @@ -290,7 +291,14 @@
> ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0,
> ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1,
> ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2,
> - ACPI_DMAR_SCOPE_TYPE_RESERVED = 3 /* 3 and greater are reserved */
> + ACPI_DMAR_SCOPE_TYPE_IOAPIC = 3,
> + ACPI_DMAR_SCOPE_TYPE_HPET = 4,
> + ACPI_DMAR_SCOPE_TYPE_RESERVED = 5 /* 5 and greater are reserved */
> +};
> +
> +struct acpi_dmar_pci_path {
> + u8 dev;
> + u8 fn;
> };
>
> /*
> @@ -301,6 +309,9 @@
>
> struct acpi_dmar_hardware_unit {
> struct acpi_dmar_header header;
> + u8 flags;
> + u8 reserved;
> + u16 segment;
> u64 address; /* Register Base Address */
> };
>
> @@ -312,7 +323,9 @@
>
> struct acpi_dmar_reserved_memory {
> struct acpi_dmar_header header;
> - u64 address; /* 4_k aligned base address */
> + u16 reserved;
> + u16 segment;
> + u64 base_address; /* 4_k aligned base address */
> u64 end_address; /* 4_k aligned limit address */
> };
>
> Index: linux-2.6.22-rc3/include/linux/dmar.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.22-rc3/include/linux/dmar.h 2007-06-04 12:33:15.000000000 -0700
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (c) 2006, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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
> + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
> + * Place - Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * Copyright (C) Ashok Raj <ashok.raj@intel.com>
> + * Copyright (C) Shaohua Li <shaohua.li@intel.com>
> + */
> +
> +#ifndef __DMAR_H__
> +#define __DMAR_H__
> +
> +#include <linux/acpi.h>
> +#include <linux/types.h>
> +
> +
> +extern int dmar_table_init(void);
> +extern int early_dmar_detect(void);
> +
> +extern struct list_head dmar_drhd_units;
> +extern struct list_head dmar_rmrr_units;
> +
> +struct dmar_drhd_unit {
> + struct list_head list; /* list of drhd units */
> + u64 reg_base_addr; /* register base address*/
> + struct pci_dev **devices; /* target device array */
> + int devices_cnt; /* target device count */
> + u8 ignored:1; /* ignore drhd */
> + u8 include_all:1;
> + struct intel_iommu *iommu;
> +};
> +
> +struct dmar_rmrr_unit {
> + struct list_head list; /* list of rmrr units */
> + u64 base_address; /* reserved base address*/
> + u64 end_address; /* reserved end address */
> + struct pci_dev **devices; /* target devices */
> + int devices_cnt; /* target device count */
> +};
> +
> +#endif /* __DMAR_H__ */
>
> --
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
next prev parent reply other threads:[~2007-06-04 22:54 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-06-04 21:02 [Intel-IOMMU 00/10] Intel IOMMU support anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 01/10] DMAR detection and parsing logic anil.s.keshavamurthy
2007-06-04 22:54 ` Jeff Garzik [this message]
2007-06-04 22:58 ` Keshavamurthy, Anil S
2007-06-04 23:03 ` Jeff Garzik
2007-06-04 23:17 ` Keshavamurthy, Anil S
2007-06-04 21:02 ` [Intel-IOMMU 02/10] Library routines for handling pre-allocated pool of objects anil.s.keshavamurthy
2007-06-04 22:57 ` Jeff Garzik
2007-06-04 23:06 ` Keshavamurthy, Anil S
2007-06-04 23:43 ` Jeff Garzik
2007-06-04 23:51 ` Keshavamurthy, Anil S
2007-06-05 20:24 ` Keshavamurthy, Anil S
2007-06-05 20:30 ` Jeff Garzik
2007-06-05 20:48 ` Keshavamurthy, Anil S
2007-06-04 21:02 ` [Intel-IOMMU 03/10] PCI generic helper function anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 04/10] clflush_cache_range now takes size param anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 05/10] IOVA allocation and management routines anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 06/10] Intel IOMMU driver anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 07/10] Intel iommu cmdline option - forcedac anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 08/10] DMAR fault handling support anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 09/10] Iommu Gfx workaround anil.s.keshavamurthy
2007-06-04 21:02 ` [Intel-IOMMU 10/10] Iommu floppy workaround anil.s.keshavamurthy
2007-06-06 18:56 [Intel-IOMMU 00/10] Intel IOMMU Support anil.s.keshavamurthy
2007-06-06 18:56 ` [Intel-IOMMU 01/10] DMAR detection and parsing logic anil.s.keshavamurthy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070604225421.GL20299@havoc.gtf.org \
--to=jeff@garzik.org \
--cc=ak@suse.de \
--cc=akpm@osdl.org \
--cc=anil.s.keshavamurthy@intel.com \
--cc=arjan@linux.intel.com \
--cc=ashok.raj@intel.com \
--cc=asit.k.mallick@intel.com \
--cc=davem@davemloft.net \
--cc=gregkh@suse.de \
--cc=linux-kernel@vger.kernel.org \
--cc=muli@il.ibm.com \
--cc=shaohua.li@intel.com \
--cc=suresh.b.siddha@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®