* Re: [PATCH 1/3] tty: serial: 8250: Add new capability for highspeed register
From: One Thousand Gnomes @ 2014-08-05 11:43 UTC (permalink / raw)
To: Matthias Brugger
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, jslaby-AlSwsSmVLrQ,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
heikki.krogerus-VuQAYsv1563Yd54FQh9/CA,
alan-VuQAYsv1563Yd54FQh9/CA,
paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ,
asierra-AQeFf1F/bRxBDgjK7y7TUQ, mwelling-EkmVulN54Sk,
dianders-F7+t8E8rja9g9hUCZPvPmw, m-karicheri2-l0cyMroinI0,
jschultz-AQeFf1F/bRxBDgjK7y7TUQ, mingo-X9Un+BFzKDI,
balbi-l0cyMroinI0, heiko-4mtYJXux2i+zQB+pC5nmwQ,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1407236054-30994-2-git-send-email-matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> /*
> + * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
> + *
> + * We need to recalcualte the quot register, as the claculation depends
> + * on the vaule in the highspeed register.
> + *
> + * Some baudrates are not supported by the chip, so we use the next
> + * lower rate supported.
> + *
> + * If highspeed register is set to 3, we need to specify sample count
> + * and sample point to increase accuracy. If not, we reset the
> + * registers to their default values.
> + */
Don't put stuff in the core driver core for your chip specific weirdness,
wrap the termios method with your own in your driver code as a fair
number of other 8250ish drivers do.
If you do that then you don't need to waste a UART CAPS flag and you
don't need to put anything in the core driver code.
Alan
^ permalink raw reply
* [PATCH 3/3] DTS: serial: Add bindings documention for the Mediatek UARTs
From: Matthias Brugger @ 2014-08-05 10:54 UTC (permalink / raw)
To: linux-kernel
Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rdunlap,
gregkh, jslaby, grant.likely, matthias.bgg, heikki.krogerus, alan,
paul.gortmaker, asierra, mwelling, dianders, m-karicheri2,
jschultz, mingo, balbi, heiko, devicetree, linux-doc,
linux-serial, linux-api
In-Reply-To: <1407236054-30994-1-git-send-email-matthias.bgg@gmail.com>
This patch adds the devicetree documentation for the Mediatek UART.
Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
---
.../devicetree/bindings/serial/mtk-uart.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/mtk-uart.txt
diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
new file mode 100644
index 0000000..2bf571e
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -0,0 +1,19 @@
+* Mediatek Universal Asynchronous Receiver/Transmitter (UART)
+
+- compatible: "mediatek,mt6577-uart"
+ Compatibility with mt6577, mt6589, mt6582
+
+- reg: The base address of the UART register bank.
+
+- interrupts: A single interrupt specifier.
+
+- clocks: Clock driving the hardware.
+
+Example:
+
+ uart0: serial@11006000 {
+ compatible = "mediatek,mt6577-uart";
+ reg = <0x11006000 0x400>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&uart_clk>;
+ };
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/3] tty: serial: 8250: Add Mediatek UART driver
From: Matthias Brugger @ 2014-08-05 10:54 UTC (permalink / raw)
To: linux-kernel
Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rdunlap,
gregkh, jslaby, grant.likely, matthias.bgg, heikki.krogerus, alan,
paul.gortmaker, asierra, mwelling, dianders, m-karicheri2,
jschultz, mingo, balbi, heiko, devicetree, linux-doc,
linux-serial, linux-api
In-Reply-To: <1407236054-30994-1-git-send-email-matthias.bgg@gmail.com>
This patch adds support for the UART block found on Mediatek SoCs.
The driver uses the highspeed capability of the 8250_core to set the
highspeed register and calculate the divisor for it.
Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
---
drivers/tty/serial/8250/8250_mtk.c | 211 ++++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 7 ++
drivers/tty/serial/8250/Makefile | 1 +
3 files changed, 219 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_mtk.c
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
new file mode 100644
index 0000000..96c72b4
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -0,0 +1,211 @@
+/*
+ * Mediatek 8250 driver.
+ *
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Matthias Brugger <matthias.bgg@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ */
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include "8250.h"
+
+#define MTK_UART_RATE_FIX 0x0D /* UART Rate Fix Register */
+
+struct mtk8250_data {
+ int line;
+ struct clk *clk;
+};
+
+static void
+mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
+{
+ if (!state)
+ pm_runtime_get_sync(port->dev);
+
+ serial8250_do_pm(port, state, old);
+
+ if (state)
+ pm_runtime_put_sync_suspend(port->dev);
+}
+
+static int mtk8250_probe_of(struct uart_port *p,
+ struct mtk8250_data *data)
+{
+ int err;
+ struct device_node *np = p->dev->of_node;
+
+ data->clk = of_clk_get(np, 0);
+ if (IS_ERR(data->clk)) {
+ pr_warn("Can't get timer clock");
+ return PTR_ERR(data->clk);
+ }
+
+ err = clk_prepare_enable(data->clk);
+ if (err) {
+ pr_warn("Can't prepare clock");
+ clk_put(data->clk);
+ return err;
+ }
+ p->uartclk = clk_get_rate(data->clk);
+
+ return 0;
+}
+
+static int mtk8250_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct mtk8250_data *data;
+ int err;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.mapbase = regs->start;
+ uart.port.irq = irq->start;
+ uart.port.pm = mtk8250_do_pm;
+ uart.port.type = PORT_16550;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UART_CAP_HIGHS;
+ uart.port.dev = &pdev->dev;
+
+ uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
+ resource_size(regs));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.regshift = 2;
+ uart.port.private_data = data;
+
+ if (pdev->dev.of_node) {
+ err = mtk8250_probe_of(&uart.port, data);
+ if (err)
+ return err;
+ } else
+ return -ENODEV;
+
+ /* Disable Rate Fix function */
+ writel(0x0, uart.port.membase +
+ (MTK_UART_RATE_FIX << uart.port.regshift));
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0)
+ return data->line;
+
+ platform_set_drvdata(pdev, data);
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static int mtk8250_remove(struct platform_device *pdev)
+{
+ struct mtk8250_data *data = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ serial8250_unregister_port(data->line);
+ if (!IS_ERR(data->clk)) {
+ clk_disable_unprepare(data->clk);
+ clk_put(data->clk);
+ }
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk8250_suspend(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+}
+
+static int mtk8250_resume(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int mtk8250_runtime_suspend(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ if (!IS_ERR(data->clk))
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int mtk8250_runtime_resume(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ if (!IS_ERR(data->clk))
+ clk_prepare_enable(data->clk);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk8250_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
+ SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id mtk8250_of_match[] = {
+ { .compatible = "mediatek,mt6577-uart" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk8250_of_match);
+
+static struct platform_driver mtk8250_platform_driver = {
+ .driver = {
+ .name = "mt6577-uart",
+ .owner = THIS_MODULE,
+ .pm = &mtk8250_pm_ops,
+ .of_match_table = mtk8250_of_match,
+ },
+ .probe = mtk8250_probe,
+ .remove = mtk8250_remove,
+};
+module_platform_driver(mtk8250_platform_driver);
+
+MODULE_AUTHOR("Matthias Brugger");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 349ee59..fac34aa 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -298,3 +298,10 @@ config SERIAL_8250_RT288X
If you have a Ralink RT288x/RT305x SoC based board and want to use the
serial port, say Y to this option. The driver can handle up to 2 serial
ports. If unsure, say N.
+
+config SERIAL_8250_MT6577
+ bool "Mediatek serial port support"
+ depends on SERIAL_8250 && ARCH_MEDIATEK
+ help
+ If you have a Mediatek based board and want to use the
+ serial port, say Y to this option. If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d0..6dcb46b 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
+obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/3] tty: serial: 8250: Add new capability for highspeed register
From: Matthias Brugger @ 2014-08-05 10:54 UTC (permalink / raw)
To: linux-kernel
Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rdunlap,
gregkh, jslaby, grant.likely, matthias.bgg, heikki.krogerus, alan,
paul.gortmaker, asierra, mwelling, dianders, m-karicheri2,
jschultz, mingo, balbi, heiko, devicetree, linux-doc,
linux-serial, linux-api
In-Reply-To: <1407236054-30994-1-git-send-email-matthias.bgg@gmail.com>
This patch adds a new capability to the 8250 driver framework. The Mediatek UART
port has a highspeed register to set the baudrate the port will work with.
This influences the calculation of the divisor.
Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
---
drivers/tty/serial/8250/8250.h | 1 +
drivers/tty/serial/8250/8250_core.c | 47 +++++++++++++++++++++++++++++++++++
include/uapi/linux/serial_reg.h | 6 +++++
3 files changed, 54 insertions(+)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 1ebf853..2b17655 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -70,6 +70,7 @@ struct serial8250_config {
#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */
#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */
#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
+#define UART_CAP_HIGHS (1 << 15) /* UART has a highspeed register (Mediatek) */
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 27f7ad6..a0c531b 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2434,6 +2434,53 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_dl_write(up, quot);
/*
+ * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
+ *
+ * We need to recalcualte the quot register, as the claculation depends
+ * on the vaule in the highspeed register.
+ *
+ * Some baudrates are not supported by the chip, so we use the next
+ * lower rate supported.
+ *
+ * If highspeed register is set to 3, we need to specify sample count
+ * and sample point to increase accuracy. If not, we reset the
+ * registers to their default values.
+ */
+ if (up->port.flags & UART_CAP_HIGHS) {
+ if (baud <= 115200) {
+ serial_port_out(port, UART_MTK_HIGHS, 0x0);
+ } else if (baud <= 576000) {
+ serial_port_out(port, UART_MTK_HIGHS, 0x2);
+
+ /* Set to next lower baudrate supported */
+ if ((baud == 500000) || (baud == 576000))
+ baud = 460800;
+ quot = DIV_ROUND_CLOSEST(port->uartclk, 4 * baud);
+ } else {
+ serial_port_out(port, UART_MTK_HIGHS, 0x3);
+
+ /* Set to highest baudrate supported */
+ if (baud >= 1152000)
+ baud = 1000000;
+ quot = DIV_ROUND_CLOSEST(port->uartclk, 256 * baud);
+ }
+
+ serial_dl_write(up, quot);
+
+ if (baud > 460800) {
+ unsigned int tmp;
+
+ tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud);
+ serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1);
+ serial_port_out(port, UART_MTK_SAMPLE_POINT,
+ (tmp - 2) >> 1);
+ } else {
+ serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00);
+ serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff);
+ }
+ }
+
+ /*
* XR17V35x UARTs have an extra fractional divisor register (DLD)
*
* We need to recalculate all of the registers, because DLM and DLL
diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h
index 99b4705..f6dc97c 100644
--- a/include/uapi/linux/serial_reg.h
+++ b/include/uapi/linux/serial_reg.h
@@ -385,5 +385,11 @@
#define UART_EXAR_TXTRG 0x0a /* Tx FIFO trigger level write-only */
#define UART_EXAR_RXTRG 0x0b /* Rx FIFO trigger level write-only */
+/*
+ * These are definitions for the Mediatek UART
+ */
+#define UART_MTK_HIGHS 0x09 /* Highspeed register */
+#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */
+#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
#endif /* _LINUX_SERIAL_REG_H */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/3] tty: serial: Add mediatek UART driver
From: Matthias Brugger @ 2014-08-05 10:54 UTC (permalink / raw)
To: linux-kernel
Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rdunlap,
gregkh, jslaby, grant.likely, matthias.bgg, heikki.krogerus, alan,
paul.gortmaker, asierra, mwelling, dianders, m-karicheri2,
jschultz, mingo, balbi, heiko, devicetree, linux-doc,
linux-serial, linux-api
This patch set adds support for the UART found in Mediatek SoCs.
The chip is a changed version of a 8250 controller.
Especially it introduces a new register called highspeed. The value
in this register has to be set depending on the baudrate. The value
in the register influences the way the divisor has to be calculated.
The patch series is build against v3.16-rc1 and tested on mt6589. Should
work as well on mt6577 and mt6582.
Thanks,
Matthias
Matthias Brugger (3):
tty: serial: 8250: Add new capability for highspeed register
tty: serial: 8250: Add Mediatek UART driver
DTS: serial: Add bindings documention for the Mediatek UARTs
.../devicetree/bindings/serial/mtk-uart.txt | 19 ++
drivers/tty/serial/8250/8250.h | 1 +
drivers/tty/serial/8250/8250_core.c | 47 +++++
drivers/tty/serial/8250/8250_mtk.c | 211 ++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 7 +
drivers/tty/serial/8250/Makefile | 1 +
include/uapi/linux/serial_reg.h | 6 +
7 files changed, 292 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/mtk-uart.txt
create mode 100644 drivers/tty/serial/8250/8250_mtk.c
--
1.7.9.5
^ permalink raw reply
* Re: [PATCH 1/2] xen: Implement ioctl to restrict privcmd to a specific domain
From: Frediano Ziglio @ 2014-08-05 9:10 UTC (permalink / raw)
To: Konrad Rzeszutek Wilk
Cc: xen-devel, Boris Ostrovsky, linux-api, David Vrabel, linux-kernel
In-Reply-To: <20140804202633.GC6380@laptop.dumpdata.com>
On Mon, 2014-08-04 at 16:26 -0400, Konrad Rzeszutek Wilk wrote:
> On Thu, Jul 31, 2014 at 02:16:44PM +0100, Frediano Ziglio wrote:
> > Add a RESTRICT ioctl to /dev/xen/privcmd, which allows privileged commands
> > file descriptor to be restricted to only working with a particular domain.
>
> I feel I am missing an justification or use case here.
>
Running Qemu in domain0 but not allowing it to mess up with other
domains.
Basically our Qemu version is quite restricted (normal user, chroot,
single domain and others) but still can fully support a virtual machine.
The reason for not using stub domains is mainly for scalability reasons.
Allocating fixed memory for every Qemu running (not taking into account
the missing memory sharing) is quite memory consuming. 4gb dom0 can
support 500 VMs.
Frediano
> >
> > Signed-off-by: Frediano Ziglio <frediano.ziglio@citrix.com>
> > ---
> > drivers/xen/privcmd.c | 209 ++++++-
> > include/uapi/xen/privcmd.h | 6 +
> > include/xen/interface/domctl.h | 1090 ++++++++++++++++++++++++++++++++++++
> > include/xen/interface/hvm/hvm_op.h | 66 +++
> > include/xen/interface/memory.h | 8 +
> > include/xen/interface/xen.h | 1 +
> > 6 files changed, 1373 insertions(+), 7 deletions(-)
> > create mode 100644 include/xen/interface/domctl.h
> >
> > diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
> > index 569a13b..c177850 100644
> > --- a/drivers/xen/privcmd.c
> > +++ b/drivers/xen/privcmd.c
> > @@ -32,6 +32,10 @@
> > #include <xen/xen.h>
> > #include <xen/privcmd.h>
> > #include <xen/interface/xen.h>
> > +#include <xen/interface/sched.h>
> > +#include <xen/interface/memory.h>
> > +#include <xen/interface/domctl.h>
> > +#include <xen/interface/hvm/hvm_op.h>
> > #include <xen/features.h>
> > #include <xen/page.h>
> > #include <xen/xen-ops.h>
> > @@ -43,24 +47,173 @@ MODULE_LICENSE("GPL");
> >
> > #define PRIV_VMA_LOCKED ((void *)1)
> >
> > +#define UNRESTRICTED_DOMID ((domid_t)-1)
> > +
> > static int privcmd_vma_range_is_mapped(
> > struct vm_area_struct *vma,
> > unsigned long addr,
> > unsigned long nr_pages);
> >
> > -static long privcmd_ioctl_hypercall(void __user *udata)
> > +struct privcmd_check_buf {
> > + unsigned copy_back;
> > + void __user *copy_ptr;
> > + union {
> > + struct sched_remote_shutdown remote_shutdown;
> > + struct xen_memory_exchange mem_exchange;
> > + struct xen_domctl domctl;
> > + unsigned char buf[1];
> > + } u;
> > +};
> > +
> > +static long privcmd_check_hypercall(struct privcmd_hypercall *hypercall,
> > + struct privcmd_check *check,
> > + domid_t restrict_domid)
> > +{
> > +#define DOMID_AT(type, field) do { \
> > + BUILD_BUG_ON(sizeof(type) > sizeof(check->u)); \
> > + BUILD_BUG_ON(sizeof(((type *) 0)->field) != sizeof(domid_t)); \
> > + check->copy_back = sizeof(type); \
> > + domid_offset = offsetof(type, field); \
> > + } while (0)
> > +
> > +/* we copy from userspace and replace arguments to avoid unsafe data */
> > +#define FETCH_ARG(dest, arg_num, size) do { \
> > + check->copy_ptr = (void *) (long) hypercall->arg[arg_num]; \
> > + if (copy_from_user(dest, check->copy_ptr, size)) \
> > + return -EFAULT; \
> > + hypercall->arg[arg_num] = (long) dest; \
> > + } while (0)
> > +
> > + unsigned domid_offset;
> > +
> > + /* default to invalid so on cases not handled we fail */
> > + domid_t domid = UNRESTRICTED_DOMID;
> > +
> > + switch (hypercall->op) {
> > + case __HYPERVISOR_sched_op:
> > + if (hypercall->arg[0] == SCHEDOP_remote_shutdown) {
> > + FETCH_ARG(&check->u.remote_shutdown, 1,
> > + sizeof(check->u.remote_shutdown));
> > + domid = check->u.remote_shutdown.domain_id;
> > + }
> > + break;
> > +
> > + case __HYPERVISOR_domctl:
> > + FETCH_ARG(&check->u.domctl, 0, sizeof(check->u.domctl));
> > + check->copy_back = sizeof(check->u.domctl);
> > + /* avoid to create a domain */
> > + if (check->u.domctl.cmd == XEN_DOMCTL_createdomain)
> > + return -EACCES;
> > + /* limit versions to avoid possible future bigger buffer */
> > + if (check->u.domctl.interface_version > XEN_DOMCTL_INTERFACE_VERSION)
> > + return -EACCES;
> > + domid = check->u.domctl.domain;
> > + break;
> > +
> > + case __HYPERVISOR_memory_op:
> > + switch (hypercall->arg[0]) {
> > + case XENMEM_increase_reservation:
> > + case XENMEM_decrease_reservation:
> > + case XENMEM_populate_physmap:
> > + DOMID_AT(struct xen_memory_reservation, domid);
> > + break;
> > + case XENMEM_exchange:
> > + DOMID_AT(struct xen_memory_exchange, in.domid);
> > + break;
> > + case XENMEM_current_reservation:
> > + case XENMEM_maximum_reservation:
> > + case XENMEM_maximum_gpfn:
> > + check->copy_back = sizeof(domid);
> > + domid_offset = 0;
> > + break;
> > + case XENMEM_add_to_physmap:
> > + DOMID_AT(struct xen_add_to_physmap, domid);
> > + break;
> > + case XENMEM_set_memory_map:
> > + DOMID_AT(struct xen_foreign_memory_map, domid);
> > + break;
> > + default:
> > + return -EACCES;
> > + }
> > + FETCH_ARG(&check->u, 1, check->copy_back);
> > + domid = *((domid_t *) &check->u.buf[domid_offset]);
> > +
> > + /* extra check for XENMEM_exchange, exchange in the same
> > + * domain */
> > + if (hypercall->arg[0] == XENMEM_exchange &&
> > + check->u.mem_exchange.in.domid != check->u.mem_exchange.out.domid)
> > + return -EACCES;
> > + break;
> > +
> > + case __HYPERVISOR_hvm_op:
> > + switch (hypercall->arg[0]) {
> > + case HVMOP_set_param:
> > + case HVMOP_get_param:
> > + DOMID_AT(struct xen_hvm_param, domid);
> > + break;
> > + case HVMOP_set_pci_intx_level:
> > + DOMID_AT(struct xen_hvm_set_pci_intx_level, domid);
> > + break;
> > + case HVMOP_set_isa_irq_level:
> > + DOMID_AT(struct xen_hvm_set_isa_irq_level, domid);
> > + break;
> > + case HVMOP_set_pci_link_route:
> > + DOMID_AT(struct xen_hvm_set_pci_link_route, domid);
> > + break;
> > + case HVMOP_modified_memory:
> > + DOMID_AT(struct xen_hvm_modified_memory, domid);
> > + break;
> > + case HVMOP_set_mem_type:
> > + DOMID_AT(struct xen_hvm_set_mem_type, domid);
> > + break;
> > + case HVMOP_track_dirty_vram:
> > + DOMID_AT(struct xen_hvm_track_dirty_vram, domid);
> > + break;
> > + default:
> > + return -EACCES;
> > + }
> > + FETCH_ARG(&check->u, 1, check->copy_back);
> > + domid = *((domid_t *) &check->u.buf[domid_offset]);
> > + break;
> > + }
> > +
> > + if (domid != restrict_domid)
> > + return -EACCES;
> > +
> > + return 0;
> > +}
> > +
> > +static long privcmd_ioctl_hypercall(void __user *udata,
> > + domid_t restrict_domid)
> > {
> > struct privcmd_hypercall hypercall;
> > + struct privcmd_check_buf check_buf;
> > long ret;
> >
> > + check_buf.copy_back = 0;
> > + check_buf.copy_ptr = NULL;
> > +
> > if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
> > return -EFAULT;
> >
> > + /* we must check domain we are using */
> > + if (restrict_domid != UNRESTRICTED_DOMID) {
> > + ret = privcmd_check_hypercall(&hypercall, &check_buf,
> > + restrict_domid);
> > + if (ret)
> > + return ret;
> > + }
> > +
> > ret = privcmd_call(hypercall.op,
> > hypercall.arg[0], hypercall.arg[1],
> > hypercall.arg[2], hypercall.arg[3],
> > hypercall.arg[4]);
> >
> > + if (check_buf.copy_back && check_buf.copy_ptr && ret >= 0)
> > + if (copy_to_user(check_buf.copy_ptr, &check_buf.u,
> > + check_buf.copy_back))
> > + ret = -EFAULT;
> > +
> > return ret;
> > }
> >
> > @@ -193,7 +346,7 @@ static int mmap_mfn_range(void *data, void *state)
> > return 0;
> > }
> >
> > -static long privcmd_ioctl_mmap(void __user *udata)
> > +static long privcmd_ioctl_mmap(void __user *udata, domid_t restrict_domid)
> > {
> > struct privcmd_mmap mmapcmd;
> > struct mm_struct *mm = current->mm;
> > @@ -209,6 +362,10 @@ static long privcmd_ioctl_mmap(void __user *udata)
> > if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
> > return -EFAULT;
> >
> > + if (restrict_domid != UNRESTRICTED_DOMID &&
> > + restrict_domid != mmapcmd.dom)
> > + return -EACCES;
> > +
> > rc = gather_array(&pagelist,
> > mmapcmd.num, sizeof(struct privcmd_mmap_entry),
> > mmapcmd.entry);
> > @@ -367,7 +524,8 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
> >
> > static struct vm_operations_struct privcmd_vm_ops;
> >
> > -static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
> > +static long privcmd_ioctl_mmap_batch(void __user *udata, int version,
> > + domid_t restrict_domid)
> > {
> > int ret;
> > struct privcmd_mmapbatch_v2 m;
> > @@ -397,6 +555,10 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
> > return -EINVAL;
> > }
> >
> > + if (restrict_domid != UNRESTRICTED_DOMID &&
> > + restrict_domid != m.dom)
> > + return -EACCES;
> > +
> > nr_pages = m.num;
> > if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
> > return -EINVAL;
> > @@ -498,27 +660,53 @@ out_unlock:
> > goto out;
> > }
> >
> > +static inline domid_t privcmd_get_restrict_domid(const struct file *file)
> > +{
> > + return (domid_t) (long) file->private_data;
> > +}
> > +
> > +static inline void privcmd_set_restrict_domid(struct file *file,
> > + domid_t domid)
> > +{
> > + file->private_data = (void *) (long) domid;
> > +}
> > +
> > static long privcmd_ioctl(struct file *file,
> > unsigned int cmd, unsigned long data)
> > {
> > int ret = -ENOSYS;
> > void __user *udata = (void __user *) data;
> > + domid_t restrict_domid = privcmd_get_restrict_domid(file);
> >
> > switch (cmd) {
> > case IOCTL_PRIVCMD_HYPERCALL:
> > - ret = privcmd_ioctl_hypercall(udata);
> > + ret = privcmd_ioctl_hypercall(udata, restrict_domid);
> > break;
> >
> > case IOCTL_PRIVCMD_MMAP:
> > - ret = privcmd_ioctl_mmap(udata);
> > + ret = privcmd_ioctl_mmap(udata, restrict_domid);
> > break;
> >
> > case IOCTL_PRIVCMD_MMAPBATCH:
> > - ret = privcmd_ioctl_mmap_batch(udata, 1);
> > + ret = privcmd_ioctl_mmap_batch(udata, 1, restrict_domid);
> > break;
> >
> > case IOCTL_PRIVCMD_MMAPBATCH_V2:
> > - ret = privcmd_ioctl_mmap_batch(udata, 2);
> > + ret = privcmd_ioctl_mmap_batch(udata, 2, restrict_domid);
> > + break;
> > +
> > + case IOCTL_PRIVCMD_RESTRICT_DOMID: {
> > + struct privcmd_restrict_domid prd;
> > +
> > + if (restrict_domid != UNRESTRICTED_DOMID)
> > + return -EACCES;
> > + if (copy_from_user(&prd, udata, sizeof(prd)))
> > + return -EFAULT;
> > + if (prd.domid >= DOMID_FIRST_RESERVED)
> > + return -EINVAL;
> > + privcmd_set_restrict_domid(file, prd.domid);
> > + ret = 0;
> > + }
> > break;
> >
> > default:
> > @@ -593,10 +781,17 @@ static int privcmd_vma_range_is_mapped(
> > is_mapped_fn, NULL) != 0;
> > }
> >
> > +static int privcmd_open(struct inode *ino, struct file *filp)
> > +{
> > + privcmd_set_restrict_domid(filp, UNRESTRICTED_DOMID);
> > + return 0;
> > +}
> > +
> > const struct file_operations xen_privcmd_fops = {
> > .owner = THIS_MODULE,
> > .unlocked_ioctl = privcmd_ioctl,
> > .mmap = privcmd_mmap,
> > + .open = privcmd_open,
> > };
> > EXPORT_SYMBOL_GPL(xen_privcmd_fops);
> >
> > diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h
> > index a853168..461a999 100644
> > --- a/include/uapi/xen/privcmd.h
> > +++ b/include/uapi/xen/privcmd.h
> > @@ -73,6 +73,10 @@ struct privcmd_mmapbatch_v2 {
> > int __user *err; /* array of error codes */
> > };
> >
> > +struct privcmd_restrict_domid {
> > + domid_t domid;
> > +};
> > +
> > /*
> > * @cmd: IOCTL_PRIVCMD_HYPERCALL
> > * @arg: &privcmd_hypercall_t
> > @@ -94,5 +98,7 @@ struct privcmd_mmapbatch_v2 {
> > _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
> > #define IOCTL_PRIVCMD_MMAPBATCH_V2 \
> > _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
> > +#define IOCTL_PRIVCMD_RESTRICT_DOMID \
> > + _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_restrict_domid))
> >
> > #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
> > diff --git a/include/xen/interface/domctl.h b/include/xen/interface/domctl.h
> > new file mode 100644
> > index 0000000..0668fed
> > --- /dev/null
> > +++ b/include/xen/interface/domctl.h
> > @@ -0,0 +1,1090 @@
> > +/******************************************************************************
> > + * domctl.h
> > + *
> > + * Domain management operations. For use by node control stack.
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a copy
> > + * of this software and associated documentation files (the "Software"), to
> > + * deal in the Software without restriction, including without limitation the
> > + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
> > + * sell copies of the Software, and to permit persons to whom the Software is
> > + * furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> > + * DEALINGS IN THE SOFTWARE.
> > + *
> > + * Copyright (c) 2002-2003, B Dragovic
> > + * Copyright (c) 2002-2006, K Fraser
> > + */
> > +
> > +#ifndef __XEN_PUBLIC_DOMCTL_H__
> > +#define __XEN_PUBLIC_DOMCTL_H__
> > +
> > +#include "xen.h"
> > +#include "grant_table.h"
> > +
> > +#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000a
> > +
> > +#if 1
> > +/*
> > + * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
> > + * If it is specified as zero, an id is auto-allocated and returned.
> > + */
> > +/* XEN_DOMCTL_createdomain */
> > +struct xen_domctl_createdomain {
> > + /* IN parameters */
> > + uint32_t ssidref;
> > + xen_domain_handle_t handle;
> > + /* Is this an HVM guest (as opposed to a PVH or PV guest)? */
> > +#define _XEN_DOMCTL_CDF_hvm_guest 0
> > +#define XEN_DOMCTL_CDF_hvm_guest (1U<<_XEN_DOMCTL_CDF_hvm_guest)
> > + /* Use hardware-assisted paging if available? */
> > +#define _XEN_DOMCTL_CDF_hap 1
> > +#define XEN_DOMCTL_CDF_hap (1U<<_XEN_DOMCTL_CDF_hap)
> > + /* Should domain memory integrity be verifed by tboot during Sx? */
> > +#define _XEN_DOMCTL_CDF_s3_integrity 2
> > +#define XEN_DOMCTL_CDF_s3_integrity (1U<<_XEN_DOMCTL_CDF_s3_integrity)
> > + /* Disable out-of-sync shadow page tables? */
> > +#define _XEN_DOMCTL_CDF_oos_off 3
> > +#define XEN_DOMCTL_CDF_oos_off (1U<<_XEN_DOMCTL_CDF_oos_off)
> > + /* Is this a PVH guest (as opposed to an HVM or PV guest)? */
> > +#define _XEN_DOMCTL_CDF_pvh_guest 4
> > +#define XEN_DOMCTL_CDF_pvh_guest (1U<<_XEN_DOMCTL_CDF_pvh_guest)
> > + uint32_t flags;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_createdomain);
> > +
> > +/* XEN_DOMCTL_getdomaininfo */
> > +struct xen_domctl_getdomaininfo {
> > + /* OUT variables. */
> > + domid_t domain; /* Also echoed in domctl.domain */
> > + /* Domain is scheduled to die. */
> > +#define _XEN_DOMINF_dying 0
> > +#define XEN_DOMINF_dying (1U<<_XEN_DOMINF_dying)
> > + /* Domain is an HVM guest (as opposed to a PV guest). */
> > +#define _XEN_DOMINF_hvm_guest 1
> > +#define XEN_DOMINF_hvm_guest (1U<<_XEN_DOMINF_hvm_guest)
> > + /* The guest OS has shut down. */
> > +#define _XEN_DOMINF_shutdown 2
> > +#define XEN_DOMINF_shutdown (1U<<_XEN_DOMINF_shutdown)
> > + /* Currently paused by control software. */
> > +#define _XEN_DOMINF_paused 3
> > +#define XEN_DOMINF_paused (1U<<_XEN_DOMINF_paused)
> > + /* Currently blocked pending an event. */
> > +#define _XEN_DOMINF_blocked 4
> > +#define XEN_DOMINF_blocked (1U<<_XEN_DOMINF_blocked)
> > + /* Domain is currently running. */
> > +#define _XEN_DOMINF_running 5
> > +#define XEN_DOMINF_running (1U<<_XEN_DOMINF_running)
> > + /* Being debugged. */
> > +#define _XEN_DOMINF_debugged 6
> > +#define XEN_DOMINF_debugged (1U<<_XEN_DOMINF_debugged)
> > +/* domain is PVH */
> > +#define _XEN_DOMINF_pvh_guest 7
> > +#define XEN_DOMINF_pvh_guest (1U<<_XEN_DOMINF_pvh_guest)
> > + /* XEN_DOMINF_shutdown guest-supplied code. */
> > +#define XEN_DOMINF_shutdownmask 255
> > +#define XEN_DOMINF_shutdownshift 16
> > + uint32_t flags; /* XEN_DOMINF_* */
> > + aligned_u64 tot_pages;
> > + aligned_u64 max_pages;
> > + aligned_u64 outstanding_pages;
> > + aligned_u64 shr_pages;
> > + aligned_u64 paged_pages;
> > + aligned_u64 shared_info_frame; /* GMFN of shared_info struct */
> > + aligned_u64 cpu_time;
> > + uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
> > + uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
> > + uint32_t ssidref;
> > + xen_domain_handle_t handle;
> > + uint32_t cpupool;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getdomaininfo);
> > +
> > +
> > +/* XEN_DOMCTL_getmemlist */
> > +struct xen_domctl_getmemlist {
> > + /* IN variables. */
> > + /* Max entries to write to output buffer. */
> > + aligned_u64 max_pfns;
> > + /* Start index in guest's page list. */
> > + aligned_u64 start_pfn;
> > + GUEST_HANDLE(uint64_t) buffer;
> > + /* OUT variables. */
> > + aligned_u64 num_pfns;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getmemlist);
> > +
> > +
> > +/* XEN_DOMCTL_getpageframeinfo */
> > +
> > +#define XEN_DOMCTL_PFINFO_LTAB_SHIFT 28
> > +#define XEN_DOMCTL_PFINFO_NOTAB (0x0U<<28)
> > +#define XEN_DOMCTL_PFINFO_L1TAB (0x1U<<28)
> > +#define XEN_DOMCTL_PFINFO_L2TAB (0x2U<<28)
> > +#define XEN_DOMCTL_PFINFO_L3TAB (0x3U<<28)
> > +#define XEN_DOMCTL_PFINFO_L4TAB (0x4U<<28)
> > +#define XEN_DOMCTL_PFINFO_LTABTYPE_MASK (0x7U<<28)
> > +#define XEN_DOMCTL_PFINFO_LPINTAB (0x1U<<31)
> > +#define XEN_DOMCTL_PFINFO_XTAB (0xfU<<28) /* invalid page */
> > +#define XEN_DOMCTL_PFINFO_XALLOC (0xeU<<28) /* allocate-only page */
> > +#define XEN_DOMCTL_PFINFO_BROKEN (0xdU<<28) /* broken page */
> > +#define XEN_DOMCTL_PFINFO_LTAB_MASK (0xfU<<28)
> > +
> > +struct xen_domctl_getpageframeinfo {
> > + /* IN variables. */
> > + aligned_u64 gmfn; /* GMFN to query */
> > + /* OUT variables. */
> > + /* Is the page PINNED to a type? */
> > + uint32_t type; /* see above type defs */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getpageframeinfo);
> > +
> > +
> > +/* XEN_DOMCTL_getpageframeinfo2 */
> > +struct xen_domctl_getpageframeinfo2 {
> > + /* IN variables. */
> > + aligned_u64 num;
> > + /* IN/OUT variables. */
> > + GUEST_HANDLE(uint32_t) array;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getpageframeinfo2);
> > +
> > +/* XEN_DOMCTL_getpageframeinfo3 */
> > +struct xen_domctl_getpageframeinfo3 {
> > + /* IN variables. */
> > + aligned_u64 num;
> > + /* IN/OUT variables. */
> > + GUEST_HANDLE(xen_pfn_t) array;
> > +};
> > +
> > +
> > +/*
> > + * Control shadow pagetables operation
> > + */
> > +/* XEN_DOMCTL_shadow_op */
> > +
> > +/* Disable shadow mode. */
> > +#define XEN_DOMCTL_SHADOW_OP_OFF 0
> > +
> > +/* Enable shadow mode (mode contains ORed XEN_DOMCTL_SHADOW_ENABLE_* flags). */
> > +#define XEN_DOMCTL_SHADOW_OP_ENABLE 32
> > +
> > +/* Log-dirty bitmap operations. */
> > + /* Return the bitmap and clean internal copy for next round. */
> > +#define XEN_DOMCTL_SHADOW_OP_CLEAN 11
> > + /* Return the bitmap but do not modify internal copy. */
> > +#define XEN_DOMCTL_SHADOW_OP_PEEK 12
> > +
> > +/* Memory allocation accessors. */
> > +#define XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION 30
> > +#define XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION 31
> > +
> > +/* Legacy enable operations. */
> > + /* Equiv. to ENABLE with no mode flags. */
> > +#define XEN_DOMCTL_SHADOW_OP_ENABLE_TEST 1
> > + /* Equiv. to ENABLE with mode flag ENABLE_LOG_DIRTY. */
> > +#define XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY 2
> > + /* Equiv. to ENABLE with mode flags ENABLE_REFCOUNT and ENABLE_TRANSLATE. */
> > +#define XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE 3
> > +
> > +/* Mode flags for XEN_DOMCTL_SHADOW_OP_ENABLE. */
> > + /*
> > + * Shadow pagetables are refcounted: guest does not use explicit mmu
> > + * operations nor write-protect its pagetables.
> > + */
> > +#define XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT (1 << 1)
> > + /*
> > + * Log pages in a bitmap as they are dirtied.
> > + * Used for live relocation to determine which pages must be re-sent.
> > + */
> > +#define XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY (1 << 2)
> > + /*
> > + * Automatically translate GPFNs into MFNs.
> > + */
> > +#define XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE (1 << 3)
> > + /*
> > + * Xen does not steal virtual address space from the guest.
> > + * Requires HVM support.
> > + */
> > +#define XEN_DOMCTL_SHADOW_ENABLE_EXTERNAL (1 << 4)
> > +
> > +struct xen_domctl_shadow_op_stats {
> > + uint32_t fault_count;
> > + uint32_t dirty_count;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_shadow_op_stats);
> > +
> > +struct xen_domctl_shadow_op {
> > + /* IN variables. */
> > + uint32_t op; /* XEN_DOMCTL_SHADOW_OP_* */
> > +
> > + /* OP_ENABLE */
> > + uint32_t mode; /* XEN_DOMCTL_SHADOW_ENABLE_* */
> > +
> > + /* OP_GET_ALLOCATION / OP_SET_ALLOCATION */
> > + uint32_t mb; /* Shadow memory allocation in MB */
> > +
> > + /* OP_PEEK / OP_CLEAN */
> > + GUEST_HANDLE(uchar) dirty_bitmap;
> > + aligned_u64 pages; /* Size of buffer. Updated with actual size. */
> > + struct xen_domctl_shadow_op_stats stats;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_shadow_op);
> > +
> > +
> > +/* XEN_DOMCTL_max_mem */
> > +struct xen_domctl_max_mem {
> > + /* IN variables. */
> > + aligned_u64 max_memkb;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_max_mem);
> > +
> > +
> > +/* XEN_DOMCTL_setvcpucontext */
> > +/* XEN_DOMCTL_getvcpucontext */
> > +struct xen_domctl_vcpucontext {
> > + uint32_t vcpu; /* IN */
> > + GUEST_HANDLE(vcpu_guest_context) ctxt; /* IN/OUT */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpucontext);
> > +
> > +
> > +/* XEN_DOMCTL_getvcpuinfo */
> > +struct xen_domctl_getvcpuinfo {
> > + /* IN variables. */
> > + uint32_t vcpu;
> > + /* OUT variables. */
> > + uint8_t online; /* currently online (not hotplugged)? */
> > + uint8_t blocked; /* blocked waiting for an event? */
> > + uint8_t running; /* currently scheduled on its CPU? */
> > + aligned_u64 cpu_time; /* total cpu time consumed (ns) */
> > + uint32_t cpu; /* current mapping */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getvcpuinfo);
> > +
> > +#if 0
> > +/* Get/set the NUMA node(s) with which the guest has affinity with. */
> > +/* XEN_DOMCTL_setnodeaffinity */
> > +/* XEN_DOMCTL_getnodeaffinity */
> > +struct xen_domctl_nodeaffinity {
> > + struct xenctl_bitmap nodemap;/* IN */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_nodeaffinity);
> > +
> > +
> > +/* Get/set which physical cpus a vcpu can execute on. */
> > +/* XEN_DOMCTL_setvcpuaffinity */
> > +/* XEN_DOMCTL_getvcpuaffinity */
> > +struct xen_domctl_vcpuaffinity {
> > + uint32_t vcpu; /* IN */
> > + struct xenctl_bitmap cpumap; /* IN/OUT */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpuaffinity);
> > +#endif
> > +
> > +
> > +/* XEN_DOMCTL_max_vcpus */
> > +struct xen_domctl_max_vcpus {
> > + uint32_t max; /* maximum number of vcpus */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_max_vcpus);
> > +
> > +
> > +/* XEN_DOMCTL_scheduler_op */
> > +/* Scheduler types. */
> > +#define XEN_SCHEDULER_SEDF 4
> > +#define XEN_SCHEDULER_CREDIT 5
> > +#define XEN_SCHEDULER_CREDIT2 6
> > +#define XEN_SCHEDULER_ARINC653 7
> > +/* Set or get info? */
> > +#define XEN_DOMCTL_SCHEDOP_putinfo 0
> > +#define XEN_DOMCTL_SCHEDOP_getinfo 1
> > +struct xen_domctl_scheduler_op {
> > + uint32_t sched_id; /* XEN_SCHEDULER_* */
> > + uint32_t cmd; /* XEN_DOMCTL_SCHEDOP_* */
> > + union {
> > + struct xen_domctl_sched_sedf {
> > + aligned_u64 period;
> > + aligned_u64 slice;
> > + aligned_u64 latency;
> > + uint32_t extratime;
> > + uint32_t weight;
> > + } sedf;
> > + struct xen_domctl_sched_credit {
> > + uint16_t weight;
> > + uint16_t cap;
> > + } credit;
> > + struct xen_domctl_sched_credit2 {
> > + uint16_t weight;
> > + } credit2;
> > + } u;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_scheduler_op);
> > +
> > +
> > +/* XEN_DOMCTL_setdomainhandle */
> > +struct xen_domctl_setdomainhandle {
> > + xen_domain_handle_t handle;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_setdomainhandle);
> > +
> > +
> > +/* XEN_DOMCTL_setdebugging */
> > +struct xen_domctl_setdebugging {
> > + uint8_t enable;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_setdebugging);
> > +
> > +
> > +/* XEN_DOMCTL_irq_permission */
> > +struct xen_domctl_irq_permission {
> > + uint8_t pirq;
> > + uint8_t allow_access; /* flag to specify enable/disable of IRQ access */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_irq_permission);
> > +
> > +
> > +/* XEN_DOMCTL_iomem_permission */
> > +struct xen_domctl_iomem_permission {
> > + aligned_u64 first_mfn;/* first page (physical page number) in range */
> > + aligned_u64 nr_mfns; /* number of pages in range (>0) */
> > + uint8_t allow_access; /* allow (!0) or deny (0) access to range? */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_iomem_permission);
> > +
> > +
> > +/* XEN_DOMCTL_ioport_permission */
> > +struct xen_domctl_ioport_permission {
> > + uint32_t first_port; /* first port int range */
> > + uint32_t nr_ports; /* size of port range */
> > + uint8_t allow_access; /* allow or deny access to range? */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ioport_permission);
> > +
> > +
> > +/* XEN_DOMCTL_hypercall_init */
> > +struct xen_domctl_hypercall_init {
> > + aligned_u64 gmfn; /* GMFN to be initialised */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hypercall_init);
> > +
> > +
> > +/* XEN_DOMCTL_arch_setup */
> > +#define _XEN_DOMAINSETUP_hvm_guest 0
> > +#define XEN_DOMAINSETUP_hvm_guest (1UL<<_XEN_DOMAINSETUP_hvm_guest)
> > +#define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save) */
> > +#define XEN_DOMAINSETUP_query (1UL<<_XEN_DOMAINSETUP_query)
> > +#define _XEN_DOMAINSETUP_sioemu_guest 2
> > +#define XEN_DOMAINSETUP_sioemu_guest (1UL<<_XEN_DOMAINSETUP_sioemu_guest)
> > +struct xen_domctl_arch_setup {
> > + aligned_u64 flags; /* XEN_DOMAINSETUP_* */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_arch_setup);
> > +
> > +
> > +/* XEN_DOMCTL_settimeoffset */
> > +struct xen_domctl_settimeoffset {
> > + int32_t time_offset_seconds; /* applied to domain wallclock time */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_settimeoffset);
> > +
> > +/* XEN_DOMCTL_gethvmcontext */
> > +/* XEN_DOMCTL_sethvmcontext */
> > +struct xen_domctl_hvmcontext {
> > + uint32_t size; /* IN/OUT: size of buffer / bytes filled */
> > + GUEST_HANDLE(uchar) buffer; /* IN/OUT: data, or call
> > + * gethvmcontext with NULL
> > + * buffer to get size req'd */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hvmcontext);
> > +
> > +
> > +/* XEN_DOMCTL_set_address_size */
> > +/* XEN_DOMCTL_get_address_size */
> > +struct xen_domctl_address_size {
> > + uint32_t size;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_address_size);
> > +
> > +
> > +/* XEN_DOMCTL_real_mode_area */
> > +struct xen_domctl_real_mode_area {
> > + uint32_t log; /* log2 of Real Mode Area size */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_real_mode_area);
> > +
> > +
> > +/* XEN_DOMCTL_sendtrigger */
> > +#define XEN_DOMCTL_SENDTRIGGER_NMI 0
> > +#define XEN_DOMCTL_SENDTRIGGER_RESET 1
> > +#define XEN_DOMCTL_SENDTRIGGER_INIT 2
> > +#define XEN_DOMCTL_SENDTRIGGER_POWER 3
> > +#define XEN_DOMCTL_SENDTRIGGER_SLEEP 4
> > +struct xen_domctl_sendtrigger {
> > + uint32_t trigger; /* IN */
> > + uint32_t vcpu; /* IN */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_sendtrigger);
> > +
> > +
> > +/* Assign PCI device to HVM guest. Sets up IOMMU structures. */
> > +/* XEN_DOMCTL_assign_device */
> > +/* XEN_DOMCTL_test_assign_device */
> > +/* XEN_DOMCTL_deassign_device */
> > +struct xen_domctl_assign_device {
> > + uint32_t machine_sbdf; /* machine PCI ID of assigned device */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_assign_device);
> > +
> > +/* Retrieve sibling devices infomation of machine_sbdf */
> > +/* XEN_DOMCTL_get_device_group */
> > +struct xen_domctl_get_device_group {
> > + uint32_t machine_sbdf; /* IN */
> > + uint32_t max_sdevs; /* IN */
> > + uint32_t num_sdevs; /* OUT */
> > + GUEST_HANDLE(uint32_t) sdev_array; /* OUT */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_get_device_group);
> > +
> > +/* Pass-through interrupts: bind real irq -> hvm devfn. */
> > +/* XEN_DOMCTL_bind_pt_irq */
> > +/* XEN_DOMCTL_unbind_pt_irq */
> > +enum pt_irq_type_e {
> > + PT_IRQ_TYPE_PCI,
> > + PT_IRQ_TYPE_ISA,
> > + PT_IRQ_TYPE_MSI,
> > + PT_IRQ_TYPE_MSI_TRANSLATE,
> > +};
> > +struct xen_domctl_bind_pt_irq {
> > + uint32_t machine_irq;
> > + enum pt_irq_type_e irq_type;
> > + uint32_t hvm_domid;
> > +
> > + union {
> > + struct {
> > + uint8_t isa_irq;
> > + } isa;
> > + struct {
> > + uint8_t bus;
> > + uint8_t device;
> > + uint8_t intx;
> > + } pci;
> > + struct {
> > + uint8_t gvec;
> > + uint32_t gflags;
> > + aligned_u64 gtable;
> > + } msi;
> > + } u;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_bind_pt_irq);
> > +
> > +
> > +/* Bind machine I/O address range -> HVM address range. */
> > +/* XEN_DOMCTL_memory_mapping */
> > +#define DPCI_ADD_MAPPING 1
> > +#define DPCI_REMOVE_MAPPING 0
> > +struct xen_domctl_memory_mapping {
> > + aligned_u64 first_gfn; /* first page (hvm guest phys page) in range */
> > + aligned_u64 first_mfn; /* first page (machine page) in range */
> > + aligned_u64 nr_mfns; /* number of pages in range (>0) */
> > + uint32_t add_mapping; /* add or remove mapping */
> > + uint32_t padding; /* padding for 64-bit aligned structure */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_memory_mapping);
> > +
> > +
> > +/* Bind machine I/O port range -> HVM I/O port range. */
> > +/* XEN_DOMCTL_ioport_mapping */
> > +struct xen_domctl_ioport_mapping {
> > + uint32_t first_gport; /* first guest IO port*/
> > + uint32_t first_mport; /* first machine IO port */
> > + uint32_t nr_ports; /* size of port range */
> > + uint32_t add_mapping; /* add or remove mapping */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ioport_mapping);
> > +
> > +
> > +/*
> > + * Pin caching type of RAM space for x86 HVM domU.
> > + */
> > +/* XEN_DOMCTL_pin_mem_cacheattr */
> > +/* Caching types: these happen to be the same as x86 MTRR/PAT type codes. */
> > +#define XEN_DOMCTL_MEM_CACHEATTR_UC 0
> > +#define XEN_DOMCTL_MEM_CACHEATTR_WC 1
> > +#define XEN_DOMCTL_MEM_CACHEATTR_WT 4
> > +#define XEN_DOMCTL_MEM_CACHEATTR_WP 5
> > +#define XEN_DOMCTL_MEM_CACHEATTR_WB 6
> > +#define XEN_DOMCTL_MEM_CACHEATTR_UCM 7
> > +struct xen_domctl_pin_mem_cacheattr {
> > + aligned_u64 start, end;
> > + uint32_t type; /* XEN_DOMCTL_MEM_CACHEATTR_* */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_pin_mem_cacheattr);
> > +
> > +
> > +#if 0
> > +/* XEN_DOMCTL_set_ext_vcpucontext */
> > +/* XEN_DOMCTL_get_ext_vcpucontext */
> > +struct xen_domctl_ext_vcpucontext {
> > + /* IN: VCPU that this call applies to. */
> > + uint32_t vcpu;
> > + /*
> > + * SET: Size of struct (IN)
> > + * GET: Size of struct (OUT, up to 128 bytes)
> > + */
> > + uint32_t size;
> > +#if defined(__i386__) || defined(__x86_64__)
> > + /* SYSCALL from 32-bit mode and SYSENTER callback information. */
> > + /* NB. SYSCALL from 64-bit mode is contained in vcpu_guest_context_t */
> > + aligned_u64 syscall32_callback_eip;
> > + aligned_u64 sysenter_callback_eip;
> > + uint16_t syscall32_callback_cs;
> > + uint16_t sysenter_callback_cs;
> > + uint8_t syscall32_disables_events;
> > + uint8_t sysenter_disables_events;
> > +#if defined(__GNUC__)
> > + union {
> > + aligned_u64 mcg_cap;
> > + struct hvm_vmce_vcpu vmce;
> > + };
> > +#else
> > + struct hvm_vmce_vcpu vmce;
> > +#endif
> > +#endif
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ext_vcpucontext);
> > +#endif
> > +
> > +/*
> > + * Set the target domain for a domain
> > + */
> > +/* XEN_DOMCTL_set_target */
> > +struct xen_domctl_set_target {
> > + domid_t target;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_target);
> > +
> > +#if defined(__i386__) || defined(__x86_64__)
> > +# define XEN_CPUID_INPUT_UNUSED 0xFFFFFFFF
> > +/* XEN_DOMCTL_set_cpuid */
> > +struct xen_domctl_cpuid {
> > + uint32_t input[2];
> > + uint32_t eax;
> > + uint32_t ebx;
> > + uint32_t ecx;
> > + uint32_t edx;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_cpuid);
> > +#endif
> > +
> > +/*
> > + * Arranges that if the domain suspends (specifically, if it shuts
> > + * down with code SHUTDOWN_suspend), this event channel will be
> > + * notified.
> > + *
> > + * This is _instead of_ the usual notification to the global
> > + * VIRQ_DOM_EXC. (In most systems that pirq is owned by xenstored.)
> > + *
> > + * Only one subscription per domain is possible. Last subscriber
> > + * wins; others are silently displaced.
> > + *
> > + * NB that contrary to the rather general name, it only applies to
> > + * domain shutdown with code suspend. Shutdown for other reasons
> > + * (including crash), and domain death, are notified to VIRQ_DOM_EXC
> > + * regardless.
> > + */
> > +/* XEN_DOMCTL_subscribe */
> > +struct xen_domctl_subscribe {
> > + uint32_t port; /* IN */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_subscribe);
> > +
> > +/*
> > + * Define the maximum machine address size which should be allocated
> > + * to a guest.
> > + */
> > +/* XEN_DOMCTL_set_machine_address_size */
> > +/* XEN_DOMCTL_get_machine_address_size */
> > +
> > +/*
> > + * Do not inject spurious page faults into this domain.
> > + */
> > +/* XEN_DOMCTL_suppress_spurious_page_faults */
> > +
> > +/* XEN_DOMCTL_debug_op */
> > +#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF 0
> > +#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON 1
> > +struct xen_domctl_debug_op {
> > + uint32_t op; /* IN */
> > + uint32_t vcpu; /* IN */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_debug_op);
> > +
> > +/*
> > + * Request a particular record from the HVM context
> > + */
> > +/* XEN_DOMCTL_gethvmcontext_partial */
> > +struct xen_domctl_hvmcontext_partial {
> > + uint32_t type; /* IN: Type of record required */
> > + uint32_t instance; /* IN: Instance of that type */
> > + GUEST_HANDLE(uchar) buffer; /* OUT: buffer to write record into */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hvmcontext_partial);
> > +
> > +/* XEN_DOMCTL_disable_migrate */
> > +struct xen_domctl_disable_migrate {
> > + uint32_t disable; /* IN: 1: disable migration and restore */
> > +};
> > +
> > +
> > +/* XEN_DOMCTL_gettscinfo */
> > +/* XEN_DOMCTL_settscinfo */
> > +struct xen_guest_tsc_info {
> > + uint32_t tsc_mode;
> > + uint32_t gtsc_khz;
> > + uint32_t incarnation;
> > + uint32_t pad;
> > + aligned_u64 elapsed_nsec;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_guest_tsc_info);
> > +
> > +struct xen_domctl_tsc_info {
> > + GUEST_HANDLE(xen_guest_tsc_info) out_info; /* OUT */
> > + struct xen_guest_tsc_info info; /* IN */
> > +};
> > +
> > +/* XEN_DOMCTL_gdbsx_guestmemio guest mem io */
> > +struct xen_domctl_gdbsx_memio {
> > + /* IN */
> > + aligned_u64 pgd3val;/* optional: init_mm.pgd[3] value */
> > + aligned_u64 gva; /* guest virtual address */
> > + aligned_u64 uva; /* user buffer virtual address */
> > + uint32_t len; /* number of bytes to read/write */
> > + uint8_t gwr; /* 0 = read from guest. 1 = write to guest */
> > + /* OUT */
> > + uint32_t remain; /* bytes remaining to be copied */
> > +};
> > +
> > +/* XEN_DOMCTL_gdbsx_pausevcpu */
> > +/* XEN_DOMCTL_gdbsx_unpausevcpu */
> > +struct xen_domctl_gdbsx_pauseunp_vcpu { /* pause/unpause a vcpu */
> > + uint32_t vcpu; /* which vcpu */
> > +};
> > +
> > +/* XEN_DOMCTL_gdbsx_domstatus */
> > +struct xen_domctl_gdbsx_domstatus {
> > + /* OUT */
> > + uint8_t paused; /* is the domain paused */
> > + uint32_t vcpu_id; /* any vcpu in an event? */
> > + uint32_t vcpu_ev; /* if yes, what event? */
> > +};
> > +
> > +/*
> > + * Memory event operations
> > + */
> > +
> > +/* XEN_DOMCTL_mem_event_op */
> > +
> > +/*
> > + * Domain memory paging
> > + * Page memory in and out.
> > + * Domctl interface to set up and tear down the
> > + * pager<->hypervisor interface. Use XENMEM_paging_op*
> > + * to perform per-page operations.
> > + *
> > + * The XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE domctl returns several
> > + * non-standard error codes to indicate why paging could not be enabled:
> > + * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> > + * EMLINK - guest has iommu passthrough enabled
> > + * EXDEV - guest has PoD enabled
> > + * EBUSY - guest has or had paging enabled, ring buffer still active
> > + */
> > +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING 1
> > +
> > +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE 0
> > +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING_DISABLE 1
> > +
> > +/*
> > + * Access permissions.
> > + *
> > + * As with paging, use the domctl for teardown/setup of the
> > + * helper<->hypervisor interface.
> > + *
> > + * There are HVM hypercalls to set the per-page access permissions of every
> > + * page in a domain. When one of these permissions--independent, read,
> > + * write, and execute--is violated, the VCPU is paused and a memory event
> > + * is sent with what happened. (See public/mem_event.h) .
> > + *
> > + * The memory event handler can then resume the VCPU and redo the access
> > + * with a XENMEM_access_op_resume hypercall.
> > + *
> > + * The XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE domctl returns several
> > + * non-standard error codes to indicate why access could not be enabled:
> > + * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> > + * EBUSY - guest has or had access enabled, ring buffer still active
> > + */
> > +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS 2
> > +
> > +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE 0
> > +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE 1
> > +
> > +/*
> > + * Sharing ENOMEM helper.
> > + *
> > + * As with paging, use the domctl for teardown/setup of the
> > + * helper<->hypervisor interface.
> > + *
> > + * If setup, this ring is used to communicate failed allocations
> > + * in the unshare path. XENMEM_sharing_op_resume is used to wake up
> > + * vcpus that could not unshare.
> > + *
> > + * Note that shring can be turned on (as per the domctl below)
> > + * *without* this ring being setup.
> > + */
> > +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING 3
> > +
> > +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING_ENABLE 0
> > +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING_DISABLE 1
> > +
> > +/* Use for teardown/setup of helper<->hypervisor interface for paging,
> > + * access and sharing.*/
> > +struct xen_domctl_mem_event_op {
> > + uint32_t op; /* XEN_DOMCTL_MEM_EVENT_OP_*_* */
> > + uint32_t mode; /* XEN_DOMCTL_MEM_EVENT_OP_* */
> > +
> > + uint32_t port; /* OUT: event channel for ring */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_mem_event_op);
> > +
> > +/*
> > + * Memory sharing operations
> > + */
> > +/* XEN_DOMCTL_mem_sharing_op.
> > + * The CONTROL sub-domctl is used for bringup/teardown. */
> > +#define XEN_DOMCTL_MEM_SHARING_CONTROL 0
> > +
> > +struct xen_domctl_mem_sharing_op {
> > + uint8_t op; /* XEN_DOMCTL_MEM_SHARING_* */
> > +
> > + union {
> > + uint8_t enable; /* CONTROL */
> > + } u;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_mem_sharing_op);
> > +
> > +struct xen_domctl_audit_p2m {
> > + /* OUT error counts */
> > + uint64_t orphans;
> > + uint64_t m2p_bad;
> > + uint64_t p2m_bad;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_audit_p2m);
> > +
> > +struct xen_domctl_set_virq_handler {
> > + uint32_t virq; /* IN */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_virq_handler);
> > +
> > +#if defined(__i386__) || defined(__x86_64__)
> > +/* XEN_DOMCTL_setvcpuextstate */
> > +/* XEN_DOMCTL_getvcpuextstate */
> > +struct xen_domctl_vcpuextstate {
> > + /* IN: VCPU that this call applies to. */
> > + uint32_t vcpu;
> > + /*
> > + * SET: Ignored.
> > + * GET: xfeature support mask of struct (IN/OUT)
> > + * xfeature mask is served as identifications of the saving format
> > + * so that compatible CPUs can have a check on format to decide
> > + * whether it can restore.
> > + */
> > + aligned_u64 xfeature_mask;
> > + /*
> > + * SET: Size of struct (IN)
> > + * GET: Size of struct (IN/OUT)
> > + */
> > + aligned_u64 size;
> > + GUEST_HANDLE(uint64_t) buffer;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpuextstate);
> > +#endif
> > +
> > +/* XEN_DOMCTL_set_access_required: sets whether a memory event listener
> > + * must be present to handle page access events: if false, the page
> > + * access will revert to full permissions if no one is listening;
> > + * */
> > +struct xen_domctl_set_access_required {
> > + uint8_t access_required;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_access_required);
> > +
> > +struct xen_domctl_set_broken_page_p2m {
> > + aligned_u64 pfn;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_broken_page_p2m);
> > +
> > +/*
> > + * XEN_DOMCTL_set_max_evtchn: sets the maximum event channel port
> > + * number the guest may use. Use this limit the amount of resources
> > + * (global mapping space, xenheap) a guest may use for event channels.
> > + */
> > +struct xen_domctl_set_max_evtchn {
> > + uint32_t max_port;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_max_evtchn);
> > +
> > +/*
> > + * ARM: Clean and invalidate caches associated with given region of
> > + * guest memory.
> > + */
> > +struct xen_domctl_cacheflush {
> > + /* IN: page range to flush. */
> > + xen_pfn_t start_pfn, nr_pfns;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_cacheflush);
> > +
> > +#if defined(__i386__) || defined(__x86_64__)
> > +struct xen_domctl_vcpu_msr {
> > + uint32_t index;
> > + uint32_t reserved;
> > + aligned_u64 value;
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpu_msr);
> > +
> > +/*
> > + * XEN_DOMCTL_set_vcpu_msrs / XEN_DOMCTL_get_vcpu_msrs.
> > + *
> > + * Input:
> > + * - A NULL 'msrs' guest handle is a request for the maximum 'msr_count'.
> > + * - Otherwise, 'msr_count' is the number of entries in 'msrs'.
> > + *
> > + * Output for get:
> > + * - If 'msr_count' is less than the number Xen needs to write, -ENOBUFS shall
> > + * be returned and 'msr_count' updated to reflect the intended number.
> > + * - On success, 'msr_count' shall indicate the number of MSRs written, which
> > + * may be less than the maximum if some are not currently used by the vcpu.
> > + *
> > + * Output for set:
> > + * - If Xen encounters an error with a specific MSR, -EINVAL shall be returned
> > + * and 'msr_count' shall be set to the offending index, to aid debugging.
> > + */
> > +struct xen_domctl_vcpu_msrs {
> > + uint32_t vcpu; /* IN */
> > + uint32_t msr_count; /* IN/OUT */
> > + GUEST_HANDLE(xen_domctl_vcpu_msr) msrs; /* IN/OUT */
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpu_msrs);
> > +#endif
> > +
> > +/*
> > + * Return information about the state and running time of a domain.
> > + * The "domain runstate" is based on the runstates of all the vcpus of the
> > + * domain (see below).
> > + * @extra_arg == pointer to domain_runstate_info structure.
> > + */
> > +struct xen_domctl_runstate_info {
> > + /* VCPU's current state (RUNSTATE_*). */
> > + uint32_t state;
> > + uint32_t missed_changes;
> > + /* Number of times we missed an update due to contention */
> > + /* When was current state entered (system time, ns)? */
> > + uint64_t state_entry_time;
> > + /*
> > + * Time spent in each RUNSTATE_* (ns). The sum of these times is
> > + * NOT guaranteed not to drift from system time.
> > + */
> > + uint64_t time[6];
> > +};
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_runstate_info);
> > +
> > +/* All vcpus are running */
> > +#define DOMAIN_RUNSTATE_full_run 0
> > +
> > +/* All vcpus are runnable (i.e., waiting for cpu) */
> > +#define DOMAIN_RUNSTATE_full_contention 1
> > +
> > +/* Some vcpus are running, some are runnable */
> > +#define DOMAIN_RUNSTATE_concurrency_hazard 2
> > +
> > +/* All vcpus are blocked / offline */
> > +#define DOMAIN_RUNSTATE_blocked 3
> > +
> > +/* Some vpcus are running, some are blocked */
> > +#define DOMAIN_RUNSTATE_partial_run 4
> > +
> > +/* Some vcpus are runnable, some are blocked */
> > +#define DOMAIN_RUNSTATE_partial_contention 5
> > +
> > +struct xen_domctl_corespersocket {
> > + uint32_t cores_per_socket;
> > +};
> > +
> > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_corespersocket);
> > +#endif
> > +
> > +struct xen_domctl {
> > + uint32_t cmd;
> > +#define XEN_DOMCTL_createdomain 1
> > +#define XEN_DOMCTL_destroydomain 2
> > +#define XEN_DOMCTL_pausedomain 3
> > +#define XEN_DOMCTL_unpausedomain 4
> > +#define XEN_DOMCTL_getdomaininfo 5
> > +#define XEN_DOMCTL_getmemlist 6
> > +#define XEN_DOMCTL_getpageframeinfo 7
> > +#define XEN_DOMCTL_getpageframeinfo2 8
> > +#define XEN_DOMCTL_setvcpuaffinity 9
> > +#define XEN_DOMCTL_shadow_op 10
> > +#define XEN_DOMCTL_max_mem 11
> > +#define XEN_DOMCTL_setvcpucontext 12
> > +#define XEN_DOMCTL_getvcpucontext 13
> > +#define XEN_DOMCTL_getvcpuinfo 14
> > +#define XEN_DOMCTL_max_vcpus 15
> > +#define XEN_DOMCTL_scheduler_op 16
> > +#define XEN_DOMCTL_setdomainhandle 17
> > +#define XEN_DOMCTL_setdebugging 18
> > +#define XEN_DOMCTL_irq_permission 19
> > +#define XEN_DOMCTL_iomem_permission 20
> > +#define XEN_DOMCTL_ioport_permission 21
> > +#define XEN_DOMCTL_hypercall_init 22
> > +#define XEN_DOMCTL_arch_setup 23
> > +#define XEN_DOMCTL_settimeoffset 24
> > +#define XEN_DOMCTL_getvcpuaffinity 25
> > +#define XEN_DOMCTL_real_mode_area 26
> > +#define XEN_DOMCTL_resumedomain 27
> > +#define XEN_DOMCTL_sendtrigger 28
> > +#define XEN_DOMCTL_subscribe 29
> > +#define XEN_DOMCTL_gethvmcontext 33
> > +#define XEN_DOMCTL_sethvmcontext 34
> > +#define XEN_DOMCTL_set_address_size 35
> > +#define XEN_DOMCTL_get_address_size 36
> > +#define XEN_DOMCTL_assign_device 37
> > +#define XEN_DOMCTL_bind_pt_irq 38
> > +#define XEN_DOMCTL_memory_mapping 39
> > +#define XEN_DOMCTL_ioport_mapping 40
> > +#define XEN_DOMCTL_pin_mem_cacheattr 41
> > +#define XEN_DOMCTL_set_ext_vcpucontext 42
> > +#define XEN_DOMCTL_get_ext_vcpucontext 43
> > +#define XEN_DOMCTL_set_opt_feature 44 /* Obsolete IA64 only */
> > +#define XEN_DOMCTL_test_assign_device 45
> > +#define XEN_DOMCTL_set_target 46
> > +#define XEN_DOMCTL_deassign_device 47
> > +#define XEN_DOMCTL_unbind_pt_irq 48
> > +#define XEN_DOMCTL_set_cpuid 49
> > +#define XEN_DOMCTL_get_device_group 50
> > +#define XEN_DOMCTL_set_machine_address_size 51
> > +#define XEN_DOMCTL_get_machine_address_size 52
> > +#define XEN_DOMCTL_suppress_spurious_page_faults 53
> > +#define XEN_DOMCTL_debug_op 54
> > +#define XEN_DOMCTL_gethvmcontext_partial 55
> > +#define XEN_DOMCTL_mem_event_op 56
> > +#define XEN_DOMCTL_mem_sharing_op 57
> > +#define XEN_DOMCTL_disable_migrate 58
> > +#define XEN_DOMCTL_gettscinfo 59
> > +#define XEN_DOMCTL_settscinfo 60
> > +#define XEN_DOMCTL_getpageframeinfo3 61
> > +#define XEN_DOMCTL_setvcpuextstate 62
> > +#define XEN_DOMCTL_getvcpuextstate 63
> > +#define XEN_DOMCTL_set_access_required 64
> > +#define XEN_DOMCTL_audit_p2m 65
> > +#define XEN_DOMCTL_set_virq_handler 66
> > +#define XEN_DOMCTL_set_broken_page_p2m 67
> > +#define XEN_DOMCTL_setnodeaffinity 68
> > +#define XEN_DOMCTL_getnodeaffinity 69
> > +#define XEN_DOMCTL_set_max_evtchn 70
> > +#define XEN_DOMCTL_cacheflush 71
> > +#define XEN_DOMCTL_get_vcpu_msrs 72
> > +#define XEN_DOMCTL_set_vcpu_msrs 73
> > +#define XEN_DOMCTL_get_runstate_info 98
> > +#define XEN_DOMCTL_gdbsx_guestmemio 1000
> > +#define XEN_DOMCTL_gdbsx_pausevcpu 1001
> > +#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
> > +#define XEN_DOMCTL_gdbsx_domstatus 1003
> > +#define XEN_DOMCTL_setcorespersocket 4001
> > + uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
> > + domid_t domain;
> > + union {
> > + struct xen_domctl_createdomain createdomain;
> > + struct xen_domctl_getdomaininfo getdomaininfo;
> > + struct xen_domctl_getmemlist getmemlist;
> > + struct xen_domctl_getpageframeinfo getpageframeinfo;
> > + struct xen_domctl_getpageframeinfo2 getpageframeinfo2;
> > + struct xen_domctl_getpageframeinfo3 getpageframeinfo3;
> > +#if 0
> > + struct xen_domctl_nodeaffinity nodeaffinity;
> > + struct xen_domctl_vcpuaffinity vcpuaffinity;
> > +#endif
> > + struct xen_domctl_shadow_op shadow_op;
> > + struct xen_domctl_max_mem max_mem;
> > + struct xen_domctl_vcpucontext vcpucontext;
> > + struct xen_domctl_getvcpuinfo getvcpuinfo;
> > + struct xen_domctl_max_vcpus max_vcpus;
> > + struct xen_domctl_scheduler_op scheduler_op;
> > + struct xen_domctl_setdomainhandle setdomainhandle;
> > + struct xen_domctl_setdebugging setdebugging;
> > + struct xen_domctl_irq_permission irq_permission;
> > + struct xen_domctl_iomem_permission iomem_permission;
> > + struct xen_domctl_ioport_permission ioport_permission;
> > + struct xen_domctl_hypercall_init hypercall_init;
> > + struct xen_domctl_arch_setup arch_setup;
> > + struct xen_domctl_settimeoffset settimeoffset;
> > + struct xen_domctl_disable_migrate disable_migrate;
> > + struct xen_domctl_tsc_info tsc_info;
> > + struct xen_domctl_real_mode_area real_mode_area;
> > + struct xen_domctl_hvmcontext hvmcontext;
> > + struct xen_domctl_hvmcontext_partial hvmcontext_partial;
> > + struct xen_domctl_address_size address_size;
> > + struct xen_domctl_sendtrigger sendtrigger;
> > + struct xen_domctl_get_device_group get_device_group;
> > + struct xen_domctl_assign_device assign_device;
> > + struct xen_domctl_bind_pt_irq bind_pt_irq;
> > + struct xen_domctl_memory_mapping memory_mapping;
> > + struct xen_domctl_ioport_mapping ioport_mapping;
> > + struct xen_domctl_pin_mem_cacheattr pin_mem_cacheattr;
> > +#if 0
> > + struct xen_domctl_ext_vcpucontext ext_vcpucontext;
> > +#endif
> > + struct xen_domctl_set_target set_target;
> > + struct xen_domctl_subscribe subscribe;
> > + struct xen_domctl_debug_op debug_op;
> > + struct xen_domctl_mem_event_op mem_event_op;
> > + struct xen_domctl_mem_sharing_op mem_sharing_op;
> > +#if defined(__i386__) || defined(__x86_64__)
> > + struct xen_domctl_cpuid cpuid;
> > + struct xen_domctl_vcpuextstate vcpuextstate;
> > + struct xen_domctl_vcpu_msrs vcpu_msrs;
> > +#endif
> > + struct xen_domctl_set_access_required access_required;
> > + struct xen_domctl_audit_p2m audit_p2m;
> > + struct xen_domctl_set_virq_handler set_virq_handler;
> > + struct xen_domctl_set_max_evtchn set_max_evtchn;
> > + struct xen_domctl_runstate_info domain_runstate;
> > + struct xen_domctl_corespersocket corespersocket;
> > + struct xen_domctl_gdbsx_memio gdbsx_guest_memio;
> > + struct xen_domctl_set_broken_page_p2m set_broken_page_p2m;
> > + struct xen_domctl_cacheflush cacheflush;
> > + struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
> > + struct xen_domctl_gdbsx_domstatus gdbsx_domstatus;
> > + uint8_t pad[128];
> > + } u __aligned(8);
> > +};
> > +
> > +#endif /* __XEN_PUBLIC_DOMCTL_H__ */
> > +
> > +/*
> > + * Local variables:
> > + * mode: C
> > + * c-file-style: "BSD"
> > + * c-basic-offset: 4
> > + * tab-width: 4
> > + * indent-tabs-mode: nil
> > + * End:
> > + */
> > diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h
> > index 956a046..5fb5260 100644
> > --- a/include/xen/interface/hvm/hvm_op.h
> > +++ b/include/xen/interface/hvm/hvm_op.h
> > @@ -32,6 +32,72 @@ struct xen_hvm_param {
> > };
> > DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_param);
> >
> > +#define HVMOP_set_pci_intx_level 2
> > +struct xen_hvm_set_pci_intx_level {
> > + /* Domain to be updated. */
> > + domid_t domid;
> > + /* PCI INTx identification in PCI topology (domain:bus:device:intx). */
> > + uint8_t domain, bus, device, intx;
> > + /* Assertion level (0 = unasserted, 1 = asserted). */
> > + uint8_t level;
> > +};
> > +
> > +#define HVMOP_set_isa_irq_level 3
> > +struct xen_hvm_set_isa_irq_level {
> > + /* Domain to be updated. */
> > + domid_t domid;
> > + /* ISA device identification, by ISA IRQ (0-15). */
> > + uint8_t isa_irq;
> > + /* Assertion level (0 = unasserted, 1 = asserted). */
> > + uint8_t level;
> > +};
> > +
> > +#define HVMOP_set_pci_link_route 4
> > +struct xen_hvm_set_pci_link_route {
> > + /* Domain to be updated. */
> > + domid_t domid;
> > + /* PCI link identifier (0-3). */
> > + uint8_t link;
> > + /* ISA IRQ (1-15), or 0 (disable link). */
> > + uint8_t isa_irq;
> > +};
> > +
> > +#define HVMOP_track_dirty_vram 6
> > +struct xen_hvm_track_dirty_vram {
> > + /* Domain to be tracked. */
> > + domid_t domid;
> > + /* First pfn to track. */
> > + aligned_u64 first_pfn;
> > + /* Number of pages to track. */
> > + aligned_u64 nr;
> > + /* OUT variable. */
> > + /* Dirty bitmap buffer. */
> > + aligned_u64 dirty_bitmap;
> > +};
> > +
> > +#define HVMOP_modified_memory 7
> > +struct xen_hvm_modified_memory {
> > + /* Domain to be updated. */
> > + domid_t domid;
> > + /* First pfn. */
> > + aligned_u64 first_pfn;
> > + /* Number of pages. */
> > + aligned_u64 nr;
> > +};
> > +
> > +#define HVMOP_set_mem_type 8
> > +/* Notify that a region of memory is to be treated in a specific way. */
> > +struct xen_hvm_set_mem_type {
> > + /* Domain to be updated. */
> > + domid_t domid;
> > + /* Memory type */
> > + uint16_t hvmmem_type;
> > + /* Number of pages. */
> > + uint32_t nr;
> > + /* First pfn. */
> > + aligned_u64 first_pfn;
> > +};
> > +
> > /* Hint from PV drivers for pagetable destruction. */
> > #define HVMOP_pagetable_dying 9
> > struct xen_hvm_pagetable_dying {
> > diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
> > index 2ecfe4f..a5fd2e6 100644
> > --- a/include/xen/interface/memory.h
> > +++ b/include/xen/interface/memory.h
> > @@ -248,6 +248,14 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map);
> > */
> > extern spinlock_t xen_reservation_lock;
> >
> > +#define XENMEM_set_memory_map 13
> > +struct xen_foreign_memory_map {
> > + domid_t domid;
> > + struct xen_memory_map map;
> > +};
> > +
> > +#define XENMEM_maximum_gpfn 14
> > +
> > /*
> > * Unmaps the page appearing at a particular GPFN from the specified guest's
> > * pseudophysical address space.
> > diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
> > index de08213..075cb6f 100644
> > --- a/include/xen/interface/xen.h
> > +++ b/include/xen/interface/xen.h
> > @@ -57,6 +57,7 @@
> > #define __HYPERVISOR_event_channel_op 32
> > #define __HYPERVISOR_physdev_op 33
> > #define __HYPERVISOR_hvm_op 34
> > +#define __HYPERVISOR_domctl 36
> > #define __HYPERVISOR_tmem_op 38
> >
> > /* Architecture-specific hypercall definitions. */
> > --
> > 1.9.1
> >
> >
^ permalink raw reply
* Re: [PATCH 4/7] locking/rwsem: threshold limited spinning for active readers
From: Davidlohr Bueso @ 2014-08-05 5:41 UTC (permalink / raw)
To: Waiman Long
Cc: Ingo Molnar, Peter Zijlstra, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Jason Low, Scott J Norton
In-Reply-To: <1407216632.2566.22.camel-5JQ4ckphU/8SZAcGdq5asR6epYMZPwEe5NbjCUgZEJk@public.gmane.org>
On Mon, 2014-08-04 at 22:30 -0700, Davidlohr Bueso wrote:
> On Mon, 2014-08-04 at 21:54 -0700, Davidlohr Bueso wrote:
> > > #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
> > > +/*
> > > + * The owner field is set to RWSEM_READ_OWNED if the last owner(s) are
> > > + * readers. It is not reset until a writer takes over and set it to its
> > > + * task structure pointer or NULL when it frees the lock. So a value
> > > + * of RWSEM_READ_OWNED doesn't mean it currently has active readers.
> > > + */
> > > +#define RWSEM_READ_OWNED ((struct task_struct *)-1)
> >
> > Looks rather weird...
>
> Instead of populating owner when taking the reader lock, why not just
> leave it NULL. Then, we can differentiate between the owner being NULL
> either because it is taken by reader(s) or simply because it is not
> taken. So something like this:
>
> static inline bool rwsem_owner_is_reader(struct rw_semaphore *sem)
> {
> return !sem->owner && rwsem_is_locked(sem));
> }
Although we could race between both checks, specially when going into
slowpaths, too bad. Probably a read barrier before calling is_locked
too. Anyway, you see, things start getting funky.
^ permalink raw reply
* Re: [PATCH 4/7] locking/rwsem: threshold limited spinning for active readers
From: Davidlohr Bueso @ 2014-08-05 5:30 UTC (permalink / raw)
To: Waiman Long
Cc: Ingo Molnar, Peter Zijlstra, linux-kernel, linux-api, linux-doc,
Jason Low, Scott J Norton
In-Reply-To: <1407214461.2566.14.camel@buesod1.americas.hpqcorp.net>
On Mon, 2014-08-04 at 21:54 -0700, Davidlohr Bueso wrote:
> > #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
> > +/*
> > + * The owner field is set to RWSEM_READ_OWNED if the last owner(s) are
> > + * readers. It is not reset until a writer takes over and set it to its
> > + * task structure pointer or NULL when it frees the lock. So a value
> > + * of RWSEM_READ_OWNED doesn't mean it currently has active readers.
> > + */
> > +#define RWSEM_READ_OWNED ((struct task_struct *)-1)
>
> Looks rather weird...
Instead of populating owner when taking the reader lock, why not just
leave it NULL. Then, we can differentiate between the owner being NULL
either because it is taken by reader(s) or simply because it is not
taken. So something like this:
static inline bool rwsem_owner_is_reader(struct rw_semaphore *sem)
{
return !sem->owner && rwsem_is_locked(sem));
}
^ permalink raw reply
* Re: [PATCH 4/7] locking/rwsem: threshold limited spinning for active readers
From: Davidlohr Bueso @ 2014-08-05 4:54 UTC (permalink / raw)
To: Waiman Long
Cc: Ingo Molnar, Peter Zijlstra, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Jason Low, Scott J Norton
In-Reply-To: <1407119782-41119-5-git-send-email-Waiman.Long-VXdhtT5mjnY@public.gmane.org>
On Sun, 2014-08-03 at 22:36 -0400, Waiman Long wrote:
> Even thought only the writers can perform optimistic spinning, there
> is still a chance that readers may take the lock before a spinning
> writer can get it. In that case, the owner field will be NULL and the
> spinning writer can spin indefinitely until its time quantum expires
> when some lock owning readers are not running.
Right, now I understand where you were coming from in patch 3/7 ;)
> This patch tries to handle this special case by:
> 1) setting the owner field to a special value RWSEM_READ_OWNED
> to indicate that the current or last owner is a reader.
> 2) seting a threshold on how many times (currently 100) spinning will
^^setting
> be done with active readers before giving up as there is no easy
> way to determine if all of them are currently running.
>
> By doing so, it tries to strike a balance between giving up too early
> and losing potential performance gain and wasting too many precious
> CPU cycles when some lock owning readers are not running.
That's exactly why these kind of magic things aren't a good thing, much
less in locking. And other alternatives are much more involved, creating
more overhead, which can make the whole thing pretty much useless.
Nor does the amount of times trying to spin strike me as the correct
metric to determine such things. Instead something y cycles or time
based.
[...]
> #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
> +/*
> + * The owner field is set to RWSEM_READ_OWNED if the last owner(s) are
> + * readers. It is not reset until a writer takes over and set it to its
> + * task structure pointer or NULL when it frees the lock. So a value
> + * of RWSEM_READ_OWNED doesn't mean it currently has active readers.
> + */
> +#define RWSEM_READ_OWNED ((struct task_struct *)-1)
Looks rather weird...
> #define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL
> #else
> #define __RWSEM_OPT_INIT(lockname)
> diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
> index 9f71a67..576d4cd 100644
> --- a/kernel/locking/rwsem-xadd.c
> +++ b/kernel/locking/rwsem-xadd.c
> @@ -304,6 +304,11 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem)
>
> #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
> /*
> + * Threshold for optimistic spinning on readers
> + */
> +#define RWSEM_READ_SPIN_THRESHOLD 100
I dislike this for the same reasons they weren't welcomed in spinlocks.
We don't know how it can impact workloads that have not been tested.
[...]
> static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
> {
> struct task_struct *owner;
> bool taken = false;
> + int read_spincnt = 0;
>
> preempt_disable();
>
> @@ -397,8 +409,12 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
>
> while (true) {
> owner = ACCESS_ONCE(sem->owner);
> - if (owner && !rwsem_spin_on_owner(sem, owner))
> + if (owner == RWSEM_READ_OWNED) {
> + if (++read_spincnt > RWSEM_READ_SPIN_THRESHOLD)
> + break;
This is still a pretty fast-path and is going to affect writers, so we
really want to keep it un-clobbered.
Thanks,
Davidlohr
^ permalink raw reply
* Re: [PATCH 2/5] sched: new clone flag CLONE_NEWCGROUP for cgroup namespace
From: Serge Hallyn @ 2014-08-04 23:12 UTC (permalink / raw)
To: Aditya Kali
Cc: Tejun Heo, Li Zefan, cgroups-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux API,
Ingo Molnar, Linux Containers
In-Reply-To: <CAGr1F2FAiSFR_Y3t1=eBVoAtJvh4m=cNUi+vG146nDkgtBjisQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Quoting Aditya Kali (adityakali-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org):
> On Thu, Jul 24, 2014 at 10:01 AM, Serge Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org> wrote:
> > Quoting Aditya Kali (adityakali-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org):
> >> CLONE_NEWCGROUP will be used to create new cgroup namespace.
> >>
> >
> > This is fine and I'm not looking to bikeshed, but am wondering - did
> > you consider any other ways beside unshare (i.e. a new mount option
> > to cgroupfs)? If so, do you have a list of the downsides of those?
> > (I mainly ask bc clone flags are still a scarce commodity)
> >
>
> I did consider couple of other ways:
>
> (1) having a cgroup.ns_root (or something) cgroup file. If this value
> is '1', it would mean that all processes it and its descendant cgroups
> will have their cgroup paths in /proc/self/cgroup terminated at this
> cgroup.
> For ex:
> [A] --> [B] --> C
> | --> [D] --> E
>
> [A], [B] and [D] has cgroup.ns_root = 1.
> * all processes in cgroup C & E will see their cgroup path as /C and
> /E respectively
> * all processes in cgroup B & D will see their own cgroup path as /
>
> In this model, its easy to know what to show if process is looking at
> its own cgroup paths (/proc/self/cgroup). It gets tricky when you are
> looking at other process's /proc/<pid>/cgroup. We may be able to come
> up with some hacky way read correct value, but depending on the
> cgroupfs mount, it may not make sense.
> One other major drawback of this approach is that "every" process in
> the cgroup will now get a restricted view. i.e., you cannot change
> cgroups without affecting your view. And this is undesirable for
> administrative processes.
>
> (2) Another idea that I didn't pursue further (and is a bit hacky as
> above) was having cgroup.ns_procs (like cgroup.procs, but all the pids
> in cgroup.ns_procs will have their /proc/self/cgroup restricted).
> Writing a pid to cgroup.ns_procs implies that you are writing it to
> cgroup.procs too. But, not vise-versa. So, you could move yourself in
> another cgroup by writing your pid in cgroup.procs, but not in
> cgroup.ns_procs, thus preventing from getting "rooted". I This was to
> solve administrative process issue in the above appraoch. But I think
> this is very clunky too and I find semantics for this approach to be
> non-intuitive. It almost looks like moving towards a separate "ns"
> subsystem. But as we already know, its a path to failure.
>
> I didn't think of using a mount option. I imagine the mount option
> (something like -o root=/bathjobs/container_1) could be used to
> restrict the visibility of cgroupfs inside the container's mount
> namespace. i.e., the value you read from /proc/<pid>/cgroup now
> depends on what mount namespace you are in. Its similar to cgroup
> namespace, but just that the cgroupns_root is now stored in the
> 'struct mnt_namespace' instead of a separate 'struct
> cgroup_namespace'. But, since mount namespace on creation inherits
> mounts from its parent, the first cgroupfs mount in a mount namespace
> is now treated specially. Also, its not possible to restrict cgroups
> without mount namespace now. This is interesting and may not be too
> bad. I am willing to give this a try. But I feel the cgroup namespace
> approach fits well in-line with other namespaces where it does one
> thing - virtualize the view of /proc/<pid>/cgroup file for processes
> inside the namespace. The semantics are more intuitive as they are
> similar to other namespaces.
Yeah, let's stick with what you have :)
thanks,
-serge
^ permalink raw reply
* Re: [PATCH 3/7] locking/rwsem: check for active writer/spinner before wakeup
From: Jason Low @ 2014-08-04 21:20 UTC (permalink / raw)
To: Waiman Long
Cc: Ingo Molnar, Peter Zijlstra, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Davidlohr Bueso, Scott J Norton
In-Reply-To: <1407119782-41119-4-git-send-email-Waiman.Long-VXdhtT5mjnY@public.gmane.org>
On Sun, 2014-08-03 at 22:36 -0400, Waiman Long wrote:
> On a highly contended rwsem, spinlock contention due to the slow
> rwsem_wake() call can be a significant portion of the total CPU cycles
> used. With writer lock stealing and writer optimistic spinning, there
> is also a pretty good chance that the lock may have been stolen
> before the waker wakes up the waiters. The woken tasks, if any,
> will have to go back to sleep again.
>
> This patch adds checking code at the beginning of the rwsem_wake()
> and __rwsem_do_wake() function to look for spinner and active
> writer respectively. The presence of an active writer will abort the
> wakeup operation. The presence of a spinner will still allow wakeup
> operation to proceed as long as the trylock operation succeeds. This
> strikes a good balance between excessive spinlock contention especially
> when there are a lot of active readers and a lot of failed fastpath
> operations because there are tasks waiting in the queue.
>
> Signed-off-by: Waiman Long <Waiman.Long-VXdhtT5mjnY@public.gmane.org>
> ---
> include/linux/osq_lock.h | 5 ++++
> kernel/locking/rwsem-xadd.c | 57 ++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 61 insertions(+), 1 deletions(-)
>
> diff --git a/include/linux/osq_lock.h b/include/linux/osq_lock.h
> index 90230d5..79db546 100644
> --- a/include/linux/osq_lock.h
> +++ b/include/linux/osq_lock.h
> @@ -24,4 +24,9 @@ static inline void osq_lock_init(struct optimistic_spin_queue *lock)
> atomic_set(&lock->tail, OSQ_UNLOCKED_VAL);
> }
>
> +static inline bool osq_has_spinner(struct optimistic_spin_queue *lock)
> +{
> + return atomic_read(&lock->tail) != OSQ_UNLOCKED_VAL;
> +}
Like with other locks, should we make this "osq_is_locked"? We can still
add the rwsem has_spinner() abstractions which makes use of
osq_is_locked() if we want.
^ permalink raw reply
* Re: [PATCH 1/7] locking/rwsem: don't resched at the end of optimistic spinning
From: Jason Low @ 2014-08-04 21:12 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Waiman Long, Ingo Molnar, linux-kernel, linux-api, linux-doc,
Davidlohr Bueso, Scott J Norton
In-Reply-To: <20140804204824.GT3935@laptop>
On Mon, 2014-08-04 at 22:48 +0200, Peter Zijlstra wrote:
> On Mon, Aug 04, 2014 at 02:36:35PM -0400, Waiman Long wrote:
> > On 08/04/2014 03:55 AM, Peter Zijlstra wrote:
> > >On Sun, Aug 03, 2014 at 10:36:16PM -0400, Waiman Long wrote:
> > >>For a fully preemptive kernel, a call to preempt_enable() could
> > >>potentially trigger a task rescheduling event. In the case of rwsem
> > >>optimistic spinning, the task has either gotten the lock or is going
> > >>to sleep soon. So there is no point to do rescheduling here.
> > >Uh what? Why shouldn't we preempt if we've gotten the lock? What if a
> > >FIFO task just woke up?
> >
> > I didn't mean that we shouldn't preempt if there is a higher priority task.
> > I am sure that there will be other preemption points along the way that a
> > higher priority task can take over the CPU. I just want to say that doing it
> > here may not be the best place especially if the task is going to sleep
> > soon.
> >
> > If you think this patch does not make sense, I can remove it as other
> > patches in the set has no dependency on this one.
>
> Yeah, its actively harmful, you delay preemption by an unspecified
> amount of time in case of the spin-acquire. We've had such bugs in -rt
> and they're not fun.
>
> Basically the only time you should use no_resched is if the very next
> statement is schedule().
Right, we actually added an extra resched check at essentially the same
point in the mutex spinning code :)
^ permalink raw reply
* Re: [PATCH 1/7] locking/rwsem: don't resched at the end of optimistic spinning
From: Peter Zijlstra @ 2014-08-04 20:48 UTC (permalink / raw)
To: Waiman Long
Cc: Ingo Molnar, linux-kernel, linux-api, linux-doc, Davidlohr Bueso,
Jason Low, Scott J Norton
In-Reply-To: <53DFD2B3.3090101@hp.com>
On Mon, Aug 04, 2014 at 02:36:35PM -0400, Waiman Long wrote:
> On 08/04/2014 03:55 AM, Peter Zijlstra wrote:
> >On Sun, Aug 03, 2014 at 10:36:16PM -0400, Waiman Long wrote:
> >>For a fully preemptive kernel, a call to preempt_enable() could
> >>potentially trigger a task rescheduling event. In the case of rwsem
> >>optimistic spinning, the task has either gotten the lock or is going
> >>to sleep soon. So there is no point to do rescheduling here.
> >Uh what? Why shouldn't we preempt if we've gotten the lock? What if a
> >FIFO task just woke up?
>
> I didn't mean that we shouldn't preempt if there is a higher priority task.
> I am sure that there will be other preemption points along the way that a
> higher priority task can take over the CPU. I just want to say that doing it
> here may not be the best place especially if the task is going to sleep
> soon.
>
> If you think this patch does not make sense, I can remove it as other
> patches in the set has no dependency on this one.
Yeah, its actively harmful, you delay preemption by an unspecified
amount of time in case of the spin-acquire. We've had such bugs in -rt
and they're not fun.
Basically the only time you should use no_resched is if the very next
statement is schedule().
^ permalink raw reply
* Re: [PATCH 1/2] xen: Implement ioctl to restrict privcmd to a specific domain
From: Konrad Rzeszutek Wilk @ 2014-08-04 20:26 UTC (permalink / raw)
To: Frediano Ziglio
Cc: xen-devel, Boris Ostrovsky, linux-api, David Vrabel, linux-kernel
In-Reply-To: <201407311317.s6VDHJV9013633@aserp1020.oracle.com>
On Thu, Jul 31, 2014 at 02:16:44PM +0100, Frediano Ziglio wrote:
> Add a RESTRICT ioctl to /dev/xen/privcmd, which allows privileged commands
> file descriptor to be restricted to only working with a particular domain.
I feel I am missing an justification or use case here.
>
> Signed-off-by: Frediano Ziglio <frediano.ziglio@citrix.com>
> ---
> drivers/xen/privcmd.c | 209 ++++++-
> include/uapi/xen/privcmd.h | 6 +
> include/xen/interface/domctl.h | 1090 ++++++++++++++++++++++++++++++++++++
> include/xen/interface/hvm/hvm_op.h | 66 +++
> include/xen/interface/memory.h | 8 +
> include/xen/interface/xen.h | 1 +
> 6 files changed, 1373 insertions(+), 7 deletions(-)
> create mode 100644 include/xen/interface/domctl.h
>
> diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
> index 569a13b..c177850 100644
> --- a/drivers/xen/privcmd.c
> +++ b/drivers/xen/privcmd.c
> @@ -32,6 +32,10 @@
> #include <xen/xen.h>
> #include <xen/privcmd.h>
> #include <xen/interface/xen.h>
> +#include <xen/interface/sched.h>
> +#include <xen/interface/memory.h>
> +#include <xen/interface/domctl.h>
> +#include <xen/interface/hvm/hvm_op.h>
> #include <xen/features.h>
> #include <xen/page.h>
> #include <xen/xen-ops.h>
> @@ -43,24 +47,173 @@ MODULE_LICENSE("GPL");
>
> #define PRIV_VMA_LOCKED ((void *)1)
>
> +#define UNRESTRICTED_DOMID ((domid_t)-1)
> +
> static int privcmd_vma_range_is_mapped(
> struct vm_area_struct *vma,
> unsigned long addr,
> unsigned long nr_pages);
>
> -static long privcmd_ioctl_hypercall(void __user *udata)
> +struct privcmd_check_buf {
> + unsigned copy_back;
> + void __user *copy_ptr;
> + union {
> + struct sched_remote_shutdown remote_shutdown;
> + struct xen_memory_exchange mem_exchange;
> + struct xen_domctl domctl;
> + unsigned char buf[1];
> + } u;
> +};
> +
> +static long privcmd_check_hypercall(struct privcmd_hypercall *hypercall,
> + struct privcmd_check *check,
> + domid_t restrict_domid)
> +{
> +#define DOMID_AT(type, field) do { \
> + BUILD_BUG_ON(sizeof(type) > sizeof(check->u)); \
> + BUILD_BUG_ON(sizeof(((type *) 0)->field) != sizeof(domid_t)); \
> + check->copy_back = sizeof(type); \
> + domid_offset = offsetof(type, field); \
> + } while (0)
> +
> +/* we copy from userspace and replace arguments to avoid unsafe data */
> +#define FETCH_ARG(dest, arg_num, size) do { \
> + check->copy_ptr = (void *) (long) hypercall->arg[arg_num]; \
> + if (copy_from_user(dest, check->copy_ptr, size)) \
> + return -EFAULT; \
> + hypercall->arg[arg_num] = (long) dest; \
> + } while (0)
> +
> + unsigned domid_offset;
> +
> + /* default to invalid so on cases not handled we fail */
> + domid_t domid = UNRESTRICTED_DOMID;
> +
> + switch (hypercall->op) {
> + case __HYPERVISOR_sched_op:
> + if (hypercall->arg[0] == SCHEDOP_remote_shutdown) {
> + FETCH_ARG(&check->u.remote_shutdown, 1,
> + sizeof(check->u.remote_shutdown));
> + domid = check->u.remote_shutdown.domain_id;
> + }
> + break;
> +
> + case __HYPERVISOR_domctl:
> + FETCH_ARG(&check->u.domctl, 0, sizeof(check->u.domctl));
> + check->copy_back = sizeof(check->u.domctl);
> + /* avoid to create a domain */
> + if (check->u.domctl.cmd == XEN_DOMCTL_createdomain)
> + return -EACCES;
> + /* limit versions to avoid possible future bigger buffer */
> + if (check->u.domctl.interface_version > XEN_DOMCTL_INTERFACE_VERSION)
> + return -EACCES;
> + domid = check->u.domctl.domain;
> + break;
> +
> + case __HYPERVISOR_memory_op:
> + switch (hypercall->arg[0]) {
> + case XENMEM_increase_reservation:
> + case XENMEM_decrease_reservation:
> + case XENMEM_populate_physmap:
> + DOMID_AT(struct xen_memory_reservation, domid);
> + break;
> + case XENMEM_exchange:
> + DOMID_AT(struct xen_memory_exchange, in.domid);
> + break;
> + case XENMEM_current_reservation:
> + case XENMEM_maximum_reservation:
> + case XENMEM_maximum_gpfn:
> + check->copy_back = sizeof(domid);
> + domid_offset = 0;
> + break;
> + case XENMEM_add_to_physmap:
> + DOMID_AT(struct xen_add_to_physmap, domid);
> + break;
> + case XENMEM_set_memory_map:
> + DOMID_AT(struct xen_foreign_memory_map, domid);
> + break;
> + default:
> + return -EACCES;
> + }
> + FETCH_ARG(&check->u, 1, check->copy_back);
> + domid = *((domid_t *) &check->u.buf[domid_offset]);
> +
> + /* extra check for XENMEM_exchange, exchange in the same
> + * domain */
> + if (hypercall->arg[0] == XENMEM_exchange &&
> + check->u.mem_exchange.in.domid != check->u.mem_exchange.out.domid)
> + return -EACCES;
> + break;
> +
> + case __HYPERVISOR_hvm_op:
> + switch (hypercall->arg[0]) {
> + case HVMOP_set_param:
> + case HVMOP_get_param:
> + DOMID_AT(struct xen_hvm_param, domid);
> + break;
> + case HVMOP_set_pci_intx_level:
> + DOMID_AT(struct xen_hvm_set_pci_intx_level, domid);
> + break;
> + case HVMOP_set_isa_irq_level:
> + DOMID_AT(struct xen_hvm_set_isa_irq_level, domid);
> + break;
> + case HVMOP_set_pci_link_route:
> + DOMID_AT(struct xen_hvm_set_pci_link_route, domid);
> + break;
> + case HVMOP_modified_memory:
> + DOMID_AT(struct xen_hvm_modified_memory, domid);
> + break;
> + case HVMOP_set_mem_type:
> + DOMID_AT(struct xen_hvm_set_mem_type, domid);
> + break;
> + case HVMOP_track_dirty_vram:
> + DOMID_AT(struct xen_hvm_track_dirty_vram, domid);
> + break;
> + default:
> + return -EACCES;
> + }
> + FETCH_ARG(&check->u, 1, check->copy_back);
> + domid = *((domid_t *) &check->u.buf[domid_offset]);
> + break;
> + }
> +
> + if (domid != restrict_domid)
> + return -EACCES;
> +
> + return 0;
> +}
> +
> +static long privcmd_ioctl_hypercall(void __user *udata,
> + domid_t restrict_domid)
> {
> struct privcmd_hypercall hypercall;
> + struct privcmd_check_buf check_buf;
> long ret;
>
> + check_buf.copy_back = 0;
> + check_buf.copy_ptr = NULL;
> +
> if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
> return -EFAULT;
>
> + /* we must check domain we are using */
> + if (restrict_domid != UNRESTRICTED_DOMID) {
> + ret = privcmd_check_hypercall(&hypercall, &check_buf,
> + restrict_domid);
> + if (ret)
> + return ret;
> + }
> +
> ret = privcmd_call(hypercall.op,
> hypercall.arg[0], hypercall.arg[1],
> hypercall.arg[2], hypercall.arg[3],
> hypercall.arg[4]);
>
> + if (check_buf.copy_back && check_buf.copy_ptr && ret >= 0)
> + if (copy_to_user(check_buf.copy_ptr, &check_buf.u,
> + check_buf.copy_back))
> + ret = -EFAULT;
> +
> return ret;
> }
>
> @@ -193,7 +346,7 @@ static int mmap_mfn_range(void *data, void *state)
> return 0;
> }
>
> -static long privcmd_ioctl_mmap(void __user *udata)
> +static long privcmd_ioctl_mmap(void __user *udata, domid_t restrict_domid)
> {
> struct privcmd_mmap mmapcmd;
> struct mm_struct *mm = current->mm;
> @@ -209,6 +362,10 @@ static long privcmd_ioctl_mmap(void __user *udata)
> if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
> return -EFAULT;
>
> + if (restrict_domid != UNRESTRICTED_DOMID &&
> + restrict_domid != mmapcmd.dom)
> + return -EACCES;
> +
> rc = gather_array(&pagelist,
> mmapcmd.num, sizeof(struct privcmd_mmap_entry),
> mmapcmd.entry);
> @@ -367,7 +524,8 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
>
> static struct vm_operations_struct privcmd_vm_ops;
>
> -static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
> +static long privcmd_ioctl_mmap_batch(void __user *udata, int version,
> + domid_t restrict_domid)
> {
> int ret;
> struct privcmd_mmapbatch_v2 m;
> @@ -397,6 +555,10 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
> return -EINVAL;
> }
>
> + if (restrict_domid != UNRESTRICTED_DOMID &&
> + restrict_domid != m.dom)
> + return -EACCES;
> +
> nr_pages = m.num;
> if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
> return -EINVAL;
> @@ -498,27 +660,53 @@ out_unlock:
> goto out;
> }
>
> +static inline domid_t privcmd_get_restrict_domid(const struct file *file)
> +{
> + return (domid_t) (long) file->private_data;
> +}
> +
> +static inline void privcmd_set_restrict_domid(struct file *file,
> + domid_t domid)
> +{
> + file->private_data = (void *) (long) domid;
> +}
> +
> static long privcmd_ioctl(struct file *file,
> unsigned int cmd, unsigned long data)
> {
> int ret = -ENOSYS;
> void __user *udata = (void __user *) data;
> + domid_t restrict_domid = privcmd_get_restrict_domid(file);
>
> switch (cmd) {
> case IOCTL_PRIVCMD_HYPERCALL:
> - ret = privcmd_ioctl_hypercall(udata);
> + ret = privcmd_ioctl_hypercall(udata, restrict_domid);
> break;
>
> case IOCTL_PRIVCMD_MMAP:
> - ret = privcmd_ioctl_mmap(udata);
> + ret = privcmd_ioctl_mmap(udata, restrict_domid);
> break;
>
> case IOCTL_PRIVCMD_MMAPBATCH:
> - ret = privcmd_ioctl_mmap_batch(udata, 1);
> + ret = privcmd_ioctl_mmap_batch(udata, 1, restrict_domid);
> break;
>
> case IOCTL_PRIVCMD_MMAPBATCH_V2:
> - ret = privcmd_ioctl_mmap_batch(udata, 2);
> + ret = privcmd_ioctl_mmap_batch(udata, 2, restrict_domid);
> + break;
> +
> + case IOCTL_PRIVCMD_RESTRICT_DOMID: {
> + struct privcmd_restrict_domid prd;
> +
> + if (restrict_domid != UNRESTRICTED_DOMID)
> + return -EACCES;
> + if (copy_from_user(&prd, udata, sizeof(prd)))
> + return -EFAULT;
> + if (prd.domid >= DOMID_FIRST_RESERVED)
> + return -EINVAL;
> + privcmd_set_restrict_domid(file, prd.domid);
> + ret = 0;
> + }
> break;
>
> default:
> @@ -593,10 +781,17 @@ static int privcmd_vma_range_is_mapped(
> is_mapped_fn, NULL) != 0;
> }
>
> +static int privcmd_open(struct inode *ino, struct file *filp)
> +{
> + privcmd_set_restrict_domid(filp, UNRESTRICTED_DOMID);
> + return 0;
> +}
> +
> const struct file_operations xen_privcmd_fops = {
> .owner = THIS_MODULE,
> .unlocked_ioctl = privcmd_ioctl,
> .mmap = privcmd_mmap,
> + .open = privcmd_open,
> };
> EXPORT_SYMBOL_GPL(xen_privcmd_fops);
>
> diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h
> index a853168..461a999 100644
> --- a/include/uapi/xen/privcmd.h
> +++ b/include/uapi/xen/privcmd.h
> @@ -73,6 +73,10 @@ struct privcmd_mmapbatch_v2 {
> int __user *err; /* array of error codes */
> };
>
> +struct privcmd_restrict_domid {
> + domid_t domid;
> +};
> +
> /*
> * @cmd: IOCTL_PRIVCMD_HYPERCALL
> * @arg: &privcmd_hypercall_t
> @@ -94,5 +98,7 @@ struct privcmd_mmapbatch_v2 {
> _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
> #define IOCTL_PRIVCMD_MMAPBATCH_V2 \
> _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
> +#define IOCTL_PRIVCMD_RESTRICT_DOMID \
> + _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_restrict_domid))
>
> #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
> diff --git a/include/xen/interface/domctl.h b/include/xen/interface/domctl.h
> new file mode 100644
> index 0000000..0668fed
> --- /dev/null
> +++ b/include/xen/interface/domctl.h
> @@ -0,0 +1,1090 @@
> +/******************************************************************************
> + * domctl.h
> + *
> + * Domain management operations. For use by node control stack.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to
> + * deal in the Software without restriction, including without limitation the
> + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + * Copyright (c) 2002-2003, B Dragovic
> + * Copyright (c) 2002-2006, K Fraser
> + */
> +
> +#ifndef __XEN_PUBLIC_DOMCTL_H__
> +#define __XEN_PUBLIC_DOMCTL_H__
> +
> +#include "xen.h"
> +#include "grant_table.h"
> +
> +#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000a
> +
> +#if 1
> +/*
> + * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
> + * If it is specified as zero, an id is auto-allocated and returned.
> + */
> +/* XEN_DOMCTL_createdomain */
> +struct xen_domctl_createdomain {
> + /* IN parameters */
> + uint32_t ssidref;
> + xen_domain_handle_t handle;
> + /* Is this an HVM guest (as opposed to a PVH or PV guest)? */
> +#define _XEN_DOMCTL_CDF_hvm_guest 0
> +#define XEN_DOMCTL_CDF_hvm_guest (1U<<_XEN_DOMCTL_CDF_hvm_guest)
> + /* Use hardware-assisted paging if available? */
> +#define _XEN_DOMCTL_CDF_hap 1
> +#define XEN_DOMCTL_CDF_hap (1U<<_XEN_DOMCTL_CDF_hap)
> + /* Should domain memory integrity be verifed by tboot during Sx? */
> +#define _XEN_DOMCTL_CDF_s3_integrity 2
> +#define XEN_DOMCTL_CDF_s3_integrity (1U<<_XEN_DOMCTL_CDF_s3_integrity)
> + /* Disable out-of-sync shadow page tables? */
> +#define _XEN_DOMCTL_CDF_oos_off 3
> +#define XEN_DOMCTL_CDF_oos_off (1U<<_XEN_DOMCTL_CDF_oos_off)
> + /* Is this a PVH guest (as opposed to an HVM or PV guest)? */
> +#define _XEN_DOMCTL_CDF_pvh_guest 4
> +#define XEN_DOMCTL_CDF_pvh_guest (1U<<_XEN_DOMCTL_CDF_pvh_guest)
> + uint32_t flags;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_createdomain);
> +
> +/* XEN_DOMCTL_getdomaininfo */
> +struct xen_domctl_getdomaininfo {
> + /* OUT variables. */
> + domid_t domain; /* Also echoed in domctl.domain */
> + /* Domain is scheduled to die. */
> +#define _XEN_DOMINF_dying 0
> +#define XEN_DOMINF_dying (1U<<_XEN_DOMINF_dying)
> + /* Domain is an HVM guest (as opposed to a PV guest). */
> +#define _XEN_DOMINF_hvm_guest 1
> +#define XEN_DOMINF_hvm_guest (1U<<_XEN_DOMINF_hvm_guest)
> + /* The guest OS has shut down. */
> +#define _XEN_DOMINF_shutdown 2
> +#define XEN_DOMINF_shutdown (1U<<_XEN_DOMINF_shutdown)
> + /* Currently paused by control software. */
> +#define _XEN_DOMINF_paused 3
> +#define XEN_DOMINF_paused (1U<<_XEN_DOMINF_paused)
> + /* Currently blocked pending an event. */
> +#define _XEN_DOMINF_blocked 4
> +#define XEN_DOMINF_blocked (1U<<_XEN_DOMINF_blocked)
> + /* Domain is currently running. */
> +#define _XEN_DOMINF_running 5
> +#define XEN_DOMINF_running (1U<<_XEN_DOMINF_running)
> + /* Being debugged. */
> +#define _XEN_DOMINF_debugged 6
> +#define XEN_DOMINF_debugged (1U<<_XEN_DOMINF_debugged)
> +/* domain is PVH */
> +#define _XEN_DOMINF_pvh_guest 7
> +#define XEN_DOMINF_pvh_guest (1U<<_XEN_DOMINF_pvh_guest)
> + /* XEN_DOMINF_shutdown guest-supplied code. */
> +#define XEN_DOMINF_shutdownmask 255
> +#define XEN_DOMINF_shutdownshift 16
> + uint32_t flags; /* XEN_DOMINF_* */
> + aligned_u64 tot_pages;
> + aligned_u64 max_pages;
> + aligned_u64 outstanding_pages;
> + aligned_u64 shr_pages;
> + aligned_u64 paged_pages;
> + aligned_u64 shared_info_frame; /* GMFN of shared_info struct */
> + aligned_u64 cpu_time;
> + uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
> + uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
> + uint32_t ssidref;
> + xen_domain_handle_t handle;
> + uint32_t cpupool;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getdomaininfo);
> +
> +
> +/* XEN_DOMCTL_getmemlist */
> +struct xen_domctl_getmemlist {
> + /* IN variables. */
> + /* Max entries to write to output buffer. */
> + aligned_u64 max_pfns;
> + /* Start index in guest's page list. */
> + aligned_u64 start_pfn;
> + GUEST_HANDLE(uint64_t) buffer;
> + /* OUT variables. */
> + aligned_u64 num_pfns;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getmemlist);
> +
> +
> +/* XEN_DOMCTL_getpageframeinfo */
> +
> +#define XEN_DOMCTL_PFINFO_LTAB_SHIFT 28
> +#define XEN_DOMCTL_PFINFO_NOTAB (0x0U<<28)
> +#define XEN_DOMCTL_PFINFO_L1TAB (0x1U<<28)
> +#define XEN_DOMCTL_PFINFO_L2TAB (0x2U<<28)
> +#define XEN_DOMCTL_PFINFO_L3TAB (0x3U<<28)
> +#define XEN_DOMCTL_PFINFO_L4TAB (0x4U<<28)
> +#define XEN_DOMCTL_PFINFO_LTABTYPE_MASK (0x7U<<28)
> +#define XEN_DOMCTL_PFINFO_LPINTAB (0x1U<<31)
> +#define XEN_DOMCTL_PFINFO_XTAB (0xfU<<28) /* invalid page */
> +#define XEN_DOMCTL_PFINFO_XALLOC (0xeU<<28) /* allocate-only page */
> +#define XEN_DOMCTL_PFINFO_BROKEN (0xdU<<28) /* broken page */
> +#define XEN_DOMCTL_PFINFO_LTAB_MASK (0xfU<<28)
> +
> +struct xen_domctl_getpageframeinfo {
> + /* IN variables. */
> + aligned_u64 gmfn; /* GMFN to query */
> + /* OUT variables. */
> + /* Is the page PINNED to a type? */
> + uint32_t type; /* see above type defs */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getpageframeinfo);
> +
> +
> +/* XEN_DOMCTL_getpageframeinfo2 */
> +struct xen_domctl_getpageframeinfo2 {
> + /* IN variables. */
> + aligned_u64 num;
> + /* IN/OUT variables. */
> + GUEST_HANDLE(uint32_t) array;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getpageframeinfo2);
> +
> +/* XEN_DOMCTL_getpageframeinfo3 */
> +struct xen_domctl_getpageframeinfo3 {
> + /* IN variables. */
> + aligned_u64 num;
> + /* IN/OUT variables. */
> + GUEST_HANDLE(xen_pfn_t) array;
> +};
> +
> +
> +/*
> + * Control shadow pagetables operation
> + */
> +/* XEN_DOMCTL_shadow_op */
> +
> +/* Disable shadow mode. */
> +#define XEN_DOMCTL_SHADOW_OP_OFF 0
> +
> +/* Enable shadow mode (mode contains ORed XEN_DOMCTL_SHADOW_ENABLE_* flags). */
> +#define XEN_DOMCTL_SHADOW_OP_ENABLE 32
> +
> +/* Log-dirty bitmap operations. */
> + /* Return the bitmap and clean internal copy for next round. */
> +#define XEN_DOMCTL_SHADOW_OP_CLEAN 11
> + /* Return the bitmap but do not modify internal copy. */
> +#define XEN_DOMCTL_SHADOW_OP_PEEK 12
> +
> +/* Memory allocation accessors. */
> +#define XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION 30
> +#define XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION 31
> +
> +/* Legacy enable operations. */
> + /* Equiv. to ENABLE with no mode flags. */
> +#define XEN_DOMCTL_SHADOW_OP_ENABLE_TEST 1
> + /* Equiv. to ENABLE with mode flag ENABLE_LOG_DIRTY. */
> +#define XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY 2
> + /* Equiv. to ENABLE with mode flags ENABLE_REFCOUNT and ENABLE_TRANSLATE. */
> +#define XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE 3
> +
> +/* Mode flags for XEN_DOMCTL_SHADOW_OP_ENABLE. */
> + /*
> + * Shadow pagetables are refcounted: guest does not use explicit mmu
> + * operations nor write-protect its pagetables.
> + */
> +#define XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT (1 << 1)
> + /*
> + * Log pages in a bitmap as they are dirtied.
> + * Used for live relocation to determine which pages must be re-sent.
> + */
> +#define XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY (1 << 2)
> + /*
> + * Automatically translate GPFNs into MFNs.
> + */
> +#define XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE (1 << 3)
> + /*
> + * Xen does not steal virtual address space from the guest.
> + * Requires HVM support.
> + */
> +#define XEN_DOMCTL_SHADOW_ENABLE_EXTERNAL (1 << 4)
> +
> +struct xen_domctl_shadow_op_stats {
> + uint32_t fault_count;
> + uint32_t dirty_count;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_shadow_op_stats);
> +
> +struct xen_domctl_shadow_op {
> + /* IN variables. */
> + uint32_t op; /* XEN_DOMCTL_SHADOW_OP_* */
> +
> + /* OP_ENABLE */
> + uint32_t mode; /* XEN_DOMCTL_SHADOW_ENABLE_* */
> +
> + /* OP_GET_ALLOCATION / OP_SET_ALLOCATION */
> + uint32_t mb; /* Shadow memory allocation in MB */
> +
> + /* OP_PEEK / OP_CLEAN */
> + GUEST_HANDLE(uchar) dirty_bitmap;
> + aligned_u64 pages; /* Size of buffer. Updated with actual size. */
> + struct xen_domctl_shadow_op_stats stats;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_shadow_op);
> +
> +
> +/* XEN_DOMCTL_max_mem */
> +struct xen_domctl_max_mem {
> + /* IN variables. */
> + aligned_u64 max_memkb;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_max_mem);
> +
> +
> +/* XEN_DOMCTL_setvcpucontext */
> +/* XEN_DOMCTL_getvcpucontext */
> +struct xen_domctl_vcpucontext {
> + uint32_t vcpu; /* IN */
> + GUEST_HANDLE(vcpu_guest_context) ctxt; /* IN/OUT */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpucontext);
> +
> +
> +/* XEN_DOMCTL_getvcpuinfo */
> +struct xen_domctl_getvcpuinfo {
> + /* IN variables. */
> + uint32_t vcpu;
> + /* OUT variables. */
> + uint8_t online; /* currently online (not hotplugged)? */
> + uint8_t blocked; /* blocked waiting for an event? */
> + uint8_t running; /* currently scheduled on its CPU? */
> + aligned_u64 cpu_time; /* total cpu time consumed (ns) */
> + uint32_t cpu; /* current mapping */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getvcpuinfo);
> +
> +#if 0
> +/* Get/set the NUMA node(s) with which the guest has affinity with. */
> +/* XEN_DOMCTL_setnodeaffinity */
> +/* XEN_DOMCTL_getnodeaffinity */
> +struct xen_domctl_nodeaffinity {
> + struct xenctl_bitmap nodemap;/* IN */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_nodeaffinity);
> +
> +
> +/* Get/set which physical cpus a vcpu can execute on. */
> +/* XEN_DOMCTL_setvcpuaffinity */
> +/* XEN_DOMCTL_getvcpuaffinity */
> +struct xen_domctl_vcpuaffinity {
> + uint32_t vcpu; /* IN */
> + struct xenctl_bitmap cpumap; /* IN/OUT */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpuaffinity);
> +#endif
> +
> +
> +/* XEN_DOMCTL_max_vcpus */
> +struct xen_domctl_max_vcpus {
> + uint32_t max; /* maximum number of vcpus */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_max_vcpus);
> +
> +
> +/* XEN_DOMCTL_scheduler_op */
> +/* Scheduler types. */
> +#define XEN_SCHEDULER_SEDF 4
> +#define XEN_SCHEDULER_CREDIT 5
> +#define XEN_SCHEDULER_CREDIT2 6
> +#define XEN_SCHEDULER_ARINC653 7
> +/* Set or get info? */
> +#define XEN_DOMCTL_SCHEDOP_putinfo 0
> +#define XEN_DOMCTL_SCHEDOP_getinfo 1
> +struct xen_domctl_scheduler_op {
> + uint32_t sched_id; /* XEN_SCHEDULER_* */
> + uint32_t cmd; /* XEN_DOMCTL_SCHEDOP_* */
> + union {
> + struct xen_domctl_sched_sedf {
> + aligned_u64 period;
> + aligned_u64 slice;
> + aligned_u64 latency;
> + uint32_t extratime;
> + uint32_t weight;
> + } sedf;
> + struct xen_domctl_sched_credit {
> + uint16_t weight;
> + uint16_t cap;
> + } credit;
> + struct xen_domctl_sched_credit2 {
> + uint16_t weight;
> + } credit2;
> + } u;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_scheduler_op);
> +
> +
> +/* XEN_DOMCTL_setdomainhandle */
> +struct xen_domctl_setdomainhandle {
> + xen_domain_handle_t handle;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_setdomainhandle);
> +
> +
> +/* XEN_DOMCTL_setdebugging */
> +struct xen_domctl_setdebugging {
> + uint8_t enable;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_setdebugging);
> +
> +
> +/* XEN_DOMCTL_irq_permission */
> +struct xen_domctl_irq_permission {
> + uint8_t pirq;
> + uint8_t allow_access; /* flag to specify enable/disable of IRQ access */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_irq_permission);
> +
> +
> +/* XEN_DOMCTL_iomem_permission */
> +struct xen_domctl_iomem_permission {
> + aligned_u64 first_mfn;/* first page (physical page number) in range */
> + aligned_u64 nr_mfns; /* number of pages in range (>0) */
> + uint8_t allow_access; /* allow (!0) or deny (0) access to range? */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_iomem_permission);
> +
> +
> +/* XEN_DOMCTL_ioport_permission */
> +struct xen_domctl_ioport_permission {
> + uint32_t first_port; /* first port int range */
> + uint32_t nr_ports; /* size of port range */
> + uint8_t allow_access; /* allow or deny access to range? */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ioport_permission);
> +
> +
> +/* XEN_DOMCTL_hypercall_init */
> +struct xen_domctl_hypercall_init {
> + aligned_u64 gmfn; /* GMFN to be initialised */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hypercall_init);
> +
> +
> +/* XEN_DOMCTL_arch_setup */
> +#define _XEN_DOMAINSETUP_hvm_guest 0
> +#define XEN_DOMAINSETUP_hvm_guest (1UL<<_XEN_DOMAINSETUP_hvm_guest)
> +#define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save) */
> +#define XEN_DOMAINSETUP_query (1UL<<_XEN_DOMAINSETUP_query)
> +#define _XEN_DOMAINSETUP_sioemu_guest 2
> +#define XEN_DOMAINSETUP_sioemu_guest (1UL<<_XEN_DOMAINSETUP_sioemu_guest)
> +struct xen_domctl_arch_setup {
> + aligned_u64 flags; /* XEN_DOMAINSETUP_* */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_arch_setup);
> +
> +
> +/* XEN_DOMCTL_settimeoffset */
> +struct xen_domctl_settimeoffset {
> + int32_t time_offset_seconds; /* applied to domain wallclock time */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_settimeoffset);
> +
> +/* XEN_DOMCTL_gethvmcontext */
> +/* XEN_DOMCTL_sethvmcontext */
> +struct xen_domctl_hvmcontext {
> + uint32_t size; /* IN/OUT: size of buffer / bytes filled */
> + GUEST_HANDLE(uchar) buffer; /* IN/OUT: data, or call
> + * gethvmcontext with NULL
> + * buffer to get size req'd */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hvmcontext);
> +
> +
> +/* XEN_DOMCTL_set_address_size */
> +/* XEN_DOMCTL_get_address_size */
> +struct xen_domctl_address_size {
> + uint32_t size;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_address_size);
> +
> +
> +/* XEN_DOMCTL_real_mode_area */
> +struct xen_domctl_real_mode_area {
> + uint32_t log; /* log2 of Real Mode Area size */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_real_mode_area);
> +
> +
> +/* XEN_DOMCTL_sendtrigger */
> +#define XEN_DOMCTL_SENDTRIGGER_NMI 0
> +#define XEN_DOMCTL_SENDTRIGGER_RESET 1
> +#define XEN_DOMCTL_SENDTRIGGER_INIT 2
> +#define XEN_DOMCTL_SENDTRIGGER_POWER 3
> +#define XEN_DOMCTL_SENDTRIGGER_SLEEP 4
> +struct xen_domctl_sendtrigger {
> + uint32_t trigger; /* IN */
> + uint32_t vcpu; /* IN */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_sendtrigger);
> +
> +
> +/* Assign PCI device to HVM guest. Sets up IOMMU structures. */
> +/* XEN_DOMCTL_assign_device */
> +/* XEN_DOMCTL_test_assign_device */
> +/* XEN_DOMCTL_deassign_device */
> +struct xen_domctl_assign_device {
> + uint32_t machine_sbdf; /* machine PCI ID of assigned device */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_assign_device);
> +
> +/* Retrieve sibling devices infomation of machine_sbdf */
> +/* XEN_DOMCTL_get_device_group */
> +struct xen_domctl_get_device_group {
> + uint32_t machine_sbdf; /* IN */
> + uint32_t max_sdevs; /* IN */
> + uint32_t num_sdevs; /* OUT */
> + GUEST_HANDLE(uint32_t) sdev_array; /* OUT */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_get_device_group);
> +
> +/* Pass-through interrupts: bind real irq -> hvm devfn. */
> +/* XEN_DOMCTL_bind_pt_irq */
> +/* XEN_DOMCTL_unbind_pt_irq */
> +enum pt_irq_type_e {
> + PT_IRQ_TYPE_PCI,
> + PT_IRQ_TYPE_ISA,
> + PT_IRQ_TYPE_MSI,
> + PT_IRQ_TYPE_MSI_TRANSLATE,
> +};
> +struct xen_domctl_bind_pt_irq {
> + uint32_t machine_irq;
> + enum pt_irq_type_e irq_type;
> + uint32_t hvm_domid;
> +
> + union {
> + struct {
> + uint8_t isa_irq;
> + } isa;
> + struct {
> + uint8_t bus;
> + uint8_t device;
> + uint8_t intx;
> + } pci;
> + struct {
> + uint8_t gvec;
> + uint32_t gflags;
> + aligned_u64 gtable;
> + } msi;
> + } u;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_bind_pt_irq);
> +
> +
> +/* Bind machine I/O address range -> HVM address range. */
> +/* XEN_DOMCTL_memory_mapping */
> +#define DPCI_ADD_MAPPING 1
> +#define DPCI_REMOVE_MAPPING 0
> +struct xen_domctl_memory_mapping {
> + aligned_u64 first_gfn; /* first page (hvm guest phys page) in range */
> + aligned_u64 first_mfn; /* first page (machine page) in range */
> + aligned_u64 nr_mfns; /* number of pages in range (>0) */
> + uint32_t add_mapping; /* add or remove mapping */
> + uint32_t padding; /* padding for 64-bit aligned structure */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_memory_mapping);
> +
> +
> +/* Bind machine I/O port range -> HVM I/O port range. */
> +/* XEN_DOMCTL_ioport_mapping */
> +struct xen_domctl_ioport_mapping {
> + uint32_t first_gport; /* first guest IO port*/
> + uint32_t first_mport; /* first machine IO port */
> + uint32_t nr_ports; /* size of port range */
> + uint32_t add_mapping; /* add or remove mapping */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ioport_mapping);
> +
> +
> +/*
> + * Pin caching type of RAM space for x86 HVM domU.
> + */
> +/* XEN_DOMCTL_pin_mem_cacheattr */
> +/* Caching types: these happen to be the same as x86 MTRR/PAT type codes. */
> +#define XEN_DOMCTL_MEM_CACHEATTR_UC 0
> +#define XEN_DOMCTL_MEM_CACHEATTR_WC 1
> +#define XEN_DOMCTL_MEM_CACHEATTR_WT 4
> +#define XEN_DOMCTL_MEM_CACHEATTR_WP 5
> +#define XEN_DOMCTL_MEM_CACHEATTR_WB 6
> +#define XEN_DOMCTL_MEM_CACHEATTR_UCM 7
> +struct xen_domctl_pin_mem_cacheattr {
> + aligned_u64 start, end;
> + uint32_t type; /* XEN_DOMCTL_MEM_CACHEATTR_* */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_pin_mem_cacheattr);
> +
> +
> +#if 0
> +/* XEN_DOMCTL_set_ext_vcpucontext */
> +/* XEN_DOMCTL_get_ext_vcpucontext */
> +struct xen_domctl_ext_vcpucontext {
> + /* IN: VCPU that this call applies to. */
> + uint32_t vcpu;
> + /*
> + * SET: Size of struct (IN)
> + * GET: Size of struct (OUT, up to 128 bytes)
> + */
> + uint32_t size;
> +#if defined(__i386__) || defined(__x86_64__)
> + /* SYSCALL from 32-bit mode and SYSENTER callback information. */
> + /* NB. SYSCALL from 64-bit mode is contained in vcpu_guest_context_t */
> + aligned_u64 syscall32_callback_eip;
> + aligned_u64 sysenter_callback_eip;
> + uint16_t syscall32_callback_cs;
> + uint16_t sysenter_callback_cs;
> + uint8_t syscall32_disables_events;
> + uint8_t sysenter_disables_events;
> +#if defined(__GNUC__)
> + union {
> + aligned_u64 mcg_cap;
> + struct hvm_vmce_vcpu vmce;
> + };
> +#else
> + struct hvm_vmce_vcpu vmce;
> +#endif
> +#endif
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ext_vcpucontext);
> +#endif
> +
> +/*
> + * Set the target domain for a domain
> + */
> +/* XEN_DOMCTL_set_target */
> +struct xen_domctl_set_target {
> + domid_t target;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_target);
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +# define XEN_CPUID_INPUT_UNUSED 0xFFFFFFFF
> +/* XEN_DOMCTL_set_cpuid */
> +struct xen_domctl_cpuid {
> + uint32_t input[2];
> + uint32_t eax;
> + uint32_t ebx;
> + uint32_t ecx;
> + uint32_t edx;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_cpuid);
> +#endif
> +
> +/*
> + * Arranges that if the domain suspends (specifically, if it shuts
> + * down with code SHUTDOWN_suspend), this event channel will be
> + * notified.
> + *
> + * This is _instead of_ the usual notification to the global
> + * VIRQ_DOM_EXC. (In most systems that pirq is owned by xenstored.)
> + *
> + * Only one subscription per domain is possible. Last subscriber
> + * wins; others are silently displaced.
> + *
> + * NB that contrary to the rather general name, it only applies to
> + * domain shutdown with code suspend. Shutdown for other reasons
> + * (including crash), and domain death, are notified to VIRQ_DOM_EXC
> + * regardless.
> + */
> +/* XEN_DOMCTL_subscribe */
> +struct xen_domctl_subscribe {
> + uint32_t port; /* IN */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_subscribe);
> +
> +/*
> + * Define the maximum machine address size which should be allocated
> + * to a guest.
> + */
> +/* XEN_DOMCTL_set_machine_address_size */
> +/* XEN_DOMCTL_get_machine_address_size */
> +
> +/*
> + * Do not inject spurious page faults into this domain.
> + */
> +/* XEN_DOMCTL_suppress_spurious_page_faults */
> +
> +/* XEN_DOMCTL_debug_op */
> +#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF 0
> +#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON 1
> +struct xen_domctl_debug_op {
> + uint32_t op; /* IN */
> + uint32_t vcpu; /* IN */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_debug_op);
> +
> +/*
> + * Request a particular record from the HVM context
> + */
> +/* XEN_DOMCTL_gethvmcontext_partial */
> +struct xen_domctl_hvmcontext_partial {
> + uint32_t type; /* IN: Type of record required */
> + uint32_t instance; /* IN: Instance of that type */
> + GUEST_HANDLE(uchar) buffer; /* OUT: buffer to write record into */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hvmcontext_partial);
> +
> +/* XEN_DOMCTL_disable_migrate */
> +struct xen_domctl_disable_migrate {
> + uint32_t disable; /* IN: 1: disable migration and restore */
> +};
> +
> +
> +/* XEN_DOMCTL_gettscinfo */
> +/* XEN_DOMCTL_settscinfo */
> +struct xen_guest_tsc_info {
> + uint32_t tsc_mode;
> + uint32_t gtsc_khz;
> + uint32_t incarnation;
> + uint32_t pad;
> + aligned_u64 elapsed_nsec;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_guest_tsc_info);
> +
> +struct xen_domctl_tsc_info {
> + GUEST_HANDLE(xen_guest_tsc_info) out_info; /* OUT */
> + struct xen_guest_tsc_info info; /* IN */
> +};
> +
> +/* XEN_DOMCTL_gdbsx_guestmemio guest mem io */
> +struct xen_domctl_gdbsx_memio {
> + /* IN */
> + aligned_u64 pgd3val;/* optional: init_mm.pgd[3] value */
> + aligned_u64 gva; /* guest virtual address */
> + aligned_u64 uva; /* user buffer virtual address */
> + uint32_t len; /* number of bytes to read/write */
> + uint8_t gwr; /* 0 = read from guest. 1 = write to guest */
> + /* OUT */
> + uint32_t remain; /* bytes remaining to be copied */
> +};
> +
> +/* XEN_DOMCTL_gdbsx_pausevcpu */
> +/* XEN_DOMCTL_gdbsx_unpausevcpu */
> +struct xen_domctl_gdbsx_pauseunp_vcpu { /* pause/unpause a vcpu */
> + uint32_t vcpu; /* which vcpu */
> +};
> +
> +/* XEN_DOMCTL_gdbsx_domstatus */
> +struct xen_domctl_gdbsx_domstatus {
> + /* OUT */
> + uint8_t paused; /* is the domain paused */
> + uint32_t vcpu_id; /* any vcpu in an event? */
> + uint32_t vcpu_ev; /* if yes, what event? */
> +};
> +
> +/*
> + * Memory event operations
> + */
> +
> +/* XEN_DOMCTL_mem_event_op */
> +
> +/*
> + * Domain memory paging
> + * Page memory in and out.
> + * Domctl interface to set up and tear down the
> + * pager<->hypervisor interface. Use XENMEM_paging_op*
> + * to perform per-page operations.
> + *
> + * The XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE domctl returns several
> + * non-standard error codes to indicate why paging could not be enabled:
> + * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> + * EMLINK - guest has iommu passthrough enabled
> + * EXDEV - guest has PoD enabled
> + * EBUSY - guest has or had paging enabled, ring buffer still active
> + */
> +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING 1
> +
> +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE 0
> +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING_DISABLE 1
> +
> +/*
> + * Access permissions.
> + *
> + * As with paging, use the domctl for teardown/setup of the
> + * helper<->hypervisor interface.
> + *
> + * There are HVM hypercalls to set the per-page access permissions of every
> + * page in a domain. When one of these permissions--independent, read,
> + * write, and execute--is violated, the VCPU is paused and a memory event
> + * is sent with what happened. (See public/mem_event.h) .
> + *
> + * The memory event handler can then resume the VCPU and redo the access
> + * with a XENMEM_access_op_resume hypercall.
> + *
> + * The XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE domctl returns several
> + * non-standard error codes to indicate why access could not be enabled:
> + * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> + * EBUSY - guest has or had access enabled, ring buffer still active
> + */
> +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS 2
> +
> +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE 0
> +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE 1
> +
> +/*
> + * Sharing ENOMEM helper.
> + *
> + * As with paging, use the domctl for teardown/setup of the
> + * helper<->hypervisor interface.
> + *
> + * If setup, this ring is used to communicate failed allocations
> + * in the unshare path. XENMEM_sharing_op_resume is used to wake up
> + * vcpus that could not unshare.
> + *
> + * Note that shring can be turned on (as per the domctl below)
> + * *without* this ring being setup.
> + */
> +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING 3
> +
> +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING_ENABLE 0
> +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING_DISABLE 1
> +
> +/* Use for teardown/setup of helper<->hypervisor interface for paging,
> + * access and sharing.*/
> +struct xen_domctl_mem_event_op {
> + uint32_t op; /* XEN_DOMCTL_MEM_EVENT_OP_*_* */
> + uint32_t mode; /* XEN_DOMCTL_MEM_EVENT_OP_* */
> +
> + uint32_t port; /* OUT: event channel for ring */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_mem_event_op);
> +
> +/*
> + * Memory sharing operations
> + */
> +/* XEN_DOMCTL_mem_sharing_op.
> + * The CONTROL sub-domctl is used for bringup/teardown. */
> +#define XEN_DOMCTL_MEM_SHARING_CONTROL 0
> +
> +struct xen_domctl_mem_sharing_op {
> + uint8_t op; /* XEN_DOMCTL_MEM_SHARING_* */
> +
> + union {
> + uint8_t enable; /* CONTROL */
> + } u;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_mem_sharing_op);
> +
> +struct xen_domctl_audit_p2m {
> + /* OUT error counts */
> + uint64_t orphans;
> + uint64_t m2p_bad;
> + uint64_t p2m_bad;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_audit_p2m);
> +
> +struct xen_domctl_set_virq_handler {
> + uint32_t virq; /* IN */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_virq_handler);
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +/* XEN_DOMCTL_setvcpuextstate */
> +/* XEN_DOMCTL_getvcpuextstate */
> +struct xen_domctl_vcpuextstate {
> + /* IN: VCPU that this call applies to. */
> + uint32_t vcpu;
> + /*
> + * SET: Ignored.
> + * GET: xfeature support mask of struct (IN/OUT)
> + * xfeature mask is served as identifications of the saving format
> + * so that compatible CPUs can have a check on format to decide
> + * whether it can restore.
> + */
> + aligned_u64 xfeature_mask;
> + /*
> + * SET: Size of struct (IN)
> + * GET: Size of struct (IN/OUT)
> + */
> + aligned_u64 size;
> + GUEST_HANDLE(uint64_t) buffer;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpuextstate);
> +#endif
> +
> +/* XEN_DOMCTL_set_access_required: sets whether a memory event listener
> + * must be present to handle page access events: if false, the page
> + * access will revert to full permissions if no one is listening;
> + * */
> +struct xen_domctl_set_access_required {
> + uint8_t access_required;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_access_required);
> +
> +struct xen_domctl_set_broken_page_p2m {
> + aligned_u64 pfn;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_broken_page_p2m);
> +
> +/*
> + * XEN_DOMCTL_set_max_evtchn: sets the maximum event channel port
> + * number the guest may use. Use this limit the amount of resources
> + * (global mapping space, xenheap) a guest may use for event channels.
> + */
> +struct xen_domctl_set_max_evtchn {
> + uint32_t max_port;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_max_evtchn);
> +
> +/*
> + * ARM: Clean and invalidate caches associated with given region of
> + * guest memory.
> + */
> +struct xen_domctl_cacheflush {
> + /* IN: page range to flush. */
> + xen_pfn_t start_pfn, nr_pfns;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_cacheflush);
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +struct xen_domctl_vcpu_msr {
> + uint32_t index;
> + uint32_t reserved;
> + aligned_u64 value;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpu_msr);
> +
> +/*
> + * XEN_DOMCTL_set_vcpu_msrs / XEN_DOMCTL_get_vcpu_msrs.
> + *
> + * Input:
> + * - A NULL 'msrs' guest handle is a request for the maximum 'msr_count'.
> + * - Otherwise, 'msr_count' is the number of entries in 'msrs'.
> + *
> + * Output for get:
> + * - If 'msr_count' is less than the number Xen needs to write, -ENOBUFS shall
> + * be returned and 'msr_count' updated to reflect the intended number.
> + * - On success, 'msr_count' shall indicate the number of MSRs written, which
> + * may be less than the maximum if some are not currently used by the vcpu.
> + *
> + * Output for set:
> + * - If Xen encounters an error with a specific MSR, -EINVAL shall be returned
> + * and 'msr_count' shall be set to the offending index, to aid debugging.
> + */
> +struct xen_domctl_vcpu_msrs {
> + uint32_t vcpu; /* IN */
> + uint32_t msr_count; /* IN/OUT */
> + GUEST_HANDLE(xen_domctl_vcpu_msr) msrs; /* IN/OUT */
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpu_msrs);
> +#endif
> +
> +/*
> + * Return information about the state and running time of a domain.
> + * The "domain runstate" is based on the runstates of all the vcpus of the
> + * domain (see below).
> + * @extra_arg == pointer to domain_runstate_info structure.
> + */
> +struct xen_domctl_runstate_info {
> + /* VCPU's current state (RUNSTATE_*). */
> + uint32_t state;
> + uint32_t missed_changes;
> + /* Number of times we missed an update due to contention */
> + /* When was current state entered (system time, ns)? */
> + uint64_t state_entry_time;
> + /*
> + * Time spent in each RUNSTATE_* (ns). The sum of these times is
> + * NOT guaranteed not to drift from system time.
> + */
> + uint64_t time[6];
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_runstate_info);
> +
> +/* All vcpus are running */
> +#define DOMAIN_RUNSTATE_full_run 0
> +
> +/* All vcpus are runnable (i.e., waiting for cpu) */
> +#define DOMAIN_RUNSTATE_full_contention 1
> +
> +/* Some vcpus are running, some are runnable */
> +#define DOMAIN_RUNSTATE_concurrency_hazard 2
> +
> +/* All vcpus are blocked / offline */
> +#define DOMAIN_RUNSTATE_blocked 3
> +
> +/* Some vpcus are running, some are blocked */
> +#define DOMAIN_RUNSTATE_partial_run 4
> +
> +/* Some vcpus are runnable, some are blocked */
> +#define DOMAIN_RUNSTATE_partial_contention 5
> +
> +struct xen_domctl_corespersocket {
> + uint32_t cores_per_socket;
> +};
> +
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_corespersocket);
> +#endif
> +
> +struct xen_domctl {
> + uint32_t cmd;
> +#define XEN_DOMCTL_createdomain 1
> +#define XEN_DOMCTL_destroydomain 2
> +#define XEN_DOMCTL_pausedomain 3
> +#define XEN_DOMCTL_unpausedomain 4
> +#define XEN_DOMCTL_getdomaininfo 5
> +#define XEN_DOMCTL_getmemlist 6
> +#define XEN_DOMCTL_getpageframeinfo 7
> +#define XEN_DOMCTL_getpageframeinfo2 8
> +#define XEN_DOMCTL_setvcpuaffinity 9
> +#define XEN_DOMCTL_shadow_op 10
> +#define XEN_DOMCTL_max_mem 11
> +#define XEN_DOMCTL_setvcpucontext 12
> +#define XEN_DOMCTL_getvcpucontext 13
> +#define XEN_DOMCTL_getvcpuinfo 14
> +#define XEN_DOMCTL_max_vcpus 15
> +#define XEN_DOMCTL_scheduler_op 16
> +#define XEN_DOMCTL_setdomainhandle 17
> +#define XEN_DOMCTL_setdebugging 18
> +#define XEN_DOMCTL_irq_permission 19
> +#define XEN_DOMCTL_iomem_permission 20
> +#define XEN_DOMCTL_ioport_permission 21
> +#define XEN_DOMCTL_hypercall_init 22
> +#define XEN_DOMCTL_arch_setup 23
> +#define XEN_DOMCTL_settimeoffset 24
> +#define XEN_DOMCTL_getvcpuaffinity 25
> +#define XEN_DOMCTL_real_mode_area 26
> +#define XEN_DOMCTL_resumedomain 27
> +#define XEN_DOMCTL_sendtrigger 28
> +#define XEN_DOMCTL_subscribe 29
> +#define XEN_DOMCTL_gethvmcontext 33
> +#define XEN_DOMCTL_sethvmcontext 34
> +#define XEN_DOMCTL_set_address_size 35
> +#define XEN_DOMCTL_get_address_size 36
> +#define XEN_DOMCTL_assign_device 37
> +#define XEN_DOMCTL_bind_pt_irq 38
> +#define XEN_DOMCTL_memory_mapping 39
> +#define XEN_DOMCTL_ioport_mapping 40
> +#define XEN_DOMCTL_pin_mem_cacheattr 41
> +#define XEN_DOMCTL_set_ext_vcpucontext 42
> +#define XEN_DOMCTL_get_ext_vcpucontext 43
> +#define XEN_DOMCTL_set_opt_feature 44 /* Obsolete IA64 only */
> +#define XEN_DOMCTL_test_assign_device 45
> +#define XEN_DOMCTL_set_target 46
> +#define XEN_DOMCTL_deassign_device 47
> +#define XEN_DOMCTL_unbind_pt_irq 48
> +#define XEN_DOMCTL_set_cpuid 49
> +#define XEN_DOMCTL_get_device_group 50
> +#define XEN_DOMCTL_set_machine_address_size 51
> +#define XEN_DOMCTL_get_machine_address_size 52
> +#define XEN_DOMCTL_suppress_spurious_page_faults 53
> +#define XEN_DOMCTL_debug_op 54
> +#define XEN_DOMCTL_gethvmcontext_partial 55
> +#define XEN_DOMCTL_mem_event_op 56
> +#define XEN_DOMCTL_mem_sharing_op 57
> +#define XEN_DOMCTL_disable_migrate 58
> +#define XEN_DOMCTL_gettscinfo 59
> +#define XEN_DOMCTL_settscinfo 60
> +#define XEN_DOMCTL_getpageframeinfo3 61
> +#define XEN_DOMCTL_setvcpuextstate 62
> +#define XEN_DOMCTL_getvcpuextstate 63
> +#define XEN_DOMCTL_set_access_required 64
> +#define XEN_DOMCTL_audit_p2m 65
> +#define XEN_DOMCTL_set_virq_handler 66
> +#define XEN_DOMCTL_set_broken_page_p2m 67
> +#define XEN_DOMCTL_setnodeaffinity 68
> +#define XEN_DOMCTL_getnodeaffinity 69
> +#define XEN_DOMCTL_set_max_evtchn 70
> +#define XEN_DOMCTL_cacheflush 71
> +#define XEN_DOMCTL_get_vcpu_msrs 72
> +#define XEN_DOMCTL_set_vcpu_msrs 73
> +#define XEN_DOMCTL_get_runstate_info 98
> +#define XEN_DOMCTL_gdbsx_guestmemio 1000
> +#define XEN_DOMCTL_gdbsx_pausevcpu 1001
> +#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
> +#define XEN_DOMCTL_gdbsx_domstatus 1003
> +#define XEN_DOMCTL_setcorespersocket 4001
> + uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
> + domid_t domain;
> + union {
> + struct xen_domctl_createdomain createdomain;
> + struct xen_domctl_getdomaininfo getdomaininfo;
> + struct xen_domctl_getmemlist getmemlist;
> + struct xen_domctl_getpageframeinfo getpageframeinfo;
> + struct xen_domctl_getpageframeinfo2 getpageframeinfo2;
> + struct xen_domctl_getpageframeinfo3 getpageframeinfo3;
> +#if 0
> + struct xen_domctl_nodeaffinity nodeaffinity;
> + struct xen_domctl_vcpuaffinity vcpuaffinity;
> +#endif
> + struct xen_domctl_shadow_op shadow_op;
> + struct xen_domctl_max_mem max_mem;
> + struct xen_domctl_vcpucontext vcpucontext;
> + struct xen_domctl_getvcpuinfo getvcpuinfo;
> + struct xen_domctl_max_vcpus max_vcpus;
> + struct xen_domctl_scheduler_op scheduler_op;
> + struct xen_domctl_setdomainhandle setdomainhandle;
> + struct xen_domctl_setdebugging setdebugging;
> + struct xen_domctl_irq_permission irq_permission;
> + struct xen_domctl_iomem_permission iomem_permission;
> + struct xen_domctl_ioport_permission ioport_permission;
> + struct xen_domctl_hypercall_init hypercall_init;
> + struct xen_domctl_arch_setup arch_setup;
> + struct xen_domctl_settimeoffset settimeoffset;
> + struct xen_domctl_disable_migrate disable_migrate;
> + struct xen_domctl_tsc_info tsc_info;
> + struct xen_domctl_real_mode_area real_mode_area;
> + struct xen_domctl_hvmcontext hvmcontext;
> + struct xen_domctl_hvmcontext_partial hvmcontext_partial;
> + struct xen_domctl_address_size address_size;
> + struct xen_domctl_sendtrigger sendtrigger;
> + struct xen_domctl_get_device_group get_device_group;
> + struct xen_domctl_assign_device assign_device;
> + struct xen_domctl_bind_pt_irq bind_pt_irq;
> + struct xen_domctl_memory_mapping memory_mapping;
> + struct xen_domctl_ioport_mapping ioport_mapping;
> + struct xen_domctl_pin_mem_cacheattr pin_mem_cacheattr;
> +#if 0
> + struct xen_domctl_ext_vcpucontext ext_vcpucontext;
> +#endif
> + struct xen_domctl_set_target set_target;
> + struct xen_domctl_subscribe subscribe;
> + struct xen_domctl_debug_op debug_op;
> + struct xen_domctl_mem_event_op mem_event_op;
> + struct xen_domctl_mem_sharing_op mem_sharing_op;
> +#if defined(__i386__) || defined(__x86_64__)
> + struct xen_domctl_cpuid cpuid;
> + struct xen_domctl_vcpuextstate vcpuextstate;
> + struct xen_domctl_vcpu_msrs vcpu_msrs;
> +#endif
> + struct xen_domctl_set_access_required access_required;
> + struct xen_domctl_audit_p2m audit_p2m;
> + struct xen_domctl_set_virq_handler set_virq_handler;
> + struct xen_domctl_set_max_evtchn set_max_evtchn;
> + struct xen_domctl_runstate_info domain_runstate;
> + struct xen_domctl_corespersocket corespersocket;
> + struct xen_domctl_gdbsx_memio gdbsx_guest_memio;
> + struct xen_domctl_set_broken_page_p2m set_broken_page_p2m;
> + struct xen_domctl_cacheflush cacheflush;
> + struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
> + struct xen_domctl_gdbsx_domstatus gdbsx_domstatus;
> + uint8_t pad[128];
> + } u __aligned(8);
> +};
> +
> +#endif /* __XEN_PUBLIC_DOMCTL_H__ */
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h
> index 956a046..5fb5260 100644
> --- a/include/xen/interface/hvm/hvm_op.h
> +++ b/include/xen/interface/hvm/hvm_op.h
> @@ -32,6 +32,72 @@ struct xen_hvm_param {
> };
> DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_param);
>
> +#define HVMOP_set_pci_intx_level 2
> +struct xen_hvm_set_pci_intx_level {
> + /* Domain to be updated. */
> + domid_t domid;
> + /* PCI INTx identification in PCI topology (domain:bus:device:intx). */
> + uint8_t domain, bus, device, intx;
> + /* Assertion level (0 = unasserted, 1 = asserted). */
> + uint8_t level;
> +};
> +
> +#define HVMOP_set_isa_irq_level 3
> +struct xen_hvm_set_isa_irq_level {
> + /* Domain to be updated. */
> + domid_t domid;
> + /* ISA device identification, by ISA IRQ (0-15). */
> + uint8_t isa_irq;
> + /* Assertion level (0 = unasserted, 1 = asserted). */
> + uint8_t level;
> +};
> +
> +#define HVMOP_set_pci_link_route 4
> +struct xen_hvm_set_pci_link_route {
> + /* Domain to be updated. */
> + domid_t domid;
> + /* PCI link identifier (0-3). */
> + uint8_t link;
> + /* ISA IRQ (1-15), or 0 (disable link). */
> + uint8_t isa_irq;
> +};
> +
> +#define HVMOP_track_dirty_vram 6
> +struct xen_hvm_track_dirty_vram {
> + /* Domain to be tracked. */
> + domid_t domid;
> + /* First pfn to track. */
> + aligned_u64 first_pfn;
> + /* Number of pages to track. */
> + aligned_u64 nr;
> + /* OUT variable. */
> + /* Dirty bitmap buffer. */
> + aligned_u64 dirty_bitmap;
> +};
> +
> +#define HVMOP_modified_memory 7
> +struct xen_hvm_modified_memory {
> + /* Domain to be updated. */
> + domid_t domid;
> + /* First pfn. */
> + aligned_u64 first_pfn;
> + /* Number of pages. */
> + aligned_u64 nr;
> +};
> +
> +#define HVMOP_set_mem_type 8
> +/* Notify that a region of memory is to be treated in a specific way. */
> +struct xen_hvm_set_mem_type {
> + /* Domain to be updated. */
> + domid_t domid;
> + /* Memory type */
> + uint16_t hvmmem_type;
> + /* Number of pages. */
> + uint32_t nr;
> + /* First pfn. */
> + aligned_u64 first_pfn;
> +};
> +
> /* Hint from PV drivers for pagetable destruction. */
> #define HVMOP_pagetable_dying 9
> struct xen_hvm_pagetable_dying {
> diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
> index 2ecfe4f..a5fd2e6 100644
> --- a/include/xen/interface/memory.h
> +++ b/include/xen/interface/memory.h
> @@ -248,6 +248,14 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map);
> */
> extern spinlock_t xen_reservation_lock;
>
> +#define XENMEM_set_memory_map 13
> +struct xen_foreign_memory_map {
> + domid_t domid;
> + struct xen_memory_map map;
> +};
> +
> +#define XENMEM_maximum_gpfn 14
> +
> /*
> * Unmaps the page appearing at a particular GPFN from the specified guest's
> * pseudophysical address space.
> diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
> index de08213..075cb6f 100644
> --- a/include/xen/interface/xen.h
> +++ b/include/xen/interface/xen.h
> @@ -57,6 +57,7 @@
> #define __HYPERVISOR_event_channel_op 32
> #define __HYPERVISOR_physdev_op 33
> #define __HYPERVISOR_hvm_op 34
> +#define __HYPERVISOR_domctl 36
> #define __HYPERVISOR_tmem_op 38
>
> /* Architecture-specific hypercall definitions. */
> --
> 1.9.1
>
>
^ permalink raw reply
* Re: [PATCH 8/9] Add devicetree bindings for Rockchip Soc EDP
From: Heiko Stübner @ 2014-08-04 19:39 UTC (permalink / raw)
To: mark yao
Cc: Rob Clark, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Randy Dunlap, David Airlie, Grant Likely,
Greg Kroah-Hartman, John Stultz, Rom Lemarchand, devicetree,
linux-doc, linux-kernel, dri-devel, linux-api, olof, djkurtz, xjq,
kfx, cym, cf, zyw, zwl, xxm, huangtao, kever.yang, zhangqing, yxj,
wxt
In-Reply-To: <1407128159-1930-1-git-send-email-yzq@rock-chips.com>
Am Montag, 4. August 2014, 12:55:59 schrieb mark yao:
> Signed-off-by: mark yao <yzq@rock-chips.com>
> ---
> .../devicetree/bindings/video/rockchip-panel.txt | 34
> ++++++++++++++++++++ 1 file changed, 34 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/video/rockchip-panel.txt
> b/Documentation/devicetree/bindings/video/rockchip-panel.txt index
> f599806..f6d80f6 100644
> --- a/Documentation/devicetree/bindings/video/rockchip-panel.txt
> +++ b/Documentation/devicetree/bindings/video/rockchip-panel.txt
> @@ -80,3 +80,37 @@ Example:
> rockchip,data-width = <24>;
> rockchip,panel = <&panel>;
> };
> +
> +Rockchip RK3288 EDP interface
> +================================
> +Required properties:
> +-compatible: "rockchip,rk3288-edp";
> +
> +- reg: physical base address of the controller and length
> +- clocks: from common clock binding: handle to dp clock.
> + of memory mapped region.
> +- clock-names: from common clock binding:
> + Required elements: "clk_edp"
> + "clk_edp_24m"
> + "clk_edp_24m_parent"
> + "pclk_edp"
> +- rockchip,grf: this soc should set GRF regs, so need get grf here.
> +- resets: Must contain an entry for each entry in reset-names.
> + See ../reset/reset.txt for details.
> +- reset-names: Must include the following entries:
> + - edp
> +- rockchip,panel: required a panel node
> +
> +Example:
> + edp: edp@ff970000 {
> + compatible = "rockchip,rk3288-edp";
> + reg = <0xff970000 0x4000>;
> + interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&cru SCLK_EDP>, <&cru SCLK_EDP_24M>, <&cru
> PCLK_EDP_CTRL>, <&xin24m>; + clock-names = "clk_edp",
> "clk_edp_24m", "pclk_edp", "clk_edp_24m_parent"; +
clk_epd_24m_parent is not part of the hardware, so instead of referencing the
target-parent as part of the device clocks, the new
"clk: Support for clock parents and rates assigned from device tree"
should be used for setting the target parent - so the re-parenting code should
also move out of the driver.
This commit [0] is part of the clk-pull request and thus will most likely be
part of 3.17.
Heiko
[0]
http://git.linaro.org/people/mike.turquette/linux.git/commitdiff/86be408bfbd846fab3c4ac21d6f9298bd2e4b790?hp=09575693a2511b5ddae0105546e0d9cefc936e34
> + rockchip,grf = <&grf>;
> + resets = <&cru 111>;
> + reset-names = "edp";
> + rockchip,panel = <&panel>;
> + };
^ permalink raw reply
* Re: [PATCH 1/7] locking/rwsem: don't resched at the end of optimistic spinning
From: Waiman Long @ 2014-08-04 18:36 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Ingo Molnar, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Davidlohr Bueso, Jason Low,
Scott J Norton
In-Reply-To: <20140804075528.GI9918-ndre7Fmf5hadTX5a5knrm8zTDFooKrT+cvkQGrU6aU0@public.gmane.org>
On 08/04/2014 03:55 AM, Peter Zijlstra wrote:
> On Sun, Aug 03, 2014 at 10:36:16PM -0400, Waiman Long wrote:
>> For a fully preemptive kernel, a call to preempt_enable() could
>> potentially trigger a task rescheduling event. In the case of rwsem
>> optimistic spinning, the task has either gotten the lock or is going
>> to sleep soon. So there is no point to do rescheduling here.
> Uh what? Why shouldn't we preempt if we've gotten the lock? What if a
> FIFO task just woke up?
I didn't mean that we shouldn't preempt if there is a higher priority
task. I am sure that there will be other preemption points along the way
that a higher priority task can take over the CPU. I just want to say
that doing it here may not be the best place especially if the task is
going to sleep soon.
If you think this patch does not make sense, I can remove it as other
patches in the set has no dependency on this one.
-Longman
^ permalink raw reply
* Re: [PATCH 0/7] locking/rwsem: enable reader opt-spinning & writer respin
From: Waiman Long @ 2014-08-04 18:07 UTC (permalink / raw)
To: Davidlohr Bueso
Cc: Ingo Molnar, Peter Zijlstra, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Jason Low, Scott J Norton
In-Reply-To: <1407126313.3216.10.camel-5JQ4ckphU/8SZAcGdq5asR6epYMZPwEe5NbjCUgZEJk@public.gmane.org>
On 08/04/2014 12:25 AM, Davidlohr Bueso wrote:
> On Sun, 2014-08-03 at 22:36 -0400, Waiman Long wrote:
>> This patch set improves upon the rwsem optimistic spinning patch set
>> from Davidlohr to enable better performing rwsem and more aggressive
>> use of optimistic spinning.
>>
>> By using a microbenchmark running 1 million lock-unlock operations per
>> thread on a 4-socket 40-core Westmere-EX x86-64 test machine running
>> 3.16-rc7 based kernels, the following table shows the execution times
>> with 2/10 threads running on different CPUs on the same socket where
>> load is the number of pause instructions in the critical section:
>>
>> lock/r:w ratio # of threads Load:Execution Time (ms)
>> -------------- ------------ ------------------------
>> mutex 2 1:530.7, 5:406.0, 10:472.7
>> mutex 10 1:1848 , 5:2046 , 10:4394
>>
>> Before patch:
>> rwsem/0:1 2 1:339.4, 5:368.9, 10:394.0
>> rwsem/1:1 2 1:2915 , 5:2621 , 10:2764
>> rwsem/10:1 2 1:891.2, 5:779.2, 10:827.2
>> rwsem/0:1 10 1:5618 , 5:5722 , 10:5683
>> rwsem/1:1 10 1:14562, 5:14561, 10:14770
>> rwsem/10:1 10 1:5914 , 5:5971 , 10:5912
>>
>> After patch:
>> rwsem/0:1 2 1:161.1, 5:244.4, 10:271.4
>> rwsem/1:1 2 1:188.8, 5:212.4, 10:312.9
>> rwsem/10:1 2 1:168.8, 5:179.5, 10:209.8
>> rwsem/0:1 10 1:1306 , 5:1733 , 10:1998
>> rwsem/1:1 10 1:1512 , 5:1602 , 10:2093
>> rwsem/10:1 10 1:1267 , 5:1458 , 10:2233
>>
>> % Change:
>> rwsem/0:1 2 1:-52.5%, 5:-33.7%, 10:-31.1%
>> rwsem/1:1 2 1:-93.5%, 5:-91.9%, 10:-88.7%
>> rwsem/10:1 2 1:-81.1%, 5:-77.0%, 10:-74.6%
>> rwsem/0:1 10 1:-76.8%, 5:-69.7%, 10:-64.8%
>> rwsem/1:1 10 1:-89.6%, 5:-89.0%, 10:-85.8%
>> rwsem/10:1 10 1:-78.6%, 5:-75.6%, 10:-62.2%
> So at a very low level you see nicer results, which aren't really
> translating to much of a significant impact at a higher level (aim7).
I was using a 4-socket system for testing. I believe the performance
gain will be higher on larger machine. I will run some tests on those
larger machine as well.
>> It can be seen that there is dramatic reduction in the execution
>> times. The new rwsem is now even faster than mutex whether it is all
>> writers or a mixture of writers and readers.
>>
>> Running the AIM7 benchmarks on the same 40-core system (HT off),
>> the performance improvements on some of the workloads were as follows:
>>
>> Workload Before Patch After Patch % Change
>> -------- ------------ ----------- --------
>> custom (200-1000) 446135 477404 +7.0%
>> custom (1100-2000) 449665 484734 +7.8%
>> high_systime 152437 154217 +1.2%
>> (200-1000)
>> high_systime 269695 278942 +3.4%
>> (1100-2000)
> I worry about complicating rwsems even _more_ than they are, specially
> for such a marginal gain. You might want to try other workloads -- ie:
> postgresql (pgbench), I normally get pretty useful data when dealing
> with rwsems.
>
Thank for the info. I will try running pgbench as well.
-Longman
^ permalink raw reply
* Re: [REVIEW][PATCH 0/4] /proc/thread-self
From: Andi Kleen @ 2014-08-04 14:47 UTC (permalink / raw)
To: linux-fsdevel; +Cc: containers, linux-api, linux-kernel
In-Reply-To: <87oaw5caq1.fsf@x220.int.ebiederm.org>
ebiederm@xmission.com (Eric W. Biederman)
writes:
> This patchset implements /proc/thread-self a magic symlink that
> solves a couple of problems.
>
> - It makes it easy to get to a specific threads directory in /proc
> with gettid() not being exported in glibc this is currently a pain.
syscall(__NR_gettid);
-Andi
--
ak@linux.intel.com -- Speaking for myself only
^ permalink raw reply
* Re: [PATCH 1/9] drm: Add drm driver for Rockchip Socs
From: Daniel Vetter @ 2014-08-04 14:46 UTC (permalink / raw)
To: mark yao
Cc: heiko, Rob Clark, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Randy Dunlap, David Airlie,
Grant Likely, Greg Kroah-Hartman, John Stultz, Rom Lemarchand,
huangtao, devicetree, zwl, cym, linux-doc, xw, linux-api, zyw,
zhangqing, linux-kernel, dri-devel, kever.yang, cf, xjq, xxm, yxj,
wxt, kfx
In-Reply-To: <1407127507-1612-1-git-send-email-yzq@rock-chips.com>
On Mon, Aug 04, 2014 at 12:45:07PM +0800, mark yao wrote:
> This patch is a DRM Driver for Rockchip Socs, driver provides an abstraction
> for the graphics hardware, such as lcd controller and connector interface.
>
> Signed-off-by: mark yao <yzq@rock-chips.com>
> ---
Just a quick drive-by comment below, don't consider this a full review by
far ;-)
> +static int lcdc_bind(struct device *dev, struct device *master, void *data)
> +{
> + struct drm_device *drm_dev = data;
> + struct rockchip_drm_private *private = drm_dev->dev_private;
> + struct lcdc_context *ctx = dev_get_drvdata(dev);
> + struct drm_crtc *crtc;
> +
> + ctx->drm_dev = drm_dev;
> +
> + ctx->pipe = rockchip_drm_pipe_get(dev);
> + ctx->dpms = DRM_MODE_DPMS_OFF;
> + crtc = &ctx->crtc;
> +
> + private->crtc[ctx->pipe] = crtc;
> + ctx->plane = rockchip_plane_init(drm_dev, 1 << ctx->pipe, true);
> + drm_crtc_init(drm_dev, crtc, &rockchip_crtc_funcs);
This function is deprecated, please use the _with_planes versions so that
this new driver supports universal planes properly.
Thanks, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply
* Re: futex(2) man page update help request
From: Carlos O'Donell @ 2014-08-04 14:46 UTC (permalink / raw)
To: Michael Kerrisk (man-pages), Thomas Gleixner
Cc: Darren Hart, Ingo Molnar, Jakub Jelinek,
linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, lkml,
Davidlohr Bueso, Arnd Bergmann, Steven Rostedt, Peter Zijlstra,
Linux API
In-Reply-To: <53752157.9070803-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On 05/15/2014 04:19 PM, Michael Kerrisk (man-pages) wrote:
> On 05/15/2014 04:14 PM, Thomas Gleixner wrote:
>> On Thu, 15 May 2014, Michael Kerrisk (man-pages) wrote:
>>> And that universe would love to have your documentation of
>>> FUTEX_WAKE_BITSET and FUTEX_WAIT_BITSET ;-),
>>
>> I give you almost the full treatment, but I leave REQUEUE_PI to Darren
>> and FUTEX_WAKE_OP to Jakub. :)
>
> Thanks Thomas--that's fantastic! Hopefully, Darren and Jakub fill in those
> missing pieces...
Michael,
Do you need any help getting these additional futex error codes
into the linux kernel man pages project? Thomas provided the
missing bits and Darren commented... what else do we need?
I'm asking because I want to point other Red Hat engineers at
these pages to say: "these are the canonical error codes."
We're trying to cleanup the userspace side of things.
Cheers,
Carlos.
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [REVIEW][PATCH 0/4] /proc/thread-self
From: Karel Zak @ 2014-08-04 13:12 UTC (permalink / raw)
To: Davidlohr Bueso
Cc: Eric W. Biederman, Linux Containers,
linux-api-u79uwXL29TY76Z2rM5mHXA, Michael Kerrisk (man-pages),
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1406860795.3036.3.camel-5JQ4ckphU/8SZAcGdq5asR6epYMZPwEe5NbjCUgZEJk@public.gmane.org>
On Thu, Jul 31, 2014 at 07:39:55PM -0700, Davidlohr Bueso wrote:
> On Thu, 2014-07-31 at 17:30 -0700, Eric W. Biederman wrote:
> > This is small chance changing /proc/net and /proc/mounts will cause
> > userspace regressions (although nothing has shown up in my testing) if
> > that happens we can just point the change that moves them from
> > /proc/self/... to /proc/thread-self/...
>
> Isn't breaking userspace a no no, no matter what? At least some
> util-linux programs makes use of both /proc/mounts and /proc/net.
Frankly, I don't care about /proc/mount, this file is more about backward
compatibility than about any real informations ;-)
The really important file is /proc/self/mountinfo. We use this file on
many places including shared libs and it seems (according to Eric's
suggestion), that the right think will be to update the libs to use
/proc/thread-self/mountinfo.
Note that I like the idea to have the magic symlink to access thread
specific /proc stuff. It's definitely nice thing for userspace.
Karel
--
Karel Zak <kzak-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v13 4/8] powerpc: add pmd_[dirty|mkclean] for THP
From: Aneesh Kumar K.V @ 2014-08-04 10:50 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, Michael Kerrisk, Linux API, Hugh Dickins,
Johannes Weiner, Rik van Riel, KOSAKI Motohiro, Mel Gorman,
Jason Evans, Zhang Yanfei, Kirill A. Shutemov, Minchan Kim,
Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
In-Reply-To: <1405666386-15095-5-git-send-email-minchan@kernel.org>
Minchan Kim <minchan@kernel.org> writes:
> MADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent
> overwrite of the contents since MADV_FREE syscall is called for
> THP page.
>
> This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE
> support.
>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> Cc: linuxppc-dev@lists.ozlabs.org
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> Signed-off-by: Minchan Kim <minchan@kernel.org>
> ---
> arch/powerpc/include/asm/pgtable-ppc64.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
> index eb9261024f51..c9a4bbe8e179 100644
> --- a/arch/powerpc/include/asm/pgtable-ppc64.h
> +++ b/arch/powerpc/include/asm/pgtable-ppc64.h
> @@ -468,9 +468,11 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)
>
> #define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
> #define pmd_young(pmd) pte_young(pmd_pte(pmd))
> +#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
> #define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
> #define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
> #define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
> +#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
> #define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
> #define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
>
> --
> 2.0.0
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 1/7] locking/rwsem: don't resched at the end of optimistic spinning
From: Peter Zijlstra @ 2014-08-04 7:55 UTC (permalink / raw)
To: Waiman Long
Cc: Ingo Molnar, linux-kernel, linux-api, linux-doc, Davidlohr Bueso,
Jason Low, Scott J Norton
In-Reply-To: <1407119782-41119-2-git-send-email-Waiman.Long@hp.com>
[-- Attachment #1: Type: text/plain, Size: 435 bytes --]
On Sun, Aug 03, 2014 at 10:36:16PM -0400, Waiman Long wrote:
> For a fully preemptive kernel, a call to preempt_enable() could
> potentially trigger a task rescheduling event. In the case of rwsem
> optimistic spinning, the task has either gotten the lock or is going
> to sleep soon. So there is no point to do rescheduling here.
Uh what? Why shouldn't we preempt if we've gotten the lock? What if a
FIFO task just woke up?
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH 9/9] drm: add Rockchip Soc rk3288 edp connector
From: mark yao @ 2014-08-04 4:57 UTC (permalink / raw)
To: heiko-4mtYJXux2i+zQB+pC5nmwQ, Rob Clark, Rob Herring, Pawel Moll,
Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
David Airlie, Grant Likely, Greg Kroah-Hartman, John Stultz,
Rom Lemarchand
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-api-u79uwXL29TY76Z2rM5mHXA, olof-nZhT3qVonbNeoWH0uzbU5w,
djkurtz-F7+t8E8rja9g9hUCZPvPmw, xjq-TNX95d0MmH7DzftRWevZcw,
kfx-TNX95d0MmH7DzftRWevZcw, cym-TNX95d0MmH7DzftRWevZcw,
cf-TNX95d0MmH7DzftRWevZcw, zyw-TNX95d0MmH7DzftRWevZcw,
zwl-TNX95d0MmH7DzftRWevZcw, xxm-TNX95d0MmH7DzftRWevZcw,
huangtao-TNX95d0MmH7DzftRWevZcw,
kever.yang-TNX95d0MmH7DzftRWevZcw,
zhangqing-TNX95d0MmH7DzftRWevZcw, yxj-TNX95d0MmH7DzftRWevZcw,
wxt-TNX95d0MmH7DzftRWevZcw, xw-TNX95d0MmH7DzftRWevZcw, mark yao
In-Reply-To: <1407127274-1356-1-git-send-email-mark.yao-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Signed-off-by: mark yao <yzq-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
drivers/gpu/drm/rockchip/connector/Kconfig | 9 +
drivers/gpu/drm/rockchip/connector/Makefile | 1 +
.../gpu/drm/rockchip/connector/rk3288_dp_core.c | 586 ++++++++++
.../gpu/drm/rockchip/connector/rk3288_dp_core.h | 355 ++++++
drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.c | 1192 ++++++++++++++++++++
drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.h | 378 +++++++
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 13 +
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 +
8 files changed, 2537 insertions(+)
create mode 100644 drivers/gpu/drm/rockchip/connector/rk3288_dp_core.c
create mode 100644 drivers/gpu/drm/rockchip/connector/rk3288_dp_core.h
create mode 100644 drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.c
create mode 100644 drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.h
diff --git a/drivers/gpu/drm/rockchip/connector/Kconfig b/drivers/gpu/drm/rockchip/connector/Kconfig
index 248942f..caffc5b 100644
--- a/drivers/gpu/drm/rockchip/connector/Kconfig
+++ b/drivers/gpu/drm/rockchip/connector/Kconfig
@@ -6,3 +6,12 @@ config RK3288_LVDS
rk3288 lvds transmitter support ttl rgb, lvds and dual lvds
mode, dual lvds mode is support for the plane which need dual
lvds channels.
+
+config RK3288_DP
+ bool "RK3288 edp connector support"
+ depends on DRM_ROCKCHIP_CONNECTOR
+ help
+ Choose this option if you have a rk32xx eDP connector.
+ Rockchip rk3288 SoC has eDP TX Controller can be used.
+ If you have an Embedded DisplayPort Panel, say Y to enable its
+ driver.
diff --git a/drivers/gpu/drm/rockchip/connector/Makefile b/drivers/gpu/drm/rockchip/connector/Makefile
index dcfbdef..4be77ea 100644
--- a/drivers/gpu/drm/rockchip/connector/Makefile
+++ b/drivers/gpu/drm/rockchip/connector/Makefile
@@ -2,3 +2,4 @@
# Makefile for display connector like lvds edp mipi
#
obj-$(CONFIG_RK3288_LVDS) += rk3288_lvds.o
+obj-$(CONFIG_RK3288_DP) += rk3288_dp_core.o rk3288_dp_reg.o
diff --git a/drivers/gpu/drm/rockchip/connector/rk3288_dp_core.c b/drivers/gpu/drm/rockchip/connector/rk3288_dp_core.c
new file mode 100644
index 0000000..3756383
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/connector/rk3288_dp_core.c
@@ -0,0 +1,586 @@
+/*
+* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+* Author:
+* yxj <yxj-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+* cym <cym-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+*
+* based on exynos_dp_core.c
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/of.h>
+
+#include "rk3288_dp_core.h"
+
+static int rk3288_edp_clk_enable(struct rk3288_edp *edp)
+{
+ int ret = 0;
+
+ if (!edp->clk_on) {
+ ret = clk_prepare_enable(edp->pclk);
+ if (ret < 0) {
+ dev_err(edp->dev, "cannot enable edp pclk %d\n", ret);
+ goto err_pclk;
+ }
+
+ ret = clk_prepare_enable(edp->clk_edp);
+ if (ret < 0) {
+ dev_err(edp->dev, "cannot enable clk_edp %d\n", ret);
+ goto err_clk_edp;
+ }
+
+ ret = clk_set_parent(edp->clk_24m, edp->clk_24m_parent);
+ if (ret < 0) {
+ dev_err(edp->dev, "cannot set edp clk_24m parent %d\n",
+ ret);
+ goto err_clk_24m;
+ }
+
+ ret = clk_prepare_enable(edp->clk_24m);
+ if (ret < 0) {
+ dev_err(edp->dev, "cannot enable edp clk_24m %d\n",
+ ret);
+ goto err_clk_24m;
+ }
+
+ edp->clk_on = true;
+ }
+
+ return 0;
+
+err_clk_24m:
+ clk_disable_unprepare(edp->clk_edp);
+err_clk_edp:
+ clk_disable_unprepare(edp->pclk);
+err_pclk:
+ edp->clk_on = false;
+
+ return ret;
+}
+
+static int rk3288_edp_clk_disable(struct rk3288_edp *edp)
+{
+ if (edp->clk_on) {
+ clk_disable_unprepare(edp->pclk);
+ clk_disable_unprepare(edp->clk_edp);
+ clk_disable_unprepare(edp->clk_24m);
+ edp->clk_on = false;
+ }
+
+ return 0;
+}
+
+static int rk3288_edp_pre_init(struct rk3288_edp *edp)
+{
+ u32 val;
+ int ret = 0;
+
+ val = GRF_EDP_REF_CLK_SEL_INTER | (GRF_EDP_REF_CLK_SEL_INTER << 16);
+ ret = regmap_write(edp->grf, edp->soc_data->grf_soc_con12, val);
+ if (ret != 0) {
+ dev_err(edp->dev, "Could not write to GRF: %d\n", ret);
+ return ret;
+ }
+
+ reset_control_assert(edp->rst);
+ usleep_range(10, 20);
+ reset_control_deassert(edp->rst);
+
+ return 0;
+}
+
+static int rk3288_edp_init_edp(struct rk3288_edp *edp)
+{
+ int lcdc_id = 1;
+ u32 val = 0;
+ int ret = 0;
+
+ /* select lcdc */
+ if (lcdc_id == 1)
+ val = EDP_SEL_VOP_LIT | (EDP_SEL_VOP_LIT << 16);
+ else
+ val = EDP_SEL_VOP_LIT << 16;
+ ret = regmap_write(edp->grf, edp->soc_data->grf_soc_con6, val);
+ if (ret != 0) {
+ dev_err(edp->dev, "Could not write to GRF: %d\n", ret);
+ return ret;
+ }
+
+ rk3288_edp_reset(edp);
+ rk3288_edp_init_refclk(edp);
+ rk3288_edp_init_interrupt(edp);
+ rk3288_edp_enable_sw_function(edp);
+ rk3288_edp_init_analog_func(edp);
+ rk3288_edp_init_hpd(edp);
+ rk3288_edp_init_aux(edp);
+
+ return 0;
+}
+
+static int rk3288_edp_get_max_rx_bandwidth(
+ struct rk3288_edp *edp,
+ u8 *bandwidth)
+{
+ u8 data;
+ int retval = 0;
+
+ /*
+ * For DP rev.1.1, Maximum link rate of Main Link lanes
+ * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+ */
+ retval = rk3288_edp_read_byte_from_dpcd(
+ edp, DPCD_ADDR_MAX_LINK_RATE, &data);
+ if (retval < 0)
+ *bandwidth = 0;
+ else
+ *bandwidth = data;
+
+ return retval;
+}
+
+static int rk3288_edp_get_max_rx_lane_count(struct rk3288_edp *edp,
+ u8 *lane_count)
+{
+ u8 data;
+ int retval;
+
+ /*
+ * For DP rev.1.1, Maximum number of Main Link lanes
+ * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+ */
+ retval = rk3288_edp_read_byte_from_dpcd(
+ edp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+ if (retval < 0)
+ *lane_count = 0;
+ else
+ *lane_count = DPCD_MAX_LANE_COUNT(data);
+
+ return retval;
+}
+
+static int rk3288_edp_init_training(struct rk3288_edp *edp)
+{
+ int retval;
+
+ /*
+ * MACRO_RST must be applied after the PLL_LOCK to avoid
+ * the DP inter pair skew issue for at least 10 us
+ */
+ rk3288_edp_reset_macro(edp);
+
+ retval = rk3288_edp_get_max_rx_bandwidth(
+ edp, &edp->link_train.link_rate);
+ retval = rk3288_edp_get_max_rx_lane_count(
+ edp, &edp->link_train.lane_count);
+ dev_dbg(edp->dev, "max link rate:%d.%dGps max number of lanes:%d\n",
+ edp->link_train.link_rate * 27/100,
+ edp->link_train.link_rate*27%100,
+ edp->link_train.lane_count);
+
+ if ((edp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+ (edp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+ dev_warn(edp->dev, "Rx Max Link Rate is abnormal :%x !\n"
+ "use default link rate:%d.%dGps\n",
+ edp->link_train.link_rate,
+ edp->video_info.link_rate*27/100,
+ edp->video_info.link_rate*27%100);
+ edp->link_train.link_rate = edp->video_info.link_rate;
+ }
+
+ if (edp->link_train.lane_count == 0) {
+ dev_err(edp->dev, "Rx Max Lane count is abnormal :%x !\n"
+ "use default lanes:%d\n",
+ edp->link_train.lane_count,
+ edp->video_info.lane_count);
+ edp->link_train.lane_count = edp->video_info.lane_count;
+ }
+
+ rk3288_edp_analog_power_ctr(edp, 1);
+
+ return 0;
+}
+
+static int rk3288_edp_hw_link_training(struct rk3288_edp *edp)
+{
+ u32 cnt = 50;
+ u32 val;
+
+ /* Set link rate and count as you want to establish*/
+ rk3288_edp_set_link_bandwidth(edp, edp->link_train.link_rate);
+ rk3288_edp_set_lane_count(edp, edp->link_train.lane_count);
+ rk3288_edp_hw_link_training_en(edp);
+ val = rk3288_edp_wait_hw_lt_done(edp);
+ while (val) {
+ if (cnt-- <= 0) {
+ dev_err(edp->dev, "hw lt timeout");
+ return -ETIMEDOUT;
+ }
+ mdelay(1);
+ val = rk3288_edp_wait_hw_lt_done(edp);
+ }
+
+ val = rk3288_edp_get_hw_lt_status(edp);
+ if (val)
+ dev_err(edp->dev, "hw lt err:%d\n", val);
+
+ return val;
+}
+
+static int rk3288_edp_set_link_train(struct rk3288_edp *edp)
+{
+ int retval;
+
+ rk3288_edp_init_training(edp);
+
+ retval = rk3288_edp_hw_link_training(edp);
+ if (retval < 0)
+ dev_err(edp->dev, "DP hw LT failed!\n");
+
+ return retval;
+}
+
+static int rk3288_edp_config_video(struct rk3288_edp *edp,
+ struct video_info *video_info)
+{
+ int retval = 0;
+ int timeout_loop = 0;
+ int done_count = 0;
+
+ rk3288_edp_config_video_slave_mode(edp, video_info);
+
+ rk3288_edp_set_video_color_format(edp, video_info->color_depth,
+ video_info->color_space,
+ video_info->dynamic_range,
+ video_info->ycbcr_coeff);
+
+ if (rk3288_edp_get_pll_lock_status(edp) == DP_PLL_UNLOCKED) {
+ dev_err(edp->dev, "PLL is not locked yet.\n");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ timeout_loop++;
+ if (rk3288_edp_is_slave_video_stream_clock_on(edp) == 0)
+ break;
+
+ if (DP_TIMEOUT_LOOP_CNT < timeout_loop) {
+ dev_err(edp->dev, "Timeout of video streamclk ok\n");
+ return -ETIMEDOUT;
+ }
+
+ udelay(1);
+ }
+
+ /* Set to use the register calculated M/N video */
+ rk3288_edp_set_video_cr_mn(edp, CALCULATED_M, 0, 0);
+
+ /* Disable video mute */
+ rk3288_edp_enable_video_mute(edp, 0);
+
+ /* Configure video slave mode */
+ rk3288_edp_enable_video_master(edp, 0);
+
+ /* Enable video */
+ rk3288_edp_start_video(edp);
+
+ timeout_loop = 0;
+
+ for (;;) {
+ timeout_loop++;
+ if (rk3288_edp_is_video_stream_on(edp) == 0) {
+ done_count++;
+ if (done_count > 10)
+ break;
+ } else if (done_count) {
+ done_count = 0;
+ }
+ if (DP_TIMEOUT_LOOP_CNT < timeout_loop) {
+ dev_err(edp->dev, "Timeout of video streamclk ok\n");
+ return -ETIMEDOUT;
+ }
+
+ mdelay(1);
+ }
+
+ if (retval != 0)
+ dev_err(edp->dev, "Video stream is not detected!\n");
+
+ return retval;
+}
+
+static irqreturn_t rk3288_edp_isr(int irq, void *arg)
+{
+ struct rk3288_edp *edp = arg;
+ enum dp_irq_type irq_type;
+
+ irq_type = rk3288_edp_get_irq_type(edp);
+ switch (irq_type) {
+ case DP_IRQ_TYPE_HP_CABLE_IN:
+ dev_dbg(edp->dev, "Received irq - cable in\n");
+ rk3288_edp_clear_hotplug_interrupts(edp);
+ break;
+ case DP_IRQ_TYPE_HP_CABLE_OUT:
+ dev_dbg(edp->dev, "Received irq - cable out\n");
+ rk3288_edp_clear_hotplug_interrupts(edp);
+ break;
+ case DP_IRQ_TYPE_HP_CHANGE:
+ /*
+ * We get these change notifications once in a while, but there
+ * is nothing we can do with them. Just ignore it for now and
+ * only handle cable changes.
+ */
+ dev_dbg(edp->dev, "Received irq - hotplug change; ignoring.\n");
+ rk3288_edp_clear_hotplug_interrupts(edp);
+ break;
+ default:
+ dev_err(edp->dev, "Received irq - unknown type[%x]!\n",
+ irq_type);
+ rk3288_edp_clear_hotplug_interrupts(edp);
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void rk3288_edp_enable(struct rockchip_connector *conn)
+{
+ struct rk3288_edp *edp = conn->priv;
+ int ret = 0;
+
+ ret = rk3288_edp_clk_enable(edp);
+ if (ret < 0) {
+ dev_err(edp->dev, "cannot enable edp clk %d\n", ret);
+ return;
+ }
+
+ ret = rk3288_edp_pre_init(edp);
+ if (ret < 0) {
+ dev_err(edp->dev, "edp pre init fail %d\n", ret);
+ return;
+ }
+
+ ret = rk3288_edp_init_edp(edp);
+ if (ret < 0) {
+ dev_err(edp->dev, "edp init fail %d\n", ret);
+ return;
+ }
+
+ enable_irq(edp->irq);
+
+ ret = rk3288_edp_set_link_train(edp);
+ if (ret)
+ dev_err(edp->dev, "link train failed!\n");
+ else
+ dev_dbg(edp->dev, "link training success.\n");
+
+ rk3288_edp_set_lane_count(edp, edp->link_train.lane_count);
+ rk3288_edp_set_link_bandwidth(edp, edp->link_train.link_rate);
+ rk3288_edp_init_video(edp);
+
+ ret = rk3288_edp_config_video(edp, &edp->video_info);
+ if (ret)
+ dev_err(edp->dev, "unable to config video\n");
+}
+
+static void rk3288_edp_disable(struct rockchip_connector *conn)
+{
+ struct rk3288_edp *edp = conn->priv;
+
+ disable_irq(edp->irq);
+ rk3288_edp_reset(edp);
+ rk3288_edp_analog_power_ctr(edp, 0);
+ rk3288_edp_clk_disable(edp);
+}
+
+static int rk3288_edp_setmode(struct rockchip_connector *conn,
+ struct drm_display_mode *mode)
+{
+ struct rk3288_edp *edp = conn->priv;
+
+ memcpy(&edp->mode, mode, sizeof(*mode));
+
+ return 0;
+}
+
+static struct rockchip_connector edp_conn = {
+ .enable = rk3288_edp_enable,
+ .disable = rk3288_edp_disable,
+ .setmode = rk3288_edp_setmode,
+};
+
+static struct rk3288_edp_soc_data soc_data[2] = {
+ {.grf_soc_con6 = 0x025c,
+ .grf_soc_con12 = 0x0274},
+ {.grf_soc_con6 = -1,
+ .grf_soc_con12 = -1},
+};
+
+static const struct of_device_id rk3288_edp_dt_ids[] = {
+ {.compatible = "rockchip,rk3288-edp",
+ .data = (void *)&soc_data[0]},
+ {}
+};
+MODULE_DEVICE_TABLE(of, rk3288_edp_dt_ids);
+
+static int rk3288_edp_probe(struct platform_device *pdev)
+{
+ struct rk3288_edp *edp;
+ struct resource *res;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ int ret = 0;
+
+ if (!np) {
+ dev_err(&pdev->dev, "Missing device tree node.\n");
+ return -EINVAL;
+ }
+
+ edp = devm_kzalloc(&pdev->dev, sizeof(struct rk3288_edp), GFP_KERNEL);
+ if (!edp) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ match = of_match_node(rk3288_edp_dt_ids, np);
+ edp->soc_data = (struct rk3288_edp_soc_data *)match->data;
+ /*
+ * The control bit is located in the GRF register space.
+ */
+ if (edp->soc_data->grf_soc_con6 >= 0) {
+ edp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(edp->grf)) {
+ dev_err(&pdev->dev,
+ "rk3288-edp needs rockchip,grf property\n");
+ return PTR_ERR(edp->grf);
+ }
+ }
+
+ edp->dev = &pdev->dev;
+ edp->video_info.h_sync_polarity = 0;
+ edp->video_info.v_sync_polarity = 0;
+ edp->video_info.interlaced = 0;
+ edp->video_info.color_space = CS_RGB;
+ edp->video_info.dynamic_range = VESA;
+ edp->video_info.ycbcr_coeff = COLOR_YCBCR601;
+ edp->video_info.color_depth = COLOR_8;
+
+ edp->video_info.link_rate = LINK_RATE_1_62GBPS;
+ edp->video_info.lane_count = LANE_CNT4;
+ edp_conn.type = ROCKCHIP_DISPLAY_TYPE_EDP;
+ edp_conn.priv = edp;
+ edp_conn.dev = &pdev->dev;
+
+ edp->base = rockchip_connector_register(&edp_conn);
+ if (!edp->base) {
+ dev_err(&pdev->dev, "connector register fail\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ edp->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(edp->regs)) {
+ dev_err(&pdev->dev, "ioremap reg failed\n");
+ return PTR_ERR(edp->regs);
+ }
+
+ edp->clk_edp = devm_clk_get(&pdev->dev, "clk_edp");
+ if (IS_ERR(edp->clk_edp)) {
+ dev_err(&pdev->dev, "cannot get clk_edp\n");
+ return PTR_ERR(edp->clk_edp);
+ }
+
+ edp->clk_24m_parent = devm_clk_get(&pdev->dev, "clk_edp_24m_parent");
+ if (IS_ERR(edp->clk_24m_parent)) {
+ dev_err(&pdev->dev, "cannot get clk_edp_24m_parent\n");
+ return PTR_ERR(edp->clk_24m_parent);
+ }
+
+ edp->clk_24m = devm_clk_get(&pdev->dev, "clk_edp_24m");
+ if (IS_ERR(edp->clk_24m)) {
+ dev_err(&pdev->dev, "cannot get clk_edp_24m\n");
+ return PTR_ERR(edp->clk_24m);
+ }
+
+ edp->pclk = devm_clk_get(&pdev->dev, "pclk_edp");
+ if (IS_ERR(edp->pclk)) {
+ dev_err(&pdev->dev, "cannot get pclk\n");
+ return PTR_ERR(edp->pclk);
+ }
+
+ edp->rst = devm_reset_control_get(&pdev->dev, "edp");
+ if (IS_ERR(edp->rst)) {
+ dev_err(&pdev->dev, "failed to get reset\n");
+ return PTR_ERR(edp->rst);
+ }
+
+ ret = rk3288_edp_clk_enable(edp);
+ if (ret < 0) {
+ dev_err(edp->dev, "cannot enable edp clk %d\n", ret);
+ return ret;
+ }
+
+ ret = rk3288_edp_pre_init(edp);
+ if (ret < 0) {
+ dev_err(edp->dev, "failed to pre init %d\n", ret);
+ return ret;
+ }
+
+ edp->irq = platform_get_irq(pdev, 0);
+ if (edp->irq < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ return edp->irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, edp->irq, rk3288_edp_isr, 0,
+ dev_name(&pdev->dev), edp);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", edp->irq);
+ return ret;
+ }
+
+ disable_irq_nosync(edp->irq);
+
+ edp->standby = true;
+
+ platform_set_drvdata(pdev, edp);
+ dev_set_name(edp->dev, "rk3288-edp");
+
+ dev_info(&pdev->dev, "rk3288 edp driver probe success\n");
+
+ return 0;
+}
+
+static int rk3288_edp_remove(struct platform_device *pdev)
+{
+ rk3288_edp_disable(&edp_conn);
+
+ return 0;
+}
+
+struct platform_driver rk3288_edp_driver = {
+ .probe = rk3288_edp_probe,
+ .remove = rk3288_edp_remove,
+ .driver = {
+ .name = "rk3288-edp",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rk3288_edp_dt_ids),
+ },
+};
diff --git a/drivers/gpu/drm/rockchip/connector/rk3288_dp_core.h b/drivers/gpu/drm/rockchip/connector/rk3288_dp_core.h
new file mode 100644
index 0000000..d71df70
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/connector/rk3288_dp_core.h
@@ -0,0 +1,355 @@
+/*
+* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+* Author:
+* yxj <yxj-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+* cym <cym-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+*
+* based on exynos_dp_core.h
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*/
+
+#ifndef __RK3288_DP_H
+#define __RK3288_DP_H
+#include "../rockchip_drm_connector.h"
+
+#define DP_TIMEOUT_LOOP_CNT 100
+#define MAX_CR_LOOP 5
+#define MAX_EQ_LOOP 5
+
+#define GRF_EDP_REF_CLK_SEL_INTER (1 << 4)
+#define GRF_EDP_HDCP_EN (1 << 15)
+#define GRF_EDP_BIST_EN (1 << 14)
+#define GRF_EDP_MEM_CTL_BY_EDP (1 << 13)
+#define GRF_EDP_SECURE_EN (1 << 3)
+#define EDP_SEL_VOP_LIT (1 << 5)
+
+enum dp_irq_type {
+ DP_IRQ_TYPE_HP_CABLE_IN,
+ DP_IRQ_TYPE_HP_CABLE_OUT,
+ DP_IRQ_TYPE_HP_CHANGE,
+ DP_IRQ_TYPE_UNKNOWN,
+};
+
+enum color_coefficient {
+ COLOR_YCBCR601,
+ COLOR_YCBCR709
+};
+
+enum dynamic_range {
+ VESA,
+ CEA
+};
+
+enum pll_status {
+ DP_PLL_UNLOCKED,
+ DP_PLL_LOCKED
+};
+
+enum clock_recovery_m_value_type {
+ CALCULATED_M,
+ REGISTER_M
+};
+
+enum video_timing_recognition_type {
+ VIDEO_TIMING_FROM_CAPTURE,
+ VIDEO_TIMING_FROM_REGISTER
+};
+
+enum pattern_set {
+ PRBS7,
+ D10_2,
+ TRAINING_PTN1,
+ TRAINING_PTN2,
+ DP_NONE
+};
+
+enum color_space {
+ CS_RGB,
+ CS_YCBCR422,
+ CS_YCBCR444
+};
+
+enum color_depth {
+ COLOR_6,
+ COLOR_8,
+ COLOR_10,
+ COLOR_12
+};
+
+enum link_rate_type {
+ LINK_RATE_1_62GBPS = 0x06,
+ LINK_RATE_2_70GBPS = 0x0a
+};
+
+enum link_lane_count_type {
+ LANE_CNT1 = 1,
+ LANE_CNT2 = 2,
+ LANE_CNT4 = 4
+};
+
+enum link_training_state {
+ LT_START,
+ LT_CLK_RECOVERY,
+ LT_EQ_TRAINING,
+ FINISHED,
+ FAILED
+};
+
+enum voltage_swing_level {
+ VOLTAGE_LEVEL_0,
+ VOLTAGE_LEVEL_1,
+ VOLTAGE_LEVEL_2,
+ VOLTAGE_LEVEL_3,
+};
+
+enum pre_emphasis_level {
+ PRE_EMPHASIS_LEVEL_0,
+ PRE_EMPHASIS_LEVEL_1,
+ PRE_EMPHASIS_LEVEL_2,
+ PRE_EMPHASIS_LEVEL_3,
+};
+
+enum analog_power_block {
+ AUX_BLOCK,
+ CH0_BLOCK,
+ CH1_BLOCK,
+ CH2_BLOCK,
+ CH3_BLOCK,
+ ANALOG_TOTAL,
+ POWER_ALL
+};
+
+struct video_info {
+ char *name;
+
+ bool h_sync_polarity;
+ bool v_sync_polarity;
+ bool interlaced;
+
+ enum color_space color_space;
+ enum dynamic_range dynamic_range;
+ enum color_coefficient ycbcr_coeff;
+ enum color_depth color_depth;
+
+ enum link_rate_type link_rate;
+ enum link_lane_count_type lane_count;
+};
+
+struct link_train {
+ int eq_loop;
+ int cr_loop[4];
+
+ u8 link_rate;
+ u8 lane_count;
+ u8 training_lane[4];
+
+ enum link_training_state lt_state;
+};
+
+/*
+ * @grf_offset: offset inside the grf regmap for setting the rk3288 lvds
+ */
+struct rk3288_edp_soc_data {
+ int grf_soc_con6;
+ int grf_soc_con12;
+};
+
+struct rk3288_edp {
+ void *base;
+ struct drm_display_mode mode;
+ struct device *dev;
+ void __iomem *regs;
+ struct regmap *grf;
+ struct rk3288_edp_soc_data *soc_data;
+ unsigned int irq;
+ /* clk for edp controller */
+ struct clk *clk_edp;
+ /* clk for edp phy parent */
+ struct clk *clk_24m_parent;
+ /* clk for edp phy */
+ struct clk *clk_24m;
+ /* clk for phb bus */
+ struct clk *pclk;
+ struct reset_control *rst;
+ struct link_train link_train;
+ struct video_info video_info;
+ bool clk_on;
+ bool standby;
+};
+
+void rk3288_edp_enable_video_mute(struct rk3288_edp *edp, bool enable);
+void rk3288_edp_stop_video(struct rk3288_edp *edp);
+void rk3288_edp_lane_swap(struct rk3288_edp *edp, bool enable);
+void rk3288_edp_init_refclk(struct rk3288_edp *edp);
+void rk3288_edp_init_interrupt(struct rk3288_edp *edp);
+void rk3288_edp_reset(struct rk3288_edp *edp);
+void rk3288_edp_config_interrupt(struct rk3288_edp *edp);
+u32 rk3288_edp_get_pll_lock_status(struct rk3288_edp *edp);
+void rk3288_edp_analog_power_ctr(struct rk3288_edp *edp, bool enable);
+void rk3288_edp_init_analog_func(struct rk3288_edp *edp);
+void rk3288_edp_init_hpd(struct rk3288_edp *edp);
+void rk3288_edp_reset_aux(struct rk3288_edp *edp);
+void rk3288_edp_init_aux(struct rk3288_edp *edp);
+int rk3288_edp_get_plug_in_status(struct rk3288_edp *edp);
+void rk3288_edp_enable_sw_function(struct rk3288_edp *edp);
+int rk3288_edp_start_aux_transaction(struct rk3288_edp *edp);
+int rk3288_edp_write_byte_to_dpcd(struct rk3288_edp *edp,
+ unsigned int reg_addr,
+ unsigned char data);
+int rk3288_edp_read_byte_from_dpcd(struct rk3288_edp *edp,
+ unsigned int reg_addr,
+ unsigned char *data);
+int rk3288_edp_write_bytes_to_dpcd(struct rk3288_edp *edp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[]);
+int rk3288_edp_read_bytes_from_dpcd(struct rk3288_edp *edp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[]);
+int rk3288_edp_select_i2c_device(struct rk3288_edp *edp,
+ unsigned int device_addr,
+ unsigned int reg_addr);
+int rk3288_edp_read_byte_from_i2c(struct rk3288_edp *edp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int *data);
+int rk3288_edp_read_bytes_from_i2c(struct rk3288_edp *edp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char edid[]);
+void rk3288_edp_set_link_bandwidth(struct rk3288_edp *edp, u32 bwtype);
+void rk3288_edp_get_link_bandwidth(struct rk3288_edp *edp, u32 *bwtype);
+void rk3288_edp_set_lane_count(struct rk3288_edp *edp, u32 count);
+void rk3288_edp_get_lane_count(struct rk3288_edp *edp, u32 *count);
+void rk3288_edp_enable_enhanced_mode(struct rk3288_edp *edp, bool enable);
+void rk3288_edp_set_training_pattern(struct rk3288_edp *edp,
+ enum pattern_set pattern);
+void rk3288_edp_set_lane0_pre_emphasis(struct rk3288_edp *edp, u32 level);
+void rk3288_edp_set_lane1_pre_emphasis(struct rk3288_edp *edp, u32 level);
+void rk3288_edp_set_lane2_pre_emphasis(struct rk3288_edp *edp, u32 level);
+void rk3288_edp_set_lane3_pre_emphasis(struct rk3288_edp *edp, u32 level);
+void rk3288_edp_set_lane0_link_training(struct rk3288_edp *edp,
+ u32 training_lane);
+void rk3288_edp_set_lane1_link_training(struct rk3288_edp *edp,
+ u32 training_lane);
+void rk3288_edp_set_lane2_link_training(struct rk3288_edp *edp,
+ u32 training_lane);
+void rk3288_edp_set_lane3_link_training(struct rk3288_edp *edp,
+ u32 training_lane);
+u32 rk3288_edp_get_lane0_link_training(struct rk3288_edp *edp);
+u32 rk3288_edp_get_lane1_link_training(struct rk3288_edp *edp);
+u32 rk3288_edp_get_lane2_link_training(struct rk3288_edp *edp);
+u32 rk3288_edp_get_lane3_link_training(struct rk3288_edp *edp);
+void rk3288_edp_reset_macro(struct rk3288_edp *edp);
+int rk3288_edp_init_video(struct rk3288_edp *edp);
+
+void rk3288_edp_set_video_color_format(struct rk3288_edp *edp,
+ u32 color_depth,
+ u32 color_space,
+ u32 dynamic_range,
+ u32 coeff);
+int rk3288_edp_is_slave_video_stream_clock_on(struct rk3288_edp *edp);
+void rk3288_edp_set_video_cr_mn(
+ struct rk3288_edp *edp,
+ enum clock_recovery_m_value_type type,
+ u32 m_value,
+ u32 n_value);
+void rk3288_edp_set_video_timing_mode(struct rk3288_edp *edp, u32 type);
+void rk3288_edp_enable_video_master(struct rk3288_edp *edp, bool enable);
+void rk3288_edp_start_video(struct rk3288_edp *edp);
+int rk3288_edp_is_video_stream_on(struct rk3288_edp *edp);
+void rk3288_edp_config_video_slave_mode(struct rk3288_edp *edp,
+ struct video_info *video_info);
+void rk3288_edp_enable_scrambling(struct rk3288_edp *edp);
+void rk3288_edp_disable_scrambling(struct rk3288_edp *edp);
+void rk3288_edp_rx_control(struct rk3288_edp *edp, bool enable);
+int rk3288_edp_bist_cfg(struct rk3288_edp *edp);
+void rk3288_edp_hw_link_training_en(struct rk3288_edp *edp);
+int rk3288_edp_get_hw_lt_status(struct rk3288_edp *edp);
+int rk3288_edp_wait_hw_lt_done(struct rk3288_edp *edp);
+enum dp_irq_type rk3288_edp_get_irq_type(struct rk3288_edp *edp);
+void rk3288_edp_clear_hotplug_interrupts(struct rk3288_edp *edp);
+
+/* I2C EDID Chip ID, Slave Address */
+#define I2C_EDID_DEVICE_ADDR 0x50
+#define I2C_E_EDID_DEVICE_ADDR 0x30
+
+#define EDID_BLOCK_LENGTH 0x80
+#define EDID_HEADER_PATTERN 0x00
+#define EDID_EXTENSION_FLAG 0x7e
+#define EDID_CHECKSUM 0x7f
+
+/* Definition for DPCD Register */
+#define DPCD_ADDR_DPCD_REV 0x0000
+#define DPCD_ADDR_MAX_LINK_RATE 0x0001
+#define DPCD_ADDR_MAX_LANE_COUNT 0x0002
+#define DPCD_ADDR_LINK_BW_SET 0x0100
+#define DPCD_ADDR_LANE_COUNT_SET 0x0101
+#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
+#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
+#define DPCD_ADDR_LANE0_1_STATUS 0x0202
+#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204
+#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
+#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
+#define DPCD_ADDR_TEST_REQUEST 0x0218
+#define DPCD_ADDR_TEST_RESPONSE 0x0260
+#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261
+#define DPCD_ADDR_SINK_POWER_STATE 0x0600
+
+/* DPCD_ADDR_MAX_LANE_COUNT */
+#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
+#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
+
+/* DPCD_ADDR_LANE_COUNT_SET */
+#define DPCD_ENHANCED_FRAME_EN (0x1 << 7)
+#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f)
+
+/* DPCD_ADDR_TRAINING_PATTERN_SET */
+#define DPCD_SCRAMBLING_DISABLED (0x1 << 5)
+#define DPCD_SCRAMBLING_ENABLED (0x0 << 5)
+#define DPCD_TRAINING_PATTERN_2 (0x2 << 0)
+#define DPCD_TRAINING_PATTERN_1 (0x1 << 0)
+#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0)
+
+/* DPCD_ADDR_TRAINING_LANE0_SET */
+#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5)
+#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3)
+#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3)
+#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3)
+#define DPCD_MAX_SWING_REACHED (0x1 << 2)
+#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0)
+#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3)
+#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0)
+
+/* DPCD_ADDR_LANE0_1_STATUS */
+#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2)
+#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1)
+#define DPCD_LANE_CR_DONE (0x1 << 0)
+#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \
+ DPCD_LANE_CHANNEL_EQ_DONE|\
+ DPCD_LANE_SYMBOL_LOCKED)
+
+/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
+#define DPCD_LINK_STATUS_UPDATED (0x1 << 7)
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6)
+#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0)
+
+/* DPCD_ADDR_TEST_REQUEST */
+#define DPCD_TEST_EDID_READ (0x1 << 2)
+
+/* DPCD_ADDR_TEST_RESPONSE */
+#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2)
+
+/* DPCD_ADDR_SINK_POWER_STATE */
+#define DPCD_SET_POWER_STATE_D0 (0x1 << 0)
+#define DPCD_SET_POWER_STATE_D4 (0x2 << 0)
+
+#define DPCD_SYMBOL_ERR_CONUT_LANE0 0x210
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.c b/drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.c
new file mode 100644
index 0000000..f558cea
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.c
@@ -0,0 +1,1192 @@
+/*
+* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+* Author:
+* yxj <yxj-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+* cym <cym-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+*
+* based on exynos_dp_reg.c
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*/
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "rk3288_dp_core.h"
+#include "rk3288_dp_reg.h"
+
+void rk3288_edp_enable_video_mute(struct rk3288_edp *edp, bool enable)
+{
+ u32 val;
+
+ if (enable) {
+ val = readl(edp->regs + VIDEO_CTL_1);
+ val |= VIDEO_MUTE;
+ writel(val, edp->regs + VIDEO_CTL_1);
+ } else {
+ val = readl(edp->regs + VIDEO_CTL_1);
+ val &= ~VIDEO_MUTE;
+ writel(val, edp->regs + VIDEO_CTL_1);
+ }
+}
+
+void rk3288_edp_stop_video(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + VIDEO_CTL_1);
+ val &= ~VIDEO_EN;
+ writel(val, edp->regs + VIDEO_CTL_1);
+}
+
+void rk3288_edp_lane_swap(struct rk3288_edp *edp, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
+ LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
+ else
+ val = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+ LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+
+ writel(val, edp->regs + LANE_MAP);
+}
+
+void rk3288_edp_init_refclk(struct rk3288_edp *edp)
+{
+ writel(SEL_24M, edp->regs + ANALOG_CTL_2);
+ writel(REF_CLK_24M, edp->regs + PLL_REG_1);
+
+ writel(0x95, edp->regs + PLL_REG_2);
+ writel(0x40, edp->regs + PLL_REG_3);
+ writel(0x58, edp->regs + PLL_REG_4);
+ writel(0x22, edp->regs + PLL_REG_5);
+ writel(0x19, edp->regs + SSC_REG);
+ writel(0x87, edp->regs + TX_REG_COMMON);
+ writel(0x03, edp->regs + DP_AUX);
+ writel(0x46, edp->regs + DP_BIAS);
+ writel(0x55, edp->regs + DP_RESERVE2);
+}
+
+void rk3288_edp_init_interrupt(struct rk3288_edp *edp)
+{
+ /* Set interrupt pin assertion polarity as high */
+ writel(INT_POL, edp->regs + INT_CTL);
+
+ /* Clear pending valisers */
+ writel(0xff, edp->regs + COMMON_INT_STA_1);
+ writel(0x4f, edp->regs + COMMON_INT_STA_2);
+ writel(0xff, edp->regs + COMMON_INT_STA_3);
+ writel(0x27, edp->regs + COMMON_INT_STA_4);
+
+ writel(0x7f, edp->regs + DP_INT_STA);
+
+ /* 0:mask,1: unmask */
+ writel(0x00, edp->regs + COMMON_INT_MASK_1);
+ writel(0x00, edp->regs + COMMON_INT_MASK_2);
+ writel(0x00, edp->regs + COMMON_INT_MASK_3);
+ writel(0x00, edp->regs + COMMON_INT_MASK_4);
+ writel(0x00, edp->regs + DP_INT_STA_MASK);
+}
+
+void rk3288_edp_reset(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ rk3288_edp_stop_video(edp);
+ rk3288_edp_enable_video_mute(edp, 0);
+
+ val = VID_CAP_FUNC_EN_N | AUD_FIFO_FUNC_EN_N |
+ AUD_FUNC_EN_N | HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+ writel(val, edp->regs + FUNC_EN_1);
+
+ val = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+ SERDES_FIFO_FUNC_EN_N |
+ LS_CLK_DOMAIN_FUNC_EN_N;
+ writel(val, edp->regs + FUNC_EN_2);
+
+ usleep_range(20, 30);
+
+ rk3288_edp_lane_swap(edp, 0);
+
+ writel(0x0, edp->regs + SYS_CTL_1);
+ writel(0x40, edp->regs + SYS_CTL_2);
+ writel(0x0, edp->regs + SYS_CTL_3);
+ writel(0x0, edp->regs + SYS_CTL_4);
+
+ writel(0x0, edp->regs + PKT_SEND_CTL);
+ writel(0x0, edp->regs + HDCP_CTL);
+
+ writel(0x5e, edp->regs + HPD_DEGLITCH_L);
+ writel(0x1a, edp->regs + HPD_DEGLITCH_H);
+
+ writel(0x10, edp->regs + LINK_DEBUG_CTL);
+
+ writel(0x0, edp->regs + VIDEO_FIFO_THRD);
+ writel(0x20, edp->regs + AUDIO_MARGIN);
+
+ writel(0x4, edp->regs + M_VID_GEN_FILTER_TH);
+ writel(0x2, edp->regs + M_AUD_GEN_FILTER_TH);
+
+ writel(0x0, edp->regs + SOC_GENERAL_CTL);
+}
+
+void rk3288_edp_config_interrupt(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ /* 0: mask, 1: unmask */
+ val = 0;
+ writel(val, edp->regs + COMMON_INT_MASK_1);
+
+ writel(val, edp->regs + COMMON_INT_MASK_2);
+
+ writel(val, edp->regs + COMMON_INT_MASK_3);
+
+ writel(val, edp->regs + COMMON_INT_MASK_4);
+
+ writel(val, edp->regs + DP_INT_STA_MASK);
+}
+
+u32 rk3288_edp_get_pll_lock_status(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + DEBUG_CTL);
+ if (val & PLL_LOCK)
+ return DP_PLL_LOCKED;
+ else
+ return DP_PLL_UNLOCKED;
+}
+
+void rk3288_edp_analog_power_ctr(struct rk3288_edp *edp, bool enable)
+{
+ u32 val;
+
+ if (enable) {
+ val = PD_EXP_BG | PD_AUX | PD_PLL |
+ PD_CH3 | PD_CH2 | PD_CH1 | PD_CH0;
+ writel(val, edp->regs + DP_PWRDN);
+ usleep_range(10, 20);
+ writel(0x0, edp->regs + DP_PWRDN);
+ } else {
+ val = PD_EXP_BG | PD_AUX | PD_PLL |
+ PD_CH3 | PD_CH2 | PD_CH1 | PD_CH0;
+ writel(val, edp->regs + DP_PWRDN);
+ }
+}
+
+void rk3288_edp_init_analog_func(struct rk3288_edp *edp)
+{
+ u32 val;
+ int wt = 0;
+
+ rk3288_edp_analog_power_ctr(edp, 1);
+
+ val = PLL_LOCK_CHG;
+ writel(val, edp->regs + COMMON_INT_STA_1);
+
+ val = readl(edp->regs + DEBUG_CTL);
+ val &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
+ writel(val, edp->regs + DEBUG_CTL);
+
+ /* Power up PLL */
+ while (wt < 100) {
+ if (rk3288_edp_get_pll_lock_status(edp) == DP_PLL_LOCKED) {
+ dev_dbg(edp->dev, "edp pll locked\n");
+ break;
+ } else {
+ wt++;
+ udelay(5);
+ }
+ }
+
+ /* Enable Serdes FIFO function and Link symbol clock domain module */
+ val = readl(edp->regs + FUNC_EN_2);
+ val &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
+ | AUX_FUNC_EN_N | SSC_FUNC_EN_N);
+ writel(val, edp->regs + FUNC_EN_2);
+}
+
+void rk3288_edp_init_hpd(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = HOTPLUG_CHG | HPD_LOST | PLUG;
+ writel(val, edp->regs + COMMON_INT_STA_4);
+
+ val = INT_HPD;
+ writel(val, edp->regs + DP_INT_STA);
+
+ val = readl(edp->regs + SYS_CTL_3);
+ val |= (F_HPD | HPD_CTRL);
+ writel(val, edp->regs + SYS_CTL_3);
+}
+
+void rk3288_edp_reset_aux(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ /* Disable AUX channel module */
+ val = readl(edp->regs + FUNC_EN_2);
+ val |= AUX_FUNC_EN_N;
+ writel(val, edp->regs + FUNC_EN_2);
+}
+
+void rk3288_edp_init_aux(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ /* Clear inerrupts related to AUX channel */
+ val = RPLY_RECEIV | AUX_ERR;
+ writel(val, edp->regs + DP_INT_STA);
+
+ rk3288_edp_reset_aux(edp);
+
+ /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+ val = DEFER_CTRL_EN | DEFER_COUNT(1);
+ writel(val, edp->regs + AUX_CH_DEFER_CTL);
+
+ /* Enable AUX channel module */
+ val = readl(edp->regs + FUNC_EN_2);
+ val &= ~AUX_FUNC_EN_N;
+ writel(val, edp->regs + FUNC_EN_2);
+}
+
+int rk3288_edp_get_plug_in_status(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + SYS_CTL_3);
+ if (val & HPD_STATUS)
+ return 0;
+
+ return -EINVAL;
+}
+
+void rk3288_edp_enable_sw_function(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + FUNC_EN_1);
+ val &= ~SW_FUNC_EN_N;
+ writel(val, edp->regs + FUNC_EN_1);
+}
+
+int rk3288_edp_start_aux_transaction(struct rk3288_edp *edp)
+{
+ int val;
+ int retval = 0;
+ int timeout_loop = 0;
+ int aux_timeout = 0;
+
+ /* Enable AUX CH operation */
+ val = readl(edp->regs + AUX_CH_CTL_2);
+ val |= AUX_EN;
+ writel(val, edp->regs + AUX_CH_CTL_2);
+
+ /* Is AUX CH operation enabled? */
+ val = readl(edp->regs + AUX_CH_CTL_2);
+ while (val & AUX_EN) {
+ aux_timeout++;
+ if ((DP_TIMEOUT_LOOP_CNT * 10) < aux_timeout) {
+ dev_err(edp->dev, "AUX CH enable timeout!\n");
+ return -ETIMEDOUT;
+ }
+ val = readl(edp->regs + AUX_CH_CTL_2);
+ usleep_range(100, 110);
+ }
+
+ /* Is AUX CH command redply received? */
+ val = readl(edp->regs + DP_INT_STA);
+ while (!(val & RPLY_RECEIV)) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_CNT < timeout_loop) {
+ dev_err(edp->dev, "AUX CH command redply failed!\n");
+ return -ETIMEDOUT;
+ }
+ val = readl(edp->regs + DP_INT_STA);
+ usleep_range(10, 20);
+ }
+
+ /* Clear interrupt source for AUX CH command redply */
+ writel(RPLY_RECEIV, edp->regs + DP_INT_STA);
+
+ /* Clear interrupt source for AUX CH access error */
+ val = readl(edp->regs + DP_INT_STA);
+ if (val & AUX_ERR) {
+ writel(AUX_ERR, edp->regs + DP_INT_STA);
+ return -EREMOTEIO;
+ }
+
+ /* Check AUX CH error access status */
+ val = readl(edp->regs + AUX_CH_STA);
+ if ((val & AUX_STATUS_MASK) != 0) {
+ dev_err(edp->dev, "AUX CH error happens: %d\n\n",
+ val & AUX_STATUS_MASK);
+ return -EREMOTEIO;
+ }
+
+ return retval;
+}
+
+int rk3288_edp_write_byte_to_dpcd(struct rk3288_edp *edp,
+ unsigned int val_addr,
+ unsigned char data)
+{
+ u32 val;
+ int i;
+ int retval;
+
+ for (i = 0; i < 3; i++) {
+ /* Clear AUX CH data buffer */
+ val = BUF_CLR;
+ writel(val, edp->regs + BUFFER_DATA_CTL);
+
+ /* Select DPCD device address */
+ val = AUX_ADDR_7_0(val_addr);
+ writel(val, edp->regs + DP_AUX_ADDR_7_0);
+ val = AUX_ADDR_15_8(val_addr);
+ writel(val, edp->regs + DP_AUX_ADDR_15_8);
+ val = AUX_ADDR_19_16(val_addr);
+ writel(val, edp->regs + DP_AUX_ADDR_19_16);
+
+ /* Write data buffer */
+ val = (unsigned int)data;
+ writel(val, edp->regs + BUF_DATA_0);
+
+ /*
+ * Set DisplayPort transaction and write 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+ }
+
+ return retval;
+}
+
+int rk3288_edp_read_byte_from_dpcd(struct rk3288_edp *edp,
+ unsigned int val_addr,
+ unsigned char *data)
+{
+ u32 val;
+ int i;
+ int retval;
+
+ for (i = 0; i < 10; i++) {
+ /* Clear AUX CH data buffer */
+ val = BUF_CLR;
+ writel(val, edp->regs + BUFFER_DATA_CTL);
+
+ /* Select DPCD device address */
+ val = AUX_ADDR_7_0(val_addr);
+ writel(val, edp->regs + DP_AUX_ADDR_7_0);
+ val = AUX_ADDR_15_8(val_addr);
+ writel(val, edp->regs + DP_AUX_ADDR_15_8);
+ val = AUX_ADDR_19_16(val_addr);
+ writel(val, edp->regs + DP_AUX_ADDR_19_16);
+
+ /*
+ * Set DisplayPort transaction and read 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+ }
+
+ /* Read data buffer */
+ val = readl(edp->regs + BUF_DATA_0);
+ *data = (unsigned char)(val & 0xff);
+
+ return retval;
+}
+
+int rk3288_edp_write_bytes_to_dpcd(struct rk3288_edp *edp,
+ unsigned int val_addr,
+ unsigned int count,
+ unsigned char data[])
+{
+ u32 val;
+ unsigned int start_offset;
+ unsigned int cur_data_count;
+ unsigned int cur_data_idx;
+ int i;
+ int retval = 0;
+
+ /* Clear AUX CH data buffer */
+ val = BUF_CLR;
+ writel(val, edp->regs + BUFFER_DATA_CTL);
+
+ start_offset = 0;
+ while (start_offset < count) {
+ /* Buffer size of AUX CH is 16 * 4bytes */
+ if ((count - start_offset) > 16)
+ cur_data_count = 16;
+ else
+ cur_data_count = count - start_offset;
+
+ for (i = 0; i < 10; i++) {
+ /* Select DPCD device address */
+ val = AUX_ADDR_7_0(val_addr + start_offset);
+ writel(val, edp->regs + DP_AUX_ADDR_7_0);
+ val = AUX_ADDR_15_8(val_addr + start_offset);
+ writel(val, edp->regs + DP_AUX_ADDR_15_8);
+ val = AUX_ADDR_19_16(val_addr + start_offset);
+ writel(val, edp->regs + DP_AUX_ADDR_19_16);
+
+ for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+ cur_data_idx++) {
+ val = data[start_offset + cur_data_idx];
+ writel(val, edp->regs + BUF_DATA_0
+ + 4 * cur_data_idx);
+ }
+
+ /*
+ * Set DisplayPort transaction and write
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_LENGTH(cur_data_count) |
+ AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+ }
+
+ start_offset += cur_data_count;
+ }
+
+ return retval;
+}
+
+int rk3288_edp_read_bytes_from_dpcd(struct rk3288_edp *edp,
+ unsigned int val_addr,
+ unsigned int count,
+ unsigned char data[])
+{
+ u32 val;
+ unsigned int start_offset;
+ unsigned int cur_data_count;
+ unsigned int cur_data_idx;
+ int i;
+ int retval = 0;
+
+ /* Clear AUX CH data buffer */
+ val = BUF_CLR;
+ writel(val, edp->regs + BUFFER_DATA_CTL);
+
+ start_offset = 0;
+ while (start_offset < count) {
+ /* Buffer size of AUX CH is 16 * 4bytes */
+ if ((count - start_offset) > 16)
+ cur_data_count = 16;
+ else
+ cur_data_count = count - start_offset;
+
+ /* AUX CH Request Transaction process */
+ for (i = 0; i < 10; i++) {
+ /* Select DPCD device address */
+ val = AUX_ADDR_7_0(val_addr + start_offset);
+ writel(val, edp->regs + DP_AUX_ADDR_7_0);
+ val = AUX_ADDR_15_8(val_addr + start_offset);
+ writel(val, edp->regs + DP_AUX_ADDR_15_8);
+ val = AUX_ADDR_19_16(val_addr + start_offset);
+ writel(val, edp->regs + DP_AUX_ADDR_19_16);
+
+ /*
+ * Set DisplayPort transaction and read
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_LENGTH(cur_data_count) |
+ AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+ }
+
+ for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+ cur_data_idx++) {
+ val = readl(edp->regs + BUF_DATA_0
+ + 4 * cur_data_idx);
+ data[start_offset + cur_data_idx] =
+ (unsigned char)val;
+ }
+
+ start_offset += cur_data_count;
+ }
+
+ return retval;
+}
+
+int rk3288_edp_select_i2c_device(struct rk3288_edp *edp,
+ unsigned int device_addr,
+ unsigned int val_addr)
+{
+ u32 val;
+ int retval;
+
+ /* Set EDID device address */
+ val = device_addr;
+ writel(val, edp->regs + DP_AUX_ADDR_7_0);
+ writel(0x0, edp->regs + DP_AUX_ADDR_15_8);
+ writel(0x0, edp->regs + DP_AUX_ADDR_19_16);
+
+ /* Set offset from base address of EDID device */
+ writel(val_addr, edp->regs + BUF_DATA_0);
+
+ /*
+ * Set I2C transaction and write address
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
+ AUX_TX_COMM_WRITE;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval != 0)
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+
+ return retval;
+}
+
+int rk3288_edp_read_byte_from_i2c(struct rk3288_edp *edp,
+ unsigned int device_addr,
+ unsigned int val_addr,
+ unsigned int *data)
+{
+ u32 val;
+ int i;
+ int retval;
+
+ for (i = 0; i < 10; i++) {
+ /* Clear AUX CH data buffer */
+ val = BUF_CLR;
+ writel(val, edp->regs + BUFFER_DATA_CTL);
+
+ /* Select EDID device */
+ retval = rk3288_edp_select_i2c_device(edp,
+ device_addr,
+ val_addr);
+ if (retval != 0) {
+ dev_err(edp->dev, "Select EDID device fail!\n");
+ continue;
+ }
+
+ /*
+ * Set I2C transaction and read data
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_READ;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+ }
+
+ /* Read data */
+ if (retval == 0)
+ *data = readl(edp->regs + BUF_DATA_0);
+
+ return retval;
+}
+
+int rk3288_edp_read_bytes_from_i2c(struct rk3288_edp *edp,
+ unsigned int device_addr,
+ unsigned int val_addr,
+ unsigned int count,
+ unsigned char edid[])
+{
+ u32 val;
+ unsigned int i, j;
+ unsigned int cur_data_idx;
+ unsigned int defer = 0;
+ int retval = 0;
+
+ for (i = 0; i < count; i += 16) {
+ for (j = 0; j < 100; j++) {
+ /* Clear AUX CH data buffer */
+ val = BUF_CLR;
+ writel(val, edp->regs + BUFFER_DATA_CTL);
+
+ /* Set normal AUX CH command */
+ val = readl(edp->regs + AUX_CH_CTL_2);
+ val &= ~ADDR_ONLY;
+ writel(val, edp->regs + AUX_CH_CTL_2);
+
+ /*
+ * If Rx sends defer, Tx sends only reads
+ * request without sending addres
+ */
+ if (!defer)
+ retval = rk3288_edp_select_i2c_device(
+ edp, device_addr, val_addr + i);
+ else
+ defer = 0;
+
+ /*
+ * Set I2C transaction and write data
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ val = AUX_LENGTH(16) | AUX_TX_COMM_I2C_TRANSACTION |
+ AUX_TX_COMM_READ;
+ writel(val, edp->regs + AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = rk3288_edp_start_aux_transaction(edp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(edp->dev, "Aux Transaction fail!\n");
+
+ /* Check if Rx sends defer */
+ val = readl(edp->regs + AUX_RX_COMM);
+ if (val == AUX_RX_COMM_AUX_DEFER ||
+ val == AUX_RX_COMM_I2C_DEFER) {
+ dev_err(edp->dev, "Defer: %d\n\n", val);
+ defer = 1;
+ }
+ }
+
+ for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
+ val = readl(edp->regs + BUF_DATA_0 + 4 * cur_data_idx);
+ edid[i + cur_data_idx] = (unsigned char)val;
+ }
+ }
+
+ return retval;
+}
+
+void rk3288_edp_set_link_bandwidth(struct rk3288_edp *edp, u32 bwtype)
+{
+ u32 val;
+
+ val = bwtype;
+ if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
+ writel(val, edp->regs + LINK_BW_SET);
+}
+
+void rk3288_edp_get_link_bandwidth(struct rk3288_edp *edp, u32 *bwtype)
+{
+ u32 val;
+
+ val = readl(edp->regs + LINK_BW_SET);
+ *bwtype = val;
+}
+
+void rk3288_edp_hw_link_training_en(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = HW_LT_EN;
+ writel(val, edp->regs + HW_LT_CTL);
+}
+
+int rk3288_edp_wait_hw_lt_done(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + DP_INT_STA);
+ if (val&HW_LT_DONE) {
+ writel(val, edp->regs + DP_INT_STA);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int rk3288_edp_get_hw_lt_status(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + HW_LT_CTL);
+ return (val & HW_LT_ERR_CODE_MASK) >> 4;
+}
+void rk3288_edp_set_lane_count(struct rk3288_edp *edp, u32 count)
+{
+ u32 val;
+
+ val = count;
+ writel(val, edp->regs + LANE_CNT_SET);
+}
+
+void rk3288_edp_get_lane_count(struct rk3288_edp *edp, u32 *count)
+{
+ u32 val;
+
+ val = readl(edp->regs + LANE_CNT_SET);
+ *count = val;
+}
+
+void rk3288_edp_enable_enhanced_mode(struct rk3288_edp *edp, bool enable)
+{
+ u32 val;
+
+ if (enable) {
+ val = readl(edp->regs + SYS_CTL_4);
+ val |= ENHANCED;
+ writel(val, edp->regs + SYS_CTL_4);
+ } else {
+ val = readl(edp->regs + SYS_CTL_4);
+ val &= ~ENHANCED;
+ writel(val, edp->regs + SYS_CTL_4);
+ }
+}
+
+void rk3288_edp_set_training_pattern(struct rk3288_edp *edp,
+ enum pattern_set pattern)
+{
+ u32 val;
+
+ switch (pattern) {
+ case PRBS7:
+ val = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+ break;
+ case D10_2:
+ val = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+ break;
+ case TRAINING_PTN1:
+ val = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+ break;
+ case TRAINING_PTN2:
+ val = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+ break;
+ case DP_NONE:
+ val = SCRAMBLING_ENABLE |
+ LINK_QUAL_PATTERN_SET_DISABLE |
+ SW_TRAINING_PATTERN_SET_DISABLE;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+ break;
+ default:
+ break;
+ }
+}
+
+void rk3288_edp_set_lane0_pre_emphasis(struct rk3288_edp *edp, u32 level)
+{
+ u32 val;
+
+ val = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(val, edp->regs + LN0_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane1_pre_emphasis(struct rk3288_edp *edp, u32 level)
+{
+ u32 val;
+
+ val = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(val, edp->regs + LN1_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane2_pre_emphasis(struct rk3288_edp *edp, u32 level)
+{
+ u32 val;
+
+ val = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(val, edp->regs + LN2_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane3_pre_emphasis(struct rk3288_edp *edp, u32 level)
+{
+ u32 val;
+
+ val = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(val, edp->regs + LN3_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane0_link_training(struct rk3288_edp *edp,
+ u32 training_lane)
+{
+ u32 val;
+
+ val = training_lane;
+ writel(val, edp->regs + LN0_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane1_link_training(struct rk3288_edp *edp,
+ u32 training_lane)
+{
+ u32 val;
+
+ val = training_lane;
+ writel(val, edp->regs + LN1_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane2_link_training(struct rk3288_edp *edp,
+ u32 training_lane)
+{
+ u32 val;
+
+ val = training_lane;
+ writel(val, edp->regs + LN2_LINK_TRAINING_CTL);
+}
+
+void rk3288_edp_set_lane3_link_training(struct rk3288_edp *edp,
+ u32 training_lane)
+{
+ u32 val;
+
+ val = training_lane;
+ writel(val, edp->regs + LN3_LINK_TRAINING_CTL);
+}
+
+u32 rk3288_edp_get_lane0_link_training(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + LN0_LINK_TRAINING_CTL);
+ return val;
+}
+
+u32 rk3288_edp_get_lane1_link_training(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + LN1_LINK_TRAINING_CTL);
+ return val;
+}
+
+u32 rk3288_edp_get_lane2_link_training(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + LN2_LINK_TRAINING_CTL);
+ return val;
+}
+
+u32 rk3288_edp_get_lane3_link_training(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + LN3_LINK_TRAINING_CTL);
+ return val;
+}
+
+void rk3288_edp_reset_macro(struct rk3288_edp *edp)
+{
+}
+
+int rk3288_edp_init_video(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+ writel(val, edp->regs + COMMON_INT_STA_1);
+
+ val = 0x0;
+ writel(val, edp->regs + SYS_CTL_1);
+
+ val = CHA_CRI(4) | CHA_CTRL;
+ writel(val, edp->regs + SYS_CTL_2);
+
+ val = VID_HRES_TH(2) | VID_VRES_TH(0);
+ writel(val, edp->regs + VIDEO_CTL_8);
+
+ return 0;
+}
+
+void rk3288_edp_set_video_color_format(struct rk3288_edp *edp,
+ u32 color_dedpth,
+ u32 color_space,
+ u32 dynamic_range,
+ u32 coeff)
+{
+ u32 val;
+
+ /* Configure the input color dedpth, color space, dynamic range */
+ val = (dynamic_range << IN_D_RANGE_SHIFT) |
+ (color_dedpth << IN_BPC_SHIFT) |
+ (color_space << IN_COLOR_F_SHIFT);
+ writel(val, edp->regs + VIDEO_CTL_2);
+
+ /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+ val = readl(edp->regs + VIDEO_CTL_3);
+ val &= ~IN_YC_COEFFI_MASK;
+ if (coeff)
+ val |= IN_YC_COEFFI_ITU709;
+ else
+ val |= IN_YC_COEFFI_ITU601;
+ writel(val, edp->regs + VIDEO_CTL_3);
+}
+
+int rk3288_edp_is_slave_video_stream_clock_on(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + SYS_CTL_1);
+ writel(val, edp->regs + SYS_CTL_1);
+
+ val = readl(edp->regs + SYS_CTL_1);
+
+ if (!(val & DET_STA)) {
+ dev_dbg(edp->dev, "Input stream clock not detected.\n");
+ return -EINVAL;
+ }
+
+ val = readl(edp->regs + SYS_CTL_2);
+ writel(val, edp->regs + SYS_CTL_2);
+
+ val = readl(edp->regs + SYS_CTL_2);
+ if (val & CHA_STA) {
+ dev_dbg(edp->dev, "Input stream clk is changing\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void rk3288_edp_set_video_cr_mn(struct rk3288_edp *edp,
+ enum clock_recovery_m_value_type type,
+ u32 m_value,
+ u32 n_value)
+{
+ u32 val;
+
+ if (type == REGISTER_M) {
+ val = readl(edp->regs + SYS_CTL_4);
+ val |= FIX_M_VID;
+ writel(val, edp->regs + SYS_CTL_4);
+ val = m_value & 0xff;
+ writel(val, edp->regs + M_VID_0);
+ val = (m_value >> 8) & 0xff;
+ writel(val, edp->regs + M_VID_1);
+ val = (m_value >> 16) & 0xff;
+ writel(val, edp->regs + M_VID_2);
+
+ val = n_value & 0xff;
+ writel(val, edp->regs + N_VID_0);
+ val = (n_value >> 8) & 0xff;
+ writel(val, edp->regs + N_VID_1);
+ val = (n_value >> 16) & 0xff;
+ writel(val, edp->regs + N_VID_2);
+ } else {
+ val = readl(edp->regs + SYS_CTL_4);
+ val &= ~FIX_M_VID;
+ writel(val, edp->regs + SYS_CTL_4);
+
+ writel(0x00, edp->regs + N_VID_0);
+ writel(0x80, edp->regs + N_VID_1);
+ writel(0x00, edp->regs + N_VID_2);
+ }
+}
+
+void rk3288_edp_set_video_timing_mode(struct rk3288_edp *edp, u32 type)
+{
+ u32 val;
+
+ if (type == VIDEO_TIMING_FROM_CAPTURE) {
+ val = readl(edp->regs + VIDEO_CTL_10);
+ val &= ~F_SEL;
+ writel(val, edp->regs + VIDEO_CTL_10);
+ } else {
+ val = readl(edp->regs + VIDEO_CTL_10);
+ val |= F_SEL;
+ writel(val, edp->regs + VIDEO_CTL_10);
+ }
+}
+
+int rk3288_edp_bist_cfg(struct rk3288_edp *edp)
+{
+ struct video_info *video_info = &edp->video_info;
+ struct drm_display_mode *mode = &edp->mode;
+ u16 x_total, y_total, x_act;
+ u32 val;
+
+ x_total = mode->htotal;
+ y_total = mode->vtotal;
+ x_act = mode->hdisplay;
+
+ rk3288_edp_set_video_cr_mn(edp, CALCULATED_M, 0, 0);
+ rk3288_edp_set_video_color_format(edp, video_info->color_depth,
+ video_info->color_space,
+ video_info->dynamic_range,
+ video_info->ycbcr_coeff);
+
+ val = y_total & 0xff;
+ writel(val, edp->regs + TOTAL_LINE_CFG_L);
+ val = (y_total >> 8);
+ writel(val, edp->regs + TOTAL_LINE_CFG_H);
+ val = (mode->vdisplay & 0xff);
+ writel(val, edp->regs + ATV_LINE_CFG_L);
+ val = (mode->vdisplay >> 8);
+ writel(val, edp->regs + ATV_LINE_CFG_H);
+ val = (mode->vsync_start - mode->vdisplay);
+ writel(val, edp->regs + VF_PORCH_REG);
+ val = (mode->vsync_end - mode->vsync_start);
+ writel(val, edp->regs + VSYNC_CFG_REG);
+ val = (mode->vtotal - mode->vsync_end);
+ writel(val, edp->regs + VB_PORCH_REG);
+ val = x_total & 0xff;
+ writel(val, edp->regs + TOTAL_PIXELL_REG);
+ val = x_total >> 8;
+ writel(val, edp->regs + TOTAL_PIXELH_REG);
+ val = (x_act & 0xff);
+ writel(val, edp->regs + ATV_PIXELL_REG);
+ val = (x_act >> 8);
+ writel(val, edp->regs + ATV_PIXELH_REG);
+ val = (mode->hsync_start - mode->hdisplay) & 0xff;
+ writel(val, edp->regs + HF_PORCHL_REG);
+ val = (mode->hsync_start - mode->hdisplay) >> 8;
+ writel(val, edp->regs + HF_PORCHH_REG);
+ val = (mode->hsync_end - mode->hsync_start) & 0xff;
+ writel(val, edp->regs + HSYNC_CFGL_REG);
+ val = (mode->hsync_end - mode->hsync_start) >> 8;
+ writel(val, edp->regs + HSYNC_CFGH_REG);
+ val = (mode->htotal - mode->hsync_end) & 0xff;
+ writel(val, edp->regs + HB_PORCHL_REG);
+ val = (mode->htotal - mode->hsync_end) >> 8;
+ writel(val, edp->regs + HB_PORCHH_REG);
+
+ val = BIST_EN | BIST_WH_64 | BIST_TYPE_COLR_BAR;
+ writel(val, edp->regs + VIDEO_CTL_4);
+
+ val = readl(edp->regs + VIDEO_CTL_10);
+ val &= ~F_SEL;
+ writel(val, edp->regs + VIDEO_CTL_10);
+ return 0;
+}
+
+void rk3288_edp_enable_video_master(struct rk3288_edp *edp, bool enable)
+{
+}
+
+void rk3288_edp_start_video(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + VIDEO_CTL_1);
+ val |= VIDEO_EN;
+ writel(val, edp->regs + VIDEO_CTL_1);
+}
+
+int rk3288_edp_is_video_stream_on(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + SYS_CTL_3);
+ writel(val, edp->regs + SYS_CTL_3);
+
+ val = readl(edp->regs + SYS_CTL_3);
+ if (!(val & STRM_VALID)) {
+ dev_dbg(edp->dev, "Input video stream is not detected.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void rk3288_edp_config_video_slave_mode(struct rk3288_edp *edp,
+ struct video_info *video_info)
+{
+ u32 val;
+
+ val = readl(edp->regs + FUNC_EN_1);
+ val &= ~(VID_FIFO_FUNC_EN_N | VID_CAP_FUNC_EN_N);
+ writel(val, edp->regs + FUNC_EN_1);
+
+ val = readl(edp->regs + VIDEO_CTL_10);
+ val &= ~INTERACE_SCAN_CFG;
+ val |= (video_info->interlaced << 2);
+ writel(val, edp->regs + VIDEO_CTL_10);
+
+ val = readl(edp->regs + VIDEO_CTL_10);
+ val &= ~VSYNC_POLARITY_CFG;
+ val |= (video_info->v_sync_polarity << 1);
+ writel(val, edp->regs + VIDEO_CTL_10);
+
+ val = readl(edp->regs + VIDEO_CTL_10);
+ val &= ~HSYNC_POLARITY_CFG;
+ val |= (video_info->h_sync_polarity << 0);
+ writel(val, edp->regs + VIDEO_CTL_10);
+}
+
+void rk3288_edp_enable_scrambling(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + TRAINING_PTN_SET);
+ val &= ~SCRAMBLING_DISABLE;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+}
+
+void rk3288_edp_disable_scrambling(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = readl(edp->regs + TRAINING_PTN_SET);
+ val |= SCRAMBLING_DISABLE;
+ writel(val, edp->regs + TRAINING_PTN_SET);
+}
+
+enum dp_irq_type rk3288_edp_get_irq_type(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ /* Parse hotplug interrupt status register */
+ val = readl(edp->regs + COMMON_INT_STA_4);
+ if (val & PLUG)
+ return DP_IRQ_TYPE_HP_CABLE_IN;
+
+ if (val & HPD_LOST)
+ return DP_IRQ_TYPE_HP_CABLE_OUT;
+
+ if (val & HOTPLUG_CHG)
+ return DP_IRQ_TYPE_HP_CHANGE;
+
+ return DP_IRQ_TYPE_UNKNOWN;
+}
+
+void rk3288_edp_clear_hotplug_interrupts(struct rk3288_edp *edp)
+{
+ u32 val;
+
+ val = HOTPLUG_CHG | HPD_LOST | PLUG;
+ writel(val, edp->regs + COMMON_INT_STA_4);
+
+ val = INT_HPD;
+ writel(val, edp->regs + DP_INT_STA);
+}
diff --git a/drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.h b/drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.h
new file mode 100644
index 0000000..baf8d90
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/connector/rk3288_dp_reg.h
@@ -0,0 +1,378 @@
+/*
+* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+* Author:
+* yxj <yxj-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+* cym <cym-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+*
+* based on exynos_dp_reg.h
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*/
+
+#ifndef _RK32XX_DP_REG_H
+#define _RK32XX_DP_REG_H
+
+#define DP_VERSION 0x10
+
+#define TX_SW_RST 0x14
+
+#define FUNC_EN_1 0x18
+#define VID_CAP_FUNC_EN_N BIT(6)
+#define VID_FIFO_FUNC_EN_N BIT(5)
+#define AUD_FIFO_FUNC_EN_N BIT(4)
+#define AUD_FUNC_EN_N BIT(3)
+#define HDCP_FUNC_EN_N BIT(2)
+#define SW_FUNC_EN_N BIT(0)
+
+#define FUNC_EN_2 0x1C
+#define SSC_FUNC_EN_N BIT(7)
+#define AUX_FUNC_EN_N BIT(2)
+#define SERDES_FIFO_FUNC_EN_N BIT(1)
+#define LS_CLK_DOMAIN_FUNC_EN_N BIT(0)
+
+#define VIDEO_CTL_1 0x20
+#define VIDEO_EN BIT(7)
+#define VIDEO_MUTE BIT(6)
+
+#define VIDEO_CTL_2 0x24
+#define IN_D_RANGE_MASK (0x1 << 7)
+#define IN_D_RANGE_SHIFT (7)
+#define IN_D_RANGE_CEA (0x1 << 7)
+#define IN_D_RANGE_VESA (0x0 << 7)
+#define IN_BPC_MASK (0x7 << 4)
+#define IN_BPC_SHIFT (4)
+#define IN_BPC_12_BITS (0x3 << 4)
+#define IN_BPC_10_BITS (0x2 << 4)
+#define IN_BPC_8_BITS (0x1 << 4)
+#define IN_BPC_6_BITS (0x0 << 4)
+#define IN_COLOR_F_MASK (0x3 << 0)
+#define IN_COLOR_F_SHIFT (0)
+#define IN_COLOR_F_YCBCR444 (0x2 << 0)
+#define IN_COLOR_F_YCBCR422 (0x1 << 0)
+#define IN_COLOR_F_RGB (0x0 << 0)
+
+#define VIDEO_CTL_3 0x28
+#define IN_YC_COEFFI_MASK (0x1 << 7)
+#define IN_YC_COEFFI_SHIFT (7)
+#define IN_YC_COEFFI_ITU709 (0x1 << 7)
+#define IN_YC_COEFFI_ITU601 (0x0 << 7)
+#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_SHIFT (4)
+#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4)
+
+#define VIDEO_CTL_4 0x2c
+#define BIST_EN (0x1 << 3)
+#define BIST_WH_64 (0x1 << 2)
+#define BIST_WH_32 (0x0 << 2)
+#define BIST_TYPE_COLR_BAR (0x0 << 0)
+#define BIST_TYPE_GRAY_BAR (0x1 << 0)
+#define BIST_TYPE_MOBILE_BAR (0x2 << 0)
+
+#define VIDEO_CTL_8 0x3C
+#define VID_HRES_TH(x) (((x) & 0xf) << 4)
+#define VID_VRES_TH(x) (((x) & 0xf) << 0)
+
+#define VIDEO_CTL_10 0x44
+#define F_SEL (0x1 << 4)
+#define INTERACE_SCAN_CFG (0x1 << 2)
+#define VSYNC_POLARITY_CFG (0x1 << 1)
+#define HSYNC_POLARITY_CFG (0x1 << 0)
+
+#define TOTAL_LINE_CFG_L 0x48
+#define TOTAL_LINE_CFG_H 0x4c
+#define ATV_LINE_CFG_L 0x50
+#define ATV_LINE_CFG_H 0x54
+#define VF_PORCH_REG 0x58
+#define VSYNC_CFG_REG 0x5c
+#define VB_PORCH_REG 0x60
+#define TOTAL_PIXELL_REG 0x64
+#define TOTAL_PIXELH_REG 0x68
+#define ATV_PIXELL_REG 0x6c
+#define ATV_PIXELH_REG 0x70
+#define HF_PORCHL_REG 0x74
+#define HF_PORCHH_REG 0x78
+#define HSYNC_CFGL_REG 0x7c
+#define HSYNC_CFGH_REG 0x80
+#define HB_PORCHL_REG 0x84
+#define HB_PORCHH_REG 0x88
+
+
+#define SSC_REG 0x104
+#define TX_REG_COMMON 0x114
+#define DP_AUX 0x120
+#define DP_BIAS 0x124
+
+#define PLL_REG_1 0xfc
+#define REF_CLK_24M (0x1 << 1)
+#define REF_CLK_27M (0x0 << 1)
+
+#define PLL_REG_2 0x9e4
+#define PLL_REG_3 0x9e8
+#define PLL_REG_4 0x9ec
+#define PLL_REG_5 0xa00
+#define DP_PWRDN 0x12c
+#define PD_INC_BG BIT(7)
+#define PD_EXP_BG BIT(6)
+#define PD_AUX BIT(5)
+#define PD_PLL BIT(4)
+#define PD_CH3 BIT(3)
+#define PD_CH2 BIT(2)
+#define PD_CH1 BIT(1)
+#define PD_CH0 BIT(0)
+
+#define DP_RESERVE2 0x134
+
+#define LANE_MAP 0x35C
+#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6)
+#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6)
+#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6)
+#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6)
+#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4)
+#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4)
+#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4)
+#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4)
+#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2)
+#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2)
+#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2)
+#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2)
+#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0)
+#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0)
+#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0)
+#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0)
+
+#define ANALOG_CTL_2 0x374
+#define SEL_24M (0x1 << 3)
+
+#define AUX_HW_RETRY_CTL 0x390
+
+#define INT_STA 0x3c0
+
+#define COMMON_INT_STA_1 0x3C4
+#define VSYNC_DET BIT(7)
+#define PLL_LOCK_CHG BIT(6)
+#define SPDIF_ERR BIT(5)
+#define SPDIF_UNSTBL BIT(4)
+#define VID_FORMAT_CHG BIT(3)
+#define AUD_CLK_CHG BIT(2)
+#define VID_CLK_CHG BIT(1)
+#define SW_INT BIT(0)
+
+#define COMMON_INT_STA_2 0x3C8
+#define ENC_EN_CHG BIT(6)
+#define HW_BKSV_RDY BIT(3)
+#define HW_SHA_DONE BIT(2)
+#define HW_AUTH_STATE_CHG BIT(1)
+#define HW_AUTH_DONE BIT(0)
+
+#define COMMON_INT_STA_3 0x3CC
+#define AFIFO_UNDER BIT(7)
+#define AFIFO_OVER BIT(6)
+#define R0_CHK_FLAG BIT(5)
+
+#define COMMON_INT_STA_4 0x3D0
+#define PSR_ACTIVE BIT(7)
+#define PSR_INACTIVE BIT(6)
+#define SPDIF_BI_PHASE_ERR BIT(5)
+#define HOTPLUG_CHG BIT(2)
+#define HPD_LOST BIT(1)
+#define PLUG BIT(0)
+
+#define DP_INT_STA 0x3DC
+#define INT_HPD BIT(6)
+#define HW_LT_DONE BIT(5)
+#define SINK_LOST BIT(3)
+#define LINK_LOST BIT(2)
+#define RPLY_RECEIV BIT(1)
+#define AUX_ERR BIT(0)
+
+#define COMMON_INT_MASK_1 0x3E0
+#define COMMON_INT_MASK_2 0x3E4
+#define COMMON_INT_MASK_3 0x3E8
+#define COMMON_INT_MASK_4 0x3EC
+#define DP_INT_STA_MASK 0x3F8
+
+#define INT_CTL 0x3FC
+#define SOFT_INT_CTRL BIT(2)
+#define INT_POL BIT(0)
+
+#define SYS_CTL_1 0x600
+#define DET_STA BIT(2)
+#define FORCE_DET BIT(1)
+#define DET_CTRL BIT(0)
+
+#define SYS_CTL_2 0x604
+#define CHA_CRI(x) (((x) & 0xf) << 4)
+#define CHA_STA BIT(2)
+#define FORCE_CHA BIT(1)
+#define CHA_CTRL BIT(0)
+
+#define SYS_CTL_3 0x608
+#define HPD_STATUS BIT(6)
+#define F_HPD BIT(5)
+#define HPD_CTRL BIT(4)
+#define HDCP_RDY BIT(3)
+#define STRM_VALID BIT(2)
+#define F_VALID BIT(1)
+#define VALID_CTRL BIT(0)
+
+#define SYS_CTL_4 0x60C
+#define FIX_M_AUD BIT(4)
+#define ENHANCED BIT(3)
+#define FIX_M_VID BIT(2)
+#define M_VID_UPDATE_CTRL BIT(0)
+
+#define PKT_SEND_CTL 0x640
+#define HDCP_CTL 0x648
+
+#define LINK_BW_SET 0x680
+#define LANE_CNT_SET 0x684
+
+#define TRAINING_PTN_SET 0x688
+#define SCRAMBLING_DISABLE (0x1 << 5)
+#define SCRAMBLING_ENABLE (0x0 << 5)
+#define LINK_QUAL_PATTERN_SET_MASK (0x7 << 2)
+#define LINK_QUAL_PATTERN_SET_HBR2 (0x5 << 2)
+#define LINK_QUAL_PATTERN_SET_80BIT (0x4 << 2)
+#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2)
+#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2)
+#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0)
+#define SW_TRAINING_PATTERN_SET_DISABLE (0x0 << 0)
+
+#define LN0_LINK_TRAINING_CTL 0x68C
+#define LN1_LINK_TRAINING_CTL 0x690
+#define LN2_LINK_TRAINING_CTL 0x694
+#define LN3_LINK_TRAINING_CTL 0x698
+
+#define HW_LT_CTL 0x6a0
+#define HW_LT_ERR_CODE_MASK 0x70
+#define HW_LT_EN BIT(0)
+
+#define DEBUG_CTL 0x6C0
+#define PLL_LOCK BIT(4)
+#define F_PLL_LOCK BIT(3)
+#define PLL_LOCK_CTRL BIT(2)
+#define POLL_EN BIT(1)
+#define PN_INV BIT(0)
+
+#define HPD_DEGLITCH_L 0x6C4
+#define HPD_DEGLITCH_H 0x6C8
+#define LINK_DEBUG_CTL 0x6E0
+
+#define M_VID_0 0x700
+#define M_VID_1 0x704
+#define M_VID_2 0x708
+#define N_VID_0 0x70C
+#define N_VID_1 0x710
+#define N_VID_2 0x714
+
+#define VIDEO_FIFO_THRD 0x730
+#define AUDIO_MARGIN 0x73C
+
+#define M_VID_GEN_FILTER_TH 0x764
+#define M_AUD_GEN_FILTER_TH 0x778
+
+#define AUX_CH_STA 0x780
+#define AUX_BUSY (0x1 << 4)
+#define AUX_STATUS_MASK (0xf << 0)
+
+#define AUX_CH_DEFER_CTL 0x788
+#define DEFER_CTRL_EN (0x1 << 7)
+#define DEFER_COUNT(x) (((x) & 0x7f) << 0)
+
+#define AUX_RX_COMM_I2C_DEFER (0x2 << 2)
+#define AUX_RX_COMM_AUX_DEFER (0x2 << 0)
+
+#define AUX_RX_COMM 0x78C
+#define BUFFER_DATA_CTL 0x790
+#define BUF_CLR (0x1 << 7)
+#define BUF_HAVE_DATA (0x1 << 4)
+#define BUF_DATA_COUNT(x) (((x) & 0xf) << 0)
+
+#define AUX_CH_CTL_1 0x794
+#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4)
+#define AUX_TX_COMM_MASK (0xf << 0)
+#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3)
+#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3)
+#define AUX_TX_COMM_MOT (0x1 << 2)
+#define AUX_TX_COMM_WRITE (0x0 << 0)
+#define AUX_TX_COMM_READ (0x1 << 0)
+
+#define DP_AUX_ADDR_7_0 0x798
+#define DP_AUX_ADDR_15_8 0x79C
+#define DP_AUX_ADDR_19_16 0x7A0
+
+#define AUX_CH_CTL_2 0x7A4
+#define PD_AUX_IDLE BIT(3)
+#define ADDR_ONLY BIT(1)
+#define AUX_EN BIT(0)
+
+#define BUF_DATA_0 0x7C0
+
+#define SOC_GENERAL_CTL 0x800
+
+/* TX_SW_RESET */
+#define RST_DP_TX BIT(0)
+
+/* ANALOG_CTL_1 */
+#define TX_TERMINAL_CTRL_50_OHM BIT(4)
+
+/* ANALOG_CTL_3 */
+#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5)
+#define VCO_BIT_600_MICRO (0x5 << 0)
+
+/* PLL_FILTER_CTL_1 */
+#define PD_RING_OSC (0x1 << 6)
+#define AUX_TERMINAL_CTRL_37_5_OHM (0x0 << 4)
+#define AUX_TERMINAL_CTRL_45_OHM (0x1 << 4)
+#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
+#define AUX_TERMINAL_CTRL_65_OHM (0x3 << 4)
+#define TX_CUR1_2X (0x1 << 2)
+#define TX_CUR_16_MA (0x3 << 0)
+
+/* TX_AMP_TUNING_CTL */
+#define CH3_AMP_SHIFT (24)
+#define CH3_AMP_400_MV (0x0 << 24)
+#define CH2_AMP_SHIFT (16)
+#define CH2_AMP_400_MV (0x0 << 16)
+#define CH1_AMP_SHIFT (8)
+#define CH1_AMP_400_MV (0x0 << 8)
+#define CH0_AMP_SHIFT (0)
+#define CH0_AMP_400_MV (0x0 << 0)
+
+/* AUX_HW_RETRY_CTL */
+#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8)
+#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3)
+#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
+#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
+#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3)
+#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3)
+#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0)
+
+/* LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
+#define PRE_EMPHASIS_SET_SHIFT (3)
+
+/* PLL_CTL */
+#define DP_PLL_PD (0x1 << 7)
+#define DP_PLL_RESET (0x1 << 6)
+#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4)
+#define DP_PLL_REF_BIT_1_1250V (0x5 << 0)
+#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
+
+/* PHY_TEST */
+#define MACRO_RST BIT(5)
+#define CH1_TEST BIT(1)
+#define CH0_TEST BIT(0)
+
+#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff)
+#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff)
+#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f)
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 59187aa..4f1205f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -564,6 +564,12 @@ static int rockchip_drm_init(void)
goto out_lvds;
#endif
+#ifdef CONFIG_RK3288_DP
+ ret = platform_driver_register(&rk3288_edp_driver);
+ if (ret)
+ goto out_edp;
+#endif
+
rockchip_drm_pdev = platform_device_register_simple("rockchip-drm", -1,
NULL, 0);
if (IS_ERR(rockchip_drm_pdev)) {
@@ -580,6 +586,10 @@ static int rockchip_drm_init(void)
out_drm_driver:
platform_device_unregister(rockchip_drm_pdev);
out_drm_pdev:
+#ifdef CONFIG_RK3288_DP
+ platform_driver_unregister(&rk3288_edp_driver);
+out_edp:
+#endif
#ifdef CONFIG_RK3288_LVDS
platform_driver_unregister(&rk3288_lvds_driver);
out_lvds:
@@ -596,6 +606,9 @@ static void rockchip_drm_exit(void)
{
platform_device_unregister(rockchip_drm_pdev);
platform_driver_unregister(&rockchip_drm_platform_driver);
+#ifdef CONFIG_RK3288_DP
+ platform_driver_unregister(&rk3288_edp_driver);
+#endif
#ifdef CONFIG_RK3288_LVDS
platform_driver_unregister(&rk3288_lvds_driver);
#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index d28f4dc..565276e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -128,4 +128,7 @@ extern struct platform_driver rockchip_lcdc_platform_driver;
#ifdef CONFIG_RK3288_LVDS
extern struct platform_driver rk3288_lvds_driver;
#endif
+#ifdef CONFIG_RK3288_DP
+extern struct platform_driver rk3288_edp_driver;
+#endif
#endif /* _ROCKCHIP_DRM_DRV_H_ */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 8/9] Add devicetree bindings for Rockchip Soc EDP
From: mark yao @ 2014-08-04 4:55 UTC (permalink / raw)
To: heiko, Rob Clark, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Randy Dunlap, David Airlie,
Grant Likely, Greg Kroah-Hartman, John Stultz, Rom Lemarchand
Cc: devicetree, linux-doc, linux-kernel, dri-devel, linux-api, olof,
djkurtz, xjq, kfx, cym, cf, zyw, zwl, xxm, huangtao, kever.yang,
zhangqing, yxj, wxt, xw, mark yao
In-Reply-To: <1407127274-1356-1-git-send-email-mark.yao@rock-chips.com>
Signed-off-by: mark yao <yzq@rock-chips.com>
---
.../devicetree/bindings/video/rockchip-panel.txt | 34 ++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/Documentation/devicetree/bindings/video/rockchip-panel.txt b/Documentation/devicetree/bindings/video/rockchip-panel.txt
index f599806..f6d80f6 100644
--- a/Documentation/devicetree/bindings/video/rockchip-panel.txt
+++ b/Documentation/devicetree/bindings/video/rockchip-panel.txt
@@ -80,3 +80,37 @@ Example:
rockchip,data-width = <24>;
rockchip,panel = <&panel>;
};
+
+Rockchip RK3288 EDP interface
+================================
+Required properties:
+-compatible: "rockchip,rk3288-edp";
+
+- reg: physical base address of the controller and length
+- clocks: from common clock binding: handle to dp clock.
+ of memory mapped region.
+- clock-names: from common clock binding:
+ Required elements: "clk_edp"
+ "clk_edp_24m"
+ "clk_edp_24m_parent"
+ "pclk_edp"
+- rockchip,grf: this soc should set GRF regs, so need get grf here.
+- resets: Must contain an entry for each entry in reset-names.
+ See ../reset/reset.txt for details.
+- reset-names: Must include the following entries:
+ - edp
+- rockchip,panel: required a panel node
+
+Example:
+ edp: edp@ff970000 {
+ compatible = "rockchip,rk3288-edp";
+ reg = <0xff970000 0x4000>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_EDP>, <&cru SCLK_EDP_24M>, <&cru PCLK_EDP_CTRL>, <&xin24m>;
+ clock-names = "clk_edp", "clk_edp_24m", "pclk_edp", "clk_edp_24m_parent";
+
+ rockchip,grf = <&grf>;
+ resets = <&cru 111>;
+ reset-names = "edp";
+ rockchip,panel = <&panel>;
+ };
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox